-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This first version is very basic and only accepts at/start, a length for the rays, a rotation and an updateRay callback that's called with each ray and is meant to remove hexes from the ray to create a field of view.
- Loading branch information
1 parent
2fe12ff
commit 50e707d
Showing
3 changed files
with
213 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
export * from './add' | ||
export * from './branch' | ||
export * from './line' | ||
export * from './rays' | ||
export * from './rectangle' | ||
export * from './ring' | ||
export * from './spiral' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import { createHex, createHexPrototype, Hex } from '../../hex' | ||
import { rays } from './rays' | ||
|
||
const hexPrototype = createHexPrototype() | ||
const cursor = createHex(hexPrototype, { q: 1, r: 2 }) | ||
const getHex = jest.fn((coordinates) => createHex(hexPrototype, coordinates)) | ||
|
||
describe('when called with only length', () => { | ||
test('returns a traverser that returns all (unique) hexes around the cursor with radius length', () => { | ||
const result = [...rays({ length: 2 })(cursor, getHex)] | ||
expect(result).toMatchObject([ | ||
{ q: 1, r: 1 }, | ||
{ q: 1, r: 0 }, | ||
{ q: 2, r: 1 }, | ||
{ q: 2, r: 0 }, | ||
{ q: 3, r: 0 }, | ||
{ q: 2, r: 2 }, | ||
{ q: 3, r: 1 }, | ||
{ q: 3, r: 2 }, | ||
{ q: 2, r: 3 }, | ||
{ q: 1, r: 3 }, | ||
{ q: 1, r: 4 }, | ||
{ q: 0, r: 4 }, | ||
{ q: 0, r: 3 }, | ||
{ q: -1, r: 4 }, | ||
{ q: -1, r: 3 }, | ||
{ q: 0, r: 2 }, | ||
{ q: -1, r: 2 }, | ||
{ q: 0, r: 1 }, | ||
]) | ||
}) | ||
}) | ||
|
||
describe('when called with start and length', () => { | ||
test('returns a traverser that returns all (unique) hexes around and including the start with radius length', () => { | ||
const result = [...rays({ start: [3, 2], length: 2 })(cursor, getHex)] | ||
expect(result).toMatchObject([ | ||
{ q: 3, r: 2 }, | ||
{ q: 3, r: 1 }, | ||
{ q: 3, r: 0 }, | ||
{ q: 4, r: 1 }, | ||
{ q: 4, r: 0 }, | ||
{ q: 5, r: 0 }, | ||
{ q: 4, r: 2 }, | ||
{ q: 5, r: 1 }, | ||
{ q: 5, r: 2 }, | ||
{ q: 4, r: 3 }, | ||
{ q: 3, r: 3 }, | ||
{ q: 3, r: 4 }, | ||
{ q: 2, r: 4 }, | ||
{ q: 2, r: 3 }, | ||
{ q: 1, r: 4 }, | ||
{ q: 1, r: 3 }, | ||
{ q: 2, r: 2 }, | ||
{ q: 1, r: 2 }, | ||
{ q: 2, r: 1 }, | ||
]) | ||
}) | ||
}) | ||
|
||
describe('when called with at and length', () => { | ||
test('returns a traverser that returns all (unique) hexes around the at with radius length', () => { | ||
const result = [...rays({ at: [1, 4], length: 2 })(cursor, getHex)] | ||
expect(result).toMatchObject([ | ||
{ q: 1, r: 3 }, | ||
{ q: 1, r: 2 }, | ||
{ q: 2, r: 3 }, | ||
{ q: 2, r: 2 }, | ||
{ q: 3, r: 2 }, | ||
{ q: 2, r: 4 }, | ||
{ q: 3, r: 3 }, | ||
{ q: 3, r: 4 }, | ||
{ q: 2, r: 5 }, | ||
{ q: 1, r: 5 }, | ||
{ q: 1, r: 6 }, | ||
{ q: 0, r: 6 }, | ||
{ q: 0, r: 5 }, | ||
{ q: -1, r: 6 }, | ||
{ q: -1, r: 5 }, | ||
{ q: 0, r: 4 }, | ||
{ q: -1, r: 4 }, | ||
{ q: 0, r: 3 }, | ||
]) | ||
}) | ||
}) | ||
|
||
describe('updateRay callback', () => { | ||
test('is called with each ray', () => { | ||
const updateRay = jest.fn<Hex[], [Hex[]]>((ray) => ray.filter((hex) => hex.q < 1)) | ||
const result = [...rays({ length: 2, updateRay })(cursor, getHex)] | ||
|
||
expect(updateRay.mock.calls).toMatchObject([ | ||
[ | ||
[ | ||
{ q: 1, r: 1 }, | ||
{ q: 1, r: 0 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 2, r: 1 }, | ||
{ q: 2, r: 0 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 2, r: 1 }, | ||
{ q: 3, r: 0 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 2, r: 2 }, | ||
{ q: 3, r: 1 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 2, r: 2 }, | ||
{ q: 3, r: 2 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 2, r: 2 }, | ||
{ q: 2, r: 3 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 1, r: 3 }, | ||
{ q: 1, r: 4 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 1, r: 3 }, | ||
{ q: 0, r: 4 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 0, r: 3 }, | ||
{ q: -1, r: 4 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 0, r: 3 }, | ||
{ q: -1, r: 3 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 0, r: 2 }, | ||
{ q: -1, r: 2 }, | ||
], | ||
], | ||
[ | ||
[ | ||
{ q: 0, r: 2 }, | ||
{ q: 0, r: 1 }, | ||
], | ||
], | ||
]) | ||
expect(result).toMatchObject([ | ||
{ q: 0, r: 4 }, | ||
{ q: 0, r: 3 }, | ||
{ q: -1, r: 4 }, | ||
{ q: -1, r: 3 }, | ||
{ q: 0, r: 2 }, | ||
{ q: -1, r: 2 }, | ||
{ q: 0, r: 1 }, | ||
]) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { assertCubeCoordinates, CubeCoordinates, Hex } from '../../hex' | ||
import { RotationLike, StartOrAt, Traverser } from '../types' | ||
import { line, LineBetweenOptions } from './line' | ||
import { ring } from './ring' | ||
|
||
// todo: | ||
// - add option for first ray () | ||
export const rays = <T extends Hex>({ | ||
at, | ||
start, | ||
length, | ||
rotation, | ||
updateRay = (_) => _, | ||
}: RaysOptions<T>): Traverser<T> => { | ||
return (cursor, getHex) => { | ||
const firstCoordinates = at ?? start ?? cursor | ||
const { q, r, s } = assertCubeCoordinates(firstCoordinates, cursor) | ||
// todo: make this configurable: either a direction or end of line? | ||
const ringStart: CubeCoordinates = { q, r: r - length, s: s + length } | ||
|
||
return ring<T>({ center: firstCoordinates, start: ringStart, rotation })(cursor, getHex) | ||
.reduce((uniqueHexes, through) => { | ||
const ray = line<T>({ at, start, through } as LineBetweenOptions)(cursor, getHex) | ||
updateRay(ray).forEach((hex) => uniqueHexes.set(hex.toString(), hex)) | ||
return uniqueHexes | ||
}, new Map<string, T>()) | ||
.values() | ||
} | ||
} | ||
|
||
export type RaysOptions<T extends Hex> = StartOrAt & { | ||
length: number | ||
// todo: add arc option | ||
rotation?: RotationLike | ||
updateRay?: (hexesInRay: T[]) => T[] | ||
} |