Skip to content

Commit

Permalink
feat(grid): remove move() alias of line() and update signature of line()
Browse files Browse the repository at this point in the history
line() now accepts an object with options: `direction`, `length`, `at` and `start`. The `direction`
and `length` options are the same as before. The `at` option sets the cursor to the provided
coordinates, but doesn't include it. `start` does the same as `at` but *does* include those
coordinates. These `at` and `start` options will be added to most traversers.

BREAKING CHANGE: Remove move() alias of line(). line() now accepts an object with options: `direction`, `length`, `at` and `start`.
  • Loading branch information
flauwekeul committed Apr 22, 2021
1 parent e63f650 commit 5205e93
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 51 deletions.
32 changes: 8 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,15 @@ import { start, Compass, line } from 'honeycomb-grid'
// This traverses ("walks") over a grid following a triangular path:
grid
.traverse([
start({ q: 0, r: 0 }), // start at the hex with coordinates { q: 0, r: 0 }
line(Compass.E, 4), // move 4 hexes East
line(Compass.SW, 4), // move 4 hexes Southwest
line(Compass.NW, 3), // move 3 hexes Northwest to close the triangle
// start at the hex with coordinates { q: 0, r: 0 } and move 4 hexes East
line({ start: { q: 0, r: 0 }, direction: Compass.E, length: 4 }),
// then move 4 hexes Southwest
line({ direction: Compass.SW, length: 4 }),
// finally move 3 hexes Northwest to close the triangle
line({ direction: Compass.NW, length: 3 }),
])
.each((hex) => console.log(hex))
.run() // logs: Hex {q: 0, r: 0}, Hex {q: 1, r: 0}, Hex {q: 2, r: 0}, …
.run() // logs: Hex {q: 0, r: 0}, Hex {q: 1, r: 0}, Hex {q: 2, r: 0}, …

// You can also supply a custom traverser.
// It's called with:
Expand Down Expand Up @@ -343,7 +345,7 @@ These methods exist in v3 and they need to be considered for v4.
- [x] `ring()` traverser (always 1 hex thick)
- [ ] `spiral()` traverser (uses `ring()` internally and offers an API to skip to the next ring)?
- [ ] `rays()` traverser (produces hexes in straight lines from the start hex)
- [x] line (can be infinite): `line()` traverser (aliased to `move()`)
- [x] line: `line()` traverser ~~(aliased to `move()`)~~
- [x] ~~neighborsOf~~ replaced with `neighborOf()` (singular)
- [ ] pointHeight
- [ ] pointWidth
Expand Down Expand Up @@ -386,24 +388,6 @@ These methods exist in v3 and they need to be considered for v4.
- [ ] something that uses path finding algorithms like A*?
- [x] ~~`grid.createTraverser(function* customTraverser(options) {})(options)`~~
- [x] 👉 Make traversers even more fine-grained (~~seems very complex~~ it is, but worth it!)
```ts
// this creates a ring around startCoordinates
grid
.traverse((
start(startCoordinates),
move(Compass.E),
// use repeat() somehow:
// repeat.withIndex(5, (i) => move(i + 1))
// or:
// withIndex((i) => repeat(5, move(i + 1)))
move(Compass.SW),
move(Compass.W),
move(Compass.NW),
move(Compass.NE),
move(Compass.E),
)
.run()
```
- [ ] **Combination**:
- [ ] `grid.add(otherGrid)` / `grid.union(otherGrid)`
- [ ] `grid.subtract(otherGrid)`
Expand Down
6 changes: 3 additions & 3 deletions src/grid/functions/flatTraverse.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { CompassDirection } from '../../compass'
import { createHex, createHexPrototype } from '../../hex'
import { add, move } from '../traversers'
import { add, line } from '../traversers'
import { flatTraverse } from './flatTraverse'

const hexPrototype = createHexPrototype()
const cursor = createHex(hexPrototype)

test('returns an array of hexes if only a single traverser is passed', () => {
const traverser = move(CompassDirection.E, 2)
const traverser = line({ direction: CompassDirection.E, length: 2 })
const result = flatTraverse(traverser)(cursor, (coordinates) => createHex(hexPrototype, coordinates))

expect(result).toEqual([createHex(hexPrototype, { q: 1, r: 0 }), createHex(hexPrototype, { q: 2, r: 0 })])
})

test('flattens the passed traversers into a single traverser and returns it', () => {
const traversers = [add({ q: 1, r: 2 }), move(CompassDirection.S, 2)]
const traversers = [add({ q: 1, r: 2 }), line({ direction: CompassDirection.S, length: 2 })]
const result = flatTraverse(traversers)(cursor, (coordinates) => createHex(hexPrototype, coordinates))

expect(result).toEqual([
Expand Down
39 changes: 27 additions & 12 deletions src/grid/traversers/line.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,36 @@ import { createHex, createHexPrototype } from '../../hex'
import { line } from './line'

const hexPrototype = createHexPrototype()
const cursor = createHex(hexPrototype, { q: 1, r: 2 })
const getHex = jest.fn((coordinates) => createHex(hexPrototype, coordinates))

test('returns a traverser that moves the cursor in the passed direction', () => {
const hex = createHex(hexPrototype, { q: 1, r: 2 })
const getHex = jest.fn((hex) => hex)
describe('when called with only a direction', () => {
test('returns a traverser that returns a hex in the passed direction relative to the cursor', () => {
expect(line({ direction: CompassDirection.E })(cursor, getHex)).toMatchObject([{ q: 2, r: 2 }])
})
})

expect(line(CompassDirection.E)(hex, getHex)).toEqual([{ q: 2, r: 2 }])
describe('when called with at', () => {
test('returns a traverser that returns a hex in the passed direction relative to the "at" coordinates', () => {
expect(line({ direction: CompassDirection.E, at: { q: 3, r: 4 } })(cursor, getHex)).toMatchObject([{ q: 4, r: 4 }])
})
})

test('returns a traverser that moves the cursor in the passed direction the passed number of times', () => {
const hex = createHex(hexPrototype, { q: 1, r: 2 })
const getHex = jest.fn((coordinates) => createHex(hexPrototype, coordinates))
describe('when called with start', () => {
test('returns a traverser that returns the start and a hex in the passed direction relative to the "start" coordinates', () => {
expect(line({ direction: CompassDirection.E, start: { q: 3, r: 4 } })(cursor, getHex)).toMatchObject([
{ q: 3, r: 4 },
{ q: 4, r: 4 },
])
})
})

expect(line(CompassDirection.NW, 3)(hex, getHex)).toMatchObject([
{ q: 1, r: 1 },
{ q: 1, r: 0 },
{ q: 1, r: -1 },
])
describe('when called with length', () => {
test('returns a traverser that returns the passed amount of hexes in the passed direction relative to the cursor', () => {
expect(line({ direction: CompassDirection.NW, length: 3 })(cursor, getHex)).toMatchObject([
{ q: 1, r: 1 },
{ q: 1, r: 0 },
{ q: 1, r: -1 },
])
})
})
23 changes: 16 additions & 7 deletions src/grid/traversers/line.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import { CompassDirection } from '../../compass'
import { Hex } from '../../hex'
import { Hex, HexCoordinates } from '../../hex'
import { neighborOf } from '../functions'
import { Traverser } from '../types'

export const line = <T extends Hex>(direction: CompassDirection, length = 1): Traverser<T> => {
export const line = <T extends Hex>({ direction, start, at, length = 1 }: LineOptions): Traverser<T> => {
return (cursor, getHex) => {
const result: T[] = []
let _cursor = cursor
// todo: these 3 lines should be moved to a helper? e.g.: `const { hexes, cursor } = getInitialTraverserState(options)`
const startHex = start ? getHex(start) : null
const hexes: T[] = startHex ? [startHex] : []
let _cursor = startHex ?? (at ? getHex(at) : cursor)

for (let i = 1; i <= length; i++) {
_cursor = getHex(neighborOf(_cursor, direction))
result.push(_cursor)
hexes.push(_cursor)
}

return result
return hexes
}
}

export const move = line
// todo: probably extend from something that has `start` or `at` or neither (XOR)
// https://stackoverflow.com/a/53229567/660260
export interface LineOptions {
direction: CompassDirection
start?: HexCoordinates
at?: HexCoordinates
length?: number
}
9 changes: 4 additions & 5 deletions src/grid/traversers/rectangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Compass, CompassDirection } from '../../compass'
import { Hex, HexCoordinates, hexToOffset, OffsetCoordinates } from '../../hex'
import { isOffset } from '../../utils'
import { Traverser } from '../types'
import { add } from './add'
import { branch } from './branch'
import { line } from './line'

Expand All @@ -19,10 +18,10 @@ export function rectangle<T extends Hex>(
? optionsFromOpposingCorners(optionsOrCornerA as HexCoordinates, cornerB, cursor.isPointy, cursor.offset)
: (optionsOrCornerA as RectangleOptions)

return branch<T>([add(start), line(Compass.rotate(direction, 2), height - 1)], line(direction, width - 1))(
cursor,
getHex,
)
return branch<T>(
line({ start, direction: Compass.rotate(direction, 2), length: height - 1 }),
line({ direction, length: width - 1 }),
)(cursor, getHex)
}
}

Expand Down

0 comments on commit 5205e93

Please sign in to comment.