Skip to content

Commit

Permalink
feat(grid): WIP: rewrite grid things to use iterables and transducers
Browse files Browse the repository at this point in the history
Transducers combined with iterables (generators mainly) are very efficient in terms of performance.
Also, they simplified the Grid class a lot. This huge commit lays the foundation to rewrite the
traversers that already exist and add more.
  • Loading branch information
flauwekeul committed Jul 23, 2022
1 parent c7a75c0 commit 3c97979
Show file tree
Hide file tree
Showing 27 changed files with 500 additions and 391 deletions.
34 changes: 34 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"rollup": "2.53.1",
"rollup-plugin-typescript2": "0.30.0",
"standard-version": "9.3.0",
"transducist": "2.2.0",
"ts-jest": "27.0.3",
"typescript": "4.7.4"
},
Expand Down
22 changes: 5 additions & 17 deletions playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,10 @@
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.0.16/svg.min.js"
integrity="sha512-p3Tp2zn+wApBreZCgRkmMwnfpN8MUPXzzOihXx7iGYXqE7t6m9drY8HeyMeeFuDWiTFKrGUrq3jpbT0vX6zY/Q=="
crossorigin="anonymous"
></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.6/platform.min.js"
integrity="sha512-eYPrm8TgYWg3aa6tvSRZjN4v0Z9Qx69q3RhfSj+Mf89QqwOMqmwSlsVqfp4N8NVAcZe/YeUhh9x/nM2CAOp6cA=="
crossorigin="anonymous"
></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.min.js"
integrity="sha512-xQc9DgKsysVXOYCdYCygJIizr64rtYYmNcOv4iKCBJw/xvuiaeG7FIwrkXuCgJg4U7oTqqNpknbC6eyc0NSREg=="
crossorigin="anonymous"
></script>
<script src="./index.ts"></script>
<script defer src="https://unpkg.com/@svgdotjs/svg.js"></script>
<script defer src="https://unpkg.com/platform"></script>
<script defer src="https://unpkg.com/lodash"></script>
<script defer src="https://unpkg.com/benchmark"></script>
<script type="module" src="./index.ts"></script>
</body>
</html>
62 changes: 50 additions & 12 deletions playground/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,66 @@
import { Compass, createHexPrototype, Grid, Hex, inStore, line, rectangle } from '../dist'
import { map } from 'transducist'
import { Compass, concat, createHexPrototype, fromCoordinates, Grid, Hex, line, move, repeat } from '../src'
import { createSuite } from './benchmark'
import { render } from './render'

interface CustomHex extends Hex {
[prop: string]: any
custom: string
}

const hexPrototype = createHexPrototype<CustomHex>({
dimensions: 30,
orientation: 'pointy',
custom: 'custom',
origin: 'topLeft',
})
// const hex = createHex(hexPrototype, { q: 4, r: 3 })

const grid = new Grid(hexPrototype, rectangle({ start: { q: 0, r: 0 }, width: 10, height: 10 }))
.traverse([line({ start: [9, 0], direction: Compass.SE, length: 4 }), line({ direction: Compass.SW, length: 4 })])
.filter(inStore)
.each((hex) => {
hex.svg = render(hex)
// console.log(hex)
})
.run()
console.log(grid.store)
const grid = new Grid(hexPrototype, [
fromCoordinates([2, 0]),
repeat(
2,
concat(
line({ length: 4, direction: Compass.E }),
move(Compass.S),
line({ length: 4, direction: Compass.W }),
move(Compass.S),
),
),
line({ length: 4, direction: Compass.E }),
])

/**
* todo: decide between update(grid.traverse(), transformer) and grid.update(transformer, grid.traverse()?)
* todo: traverser should adhere to rules:
* - max iteration (with sensible default) to prevent infinite loops
*
* update(grid, transformer): void -> transduce(grid, transformer, grid)
* update(grid.traverse(), transformer): void
* clone(grid, transformer?): newGrid -> transduce(grid, transformer, toGrid)
* clone(grid.traverse(), transformer?): newGrid
* ?? merge(grid, otherGrid, transformer?): void -> transduce(otherGrid, transformer, grid)
* ?? merge(grid.traverse(), otherGrid, transformer?): void
*
* or:
* grid.update(transformer, traverser?): grid
* grid.clone(transformer, traverser?): newGrid -> grid.clone() only clones the grid, a transformer like map(cloneHex) is needed to also clone the hexes
* ?? merge(grid, otherGrid): grid
* ?? add to grid
* ?? subtract from grid
*/

grid.update(
map((h) => {
const c = h.clone()
c.custom = 'custom'
return c
}),
grid.traverse(line({ length: 10, direction: Compass.E })),
)
// grid.toArray().forEach((h) => console.log(h))

for (const hex of grid) {
render(hex)
}

createSuite().add('', function () {
/* */
Expand Down
22 changes: 22 additions & 0 deletions playground/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,25 @@ export const render = (hex: Hex) => {

return draw.group().add(polygon).add(text)
}

// declare const PIXI: any

// const app = new PIXI.Application({ transparent: true })
// const graphics = new PIXI.Graphics()

// document.body.appendChild(app.view)
// // set a line style of 1px wide and color #999
// graphics.lineStyle(1, 0x999999)

// export const render = (hex: Hex) => {
// const [firstCorner, ...otherCorners] = hex.corners

// // move the "pen" to the first corner
// graphics.moveTo(firstCorner.x, firstCorner.y)
// // draw lines to the other corners
// otherCorners.forEach(({ x, y }) => graphics.lineTo(x, y))
// // finish at the first corner
// graphics.lineTo(firstCorner.x, firstCorner.y)

// app.stage.addChild(graphics)
// }
2 changes: 2 additions & 0 deletions src/compass/compass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export enum CompassDirection {
NW,
}

// todo: add lowercase strings to this type
// todo: use CompassDirectionLike as much as possible (instead of regular CompassDirection), this requires a util to convert this type to CompassDirection
export type CompassDirectionLike = keyof typeof CompassDirection | number

export class Compass {
Expand Down
15 changes: 15 additions & 0 deletions src/grid/functions/concat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Hex } from '../../hex'
import { HexGenerator, Traverser } from '../types'

export function concat<T extends Hex>(...traversers: Traverser<T>[]): Traverser<T, HexGenerator<T>> {
return function* concatTraverser(createHex, cursor) {
let _cursor = cursor
for (const traverser of traversers) {
// don't use `_cursor = yield* traverser(createHex, _cursor)` doesn't work if `traverser()` returns an array,
// because arrays always return `{ value: undefined, done: true }` when iterated
for (const hex of traverser(createHex, _cursor)) {
yield (_cursor = hex)
}
}
}
}
25 changes: 0 additions & 25 deletions src/grid/functions/flatTraverse.test.ts

This file was deleted.

20 changes: 0 additions & 20 deletions src/grid/functions/flatTraverse.ts

This file was deleted.

13 changes: 0 additions & 13 deletions src/grid/functions/inStore.test.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/grid/functions/inStore.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/grid/functions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './concat'
export * from './distance'
export * from './flatTraverse'
export * from './inStore'
export * from './neighborOf'
export * from './repeat'
1 change: 1 addition & 0 deletions src/grid/functions/neighborOf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ export const neighborOfFlat = <T extends Hex>({ offset, q, r, col, row }: T, dir
return { q: q + neighbor.q, r: r + neighbor.r }
}

// todo: rename to `neighborCoordinates` or `adjacentCoordinates`?
export const neighborOf = <T extends Hex>(hex: T, direction: CompassDirection): AxialCoordinates =>
hex.isPointy ? neighborOfPointy(hex, direction) : neighborOfFlat(hex, direction)
24 changes: 24 additions & 0 deletions src/grid/functions/repeat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Hex } from '../../hex'
import { HexGenerator, Traverser } from '../types'

export function repeat<T extends Hex>(
times: number,
traverser: Traverser<T>,
{ max = 100 } = {},
): Traverser<T, HexGenerator<T>> {
// todo: generalize this in all traversers that can potentially loop infinitely
if (times > max) {
console.warn(`Traverser created that outputs more hexes (${times}) than configured. Limiting iteration to ${max}.`)
}

const _times = Math.min(times, max)

return function* repeatTraverser(createHex, cursor) {
let _cursor = cursor
for (let i = 0; i < _times; i++) {
for (const hex of traverser(createHex, _cursor)) {
yield (_cursor = hex)
}
}
}
}

0 comments on commit 3c97979

Please sign in to comment.