Skip to content

Commit

Permalink
feat(grid): remove map method, add filter and takeWhile methods and a…
Browse files Browse the repository at this point in the history
…dd inStore helper function

Having a map() method on Grid doesn't make much sense: what else than a hex should it map to?
takeWhile() stops once the passed predicate returns false. the inStore() helper function can be
passed to filter() or takeWhile() to only allow hexes present in the grid's store or an external
store (e.g.: `filter(inStore(externalStore))`).
  • Loading branch information
flauwekeul committed Apr 22, 2021
1 parent 306dae8 commit 956a2a0
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 27 deletions.
24 changes: 10 additions & 14 deletions playground/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { at, CompassDirection, createHexPrototype, Grid, Hex, move, Orientation } from '../dist'
import { at, CompassDirection, createHexPrototype, Grid, Hex, inStore, move, Orientation } from '../dist'
import { createSuite } from './benchmark'
import { render } from './render'

Expand All @@ -20,7 +20,7 @@ import { render } from './render'
* done: how does Grid know how to get hexes from store?
* -> store must have get() method
* statefulGrid.traverse() -> always over any hexes, but hexes are only created when not present in store
* todo: how to limit traversal outside store?
* done: how to limit traversal outside store?
* -> statefulGrid.traverse().takeWhile(inStore) // stops once a hex is traversed that's not in the store
* -> statefulGrid.traverse().filter(inStore) // rejects hexes that are not in the store
* done: how to update store?
Expand All @@ -45,22 +45,18 @@ const hexPrototype = createHexPrototype<CustomHex>({
// const hex = createHex(hexPrototype, { q: 4, r: 3 })

const store = new Map<string, CustomHex>()
const grid = Grid.of(hexPrototype, store)
// todo: when passed a store as 2nd argument, automatically use it (get and set)?
Grid.of(hexPrototype, store)
.rectangle({ start: { q: 0, r: 0 }, width: 10, height: 10 })
.traverse(at({ q: 0, r: 0 }), move(CompassDirection.SE, 4))
.traverse(move(CompassDirection.E, 8))
// .traverse(move(CompassDirection.NE, 6))
.each((hex) => {
.each((hex, { store }) => store.set(hex.toString(), hex))
.traverse(at({ q: 9, r: 0 }), move(CompassDirection.SE, 4), move(CompassDirection.SW, 4))
.filter(inStore())
// .takeWhile(inStore())
.run((hex) => {
hex.svg = render(hex)
// console.log(hex)
})
.map((hex, grid) => {
hex.custom = 'custom'
grid.store.set(hex.toString(), hex)
return hex
})
.run()
console.log('final', grid, store)
console.log('final', store)

const amount = 10
createSuite().add('onlyHexes', function () {
Expand Down
8 changes: 8 additions & 0 deletions src/grid/functions/inStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Hex } from '../../hex'
import { Grid } from '../grid'
import { GridStore } from '../types'

export const inStore = <T extends Hex, S extends GridStore<T>, G extends GridStore<T>>(store?: S) => (
hex: T,
grid: Grid<T, G>,
): boolean => !!(store ?? grid.store)?.get(hex.toString())
1 change: 1 addition & 0 deletions src/grid/functions/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './inStore'
export * from './neighborOf'
50 changes: 37 additions & 13 deletions src/grid/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,36 +35,60 @@ export class Grid<T extends Hex, S extends GridStore<T>> {
}

each(callback: (hex: T, grid: this) => void) {
const each = () => {
const each: GetPrevHexState<T, S> = () => {
const prevHexState = this.getPrevHexState()
for (const hex of prevHexState.hexes) {
callback(hex, this)
}
return prevHexState
}

return this.clone(each)
}

map(callback: (hex: T, grid: this) => T) {
const map = () => {
const { hexes, cursor } = this.getPrevHexState()
filter(callback: (hex: T, grid: this) => boolean) {
const filter: GetPrevHexState<T, S> = () => {
const nextHexes: T[] = []
for (const hex of hexes) {
nextHexes.push(callback(hex, this))
const prevHexState = this.getPrevHexState()
let cursor = prevHexState.cursor

for (const hex of prevHexState.hexes) {
if (callback(hex, this)) {
cursor = hex
nextHexes.push(cursor)
}
}

return { hexes: nextHexes, cursor }
}

return this.clone(map)
return this.clone(filter)
}

// todo: alias to take or takeUntil?
run(stopFn: (hex: T) => boolean = () => false) {
for (const hex of this.getPrevHexState().hexes) {
if (stopFn(hex)) {
return this
takeWhile(callback: (hex: T, grid: this) => boolean) {
const takeWhile: GetPrevHexState<T, S> = () => {
const nextHexes: T[] = []
const prevHexState = this.getPrevHexState()
let cursor = prevHexState.cursor

for (const hex of prevHexState.hexes) {
if (!callback(hex, this)) {
return { hexes: nextHexes, cursor }
}
cursor = hex
nextHexes.push(cursor)
}

return { hexes: nextHexes, cursor }
}

return this.clone(takeWhile)
}

// todo: maybe traversal should be done with separate curried function: traverse(...traversers)(grid): grid
// I should really test this with a project that uses Honeycomb, see what API works best
run(callback?: (hex: T, grid: this) => void) {
for (const hex of this.getPrevHexState().hexes) {
callback && callback(hex, this)
}
return this
}
Expand Down

0 comments on commit 956a2a0

Please sign in to comment.