Skip to content

Commit

Permalink
feat(grid): subsequent traverse() calls now stop when attempting to t…
Browse files Browse the repository at this point in the history
…raverse outside the grid

When a grid has a traverser that's not the (default) infiniteGenerator (currently this can be
achieved with grid.rectangle() and grid.traverse(), or by creating a grid with a custom traverser)
and it's traversed again, the 2nd traverser (and all subsequent traversers) return early when an
attempt is made to move to hex coordinates that are not in the first traverser
  • Loading branch information
flauwekeul committed Apr 22, 2021
1 parent bdfb22b commit 1aa8f73
Showing 1 changed file with 16 additions and 21 deletions.
37 changes: 16 additions & 21 deletions src/grid/grid.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createHex, Hex } from '../hex'
import { createHex, equals, Hex, HexCoordinates } from '../hex'
import { rectangle, RectangleOptions } from './functions'
import { GridGenerator, Traverser } from './types'

Expand All @@ -9,30 +9,18 @@ interface InternalTraverser<T extends Hex> {
// eslint-disable-next-line @typescript-eslint/no-empty-function
function* infiniteTraverser<T extends Hex>(): GridGenerator<T> {}

// fixme: there's a lot of duplicate iteration, use a cache (or memoisation?)
export class Grid<T extends Hex> {
static of<T extends Hex>(hexPrototype: T, traverser?: InternalTraverser<T>) {
return new Grid(hexPrototype, traverser)
}

// todo: rename traverser to iterator?
constructor(public hexPrototype: T, private traverser: InternalTraverser<T> = infiniteTraverser) {}

[Symbol.iterator]() {
return this.traverser()
}

has(coordinates: HexCoordinates) {
// the defaultTraverser "has" all coordinates
if (this.traverser === infiniteTraverser) {
return true
}
for (const hex of this) {
if (equals(hex, coordinates)) {
return true
}
}
}

clone(traverser = this.traverser) {
return Grid.of(this.hexPrototype, traverser.bind(this))
}
Expand All @@ -45,8 +33,8 @@ export class Grid<T extends Hex> {
// fixme: use generic functions for these kinds of operations
// something like https://github.com/benji6/imlazy or https://github.com/lodash/lodash/wiki/FP-Guide
each(fn: (hex: T) => void) {
const each: InternalTraverser<T> = function* () {
for (const hex of this) {
const each: InternalTraverser<T> = function* each() {
for (const hex of this.traverser()) {
fn(hex)
yield hex
}
Expand All @@ -55,8 +43,8 @@ export class Grid<T extends Hex> {
}

map(fn: (hex: T) => T) {
const map: InternalTraverser<T> = function* () {
for (const hex of this) {
const map: InternalTraverser<T> = function* map() {
for (const hex of this.traverser()) {
yield fn(hex)
}
}
Expand All @@ -65,7 +53,7 @@ export class Grid<T extends Hex> {

// todo: alias to take or takeUntil?
run(stopFn: (hex: T) => boolean = () => false) {
for (const hex of this) {
for (const hex of this.traverser()) {
if (stopFn(hex)) {
return this
}
Expand All @@ -77,16 +65,23 @@ export class Grid<T extends Hex> {
if (commands.length === 0) {
return this // or clone()? todo: when to return clone and when not?
}
let coordinates = this.traverser().next().value || { q: 0, r: 0 }

function* traverse(this: Grid<T>) {
const traverse: InternalTraverser<T> = function* traverse() {
const hasTraversedBefore = this.traverser !== infiniteTraverser
const previousHexes = [...this.traverser()]
let coordinates: HexCoordinates = previousHexes[previousHexes.length - 1] || { q: 0, r: 0 }

for (const command of commands) {
for (const nextCoordinates of command(coordinates)) {
coordinates = nextCoordinates
if (hasTraversedBefore && !previousHexes.some((prevCoords) => equals(prevCoords, coordinates))) {
return // todo: or continue? or make this configurable?
}
yield createHex(this.hexPrototype, coordinates)
}
}
}

return this.clone(traverse)
}
}

0 comments on commit 1aa8f73

Please sign in to comment.