@xtia/grid 0.0.13 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `Grid`
2
2
 
3
- **Alpha**: Pre-0.1.0 API details may change
3
+ **Beta**: Stable core, open to refinement pre-1.0.0
4
4
 
5
5
  ## Summary
6
6
 
@@ -22,7 +22,7 @@ npm i @xtia/grid
22
22
  ```
23
23
 
24
24
  ```ts
25
- import { Grid } from "@xtia/grid"; // ~4.8kb gzipped
25
+ import { Grid } from "@xtia/grid"; // ~4.8kb gzipped (2.2kb + Pipe2D dep)
26
26
 
27
27
  // initialise a 30x20 Grid<number> of 0's
28
28
  const numGrid = Grid.solid(30, 20, 0);
@@ -32,7 +32,7 @@ numGrid.set(3, 3, 50);
32
32
 
33
33
  // initialise a chessboard
34
34
  const chessGrid = Grid.init(8, 8, (x, y) =>
35
- (x + y) % 2 === 0 ? 'black' : 'white'
35
+ (x + y) % 2 === 0 ? 'black' : 'white'
36
36
  );
37
37
 
38
38
  // read a value
@@ -106,12 +106,11 @@ const lakeGrid = Grid.from(lakeRegion);
106
106
 
107
107
  ```ts
108
108
  const spriteMap = world.map(
109
- type => type + ".png",
110
- sprite => sprite.replace(/\..*/, '')
109
+ type => type + ".png", // add .png on parent-read
110
+ sprite => sprite.replace(/\..*/, '') // remove it on parent-write
111
111
  );
112
112
 
113
- world.set(0, 0, "mountain"); // modify the parent
114
- console.log(spriteMap.get(0, 0)); // read the transformed view: "mountain.png"
113
+ console.log(spriteMap.get(0, 0)); // read the transformed view: "grass.png"
115
114
  spriteMap.set(1, 0, "forest.png"); // modify the view
116
115
  console.log(world.get(1, 0)); // read the parent: "forest"
117
116
  ```
@@ -144,7 +143,6 @@ const minimap = world.pipe
144
143
  .floorCoordinates()
145
144
  .crop(viewX, viewY, vw, vh)
146
145
  .stretch(canvas.width, canvas.height);
147
-
148
146
  ```
149
147
 
150
148
  ## Cell interface
@@ -248,7 +246,7 @@ world.paste(snapshot);
248
246
  For persistent storage or transmission, Pipe2D can export as array:
249
247
 
250
248
  ```ts
251
- const saved = snapshot.toFlatArrayXY(); // ["mountain", "forest", "grass", ...]
249
+ const saved = snapshot.toFlatArrayXY(); // ["grass", "forest", "grass", ...]
252
250
 
253
251
  const restoredSnapshot = Pipe2D.fromFlatArrayXY(saved);
254
252
  ```
package/lib/grid.d.ts CHANGED
@@ -67,13 +67,8 @@ export declare class Grid<T> {
67
67
  fill(value: T): void;
68
68
  paste(source: Source2D<T>, x?: number, y?: number): void;
69
69
  writeMask(mask: Source2D<boolean> | GetXYFunc<boolean>): Grid<T>;
70
- [Symbol.iterator](): IterableIterator<{
71
- x: number;
72
- y: number;
73
- value: T;
74
- }>;
70
+ [Symbol.iterator](): IterableIterator<T>;
75
71
  forEach(callback: (value: T, x: number, y: number) => void): void;
76
- combine<U, R>(aux: Source2D<U>, cb: (source: T, aux: U) => R): GridBase<R>;
77
72
  map<U>(read: (initial: T, x: number, y: number) => U, write: (local: U, x: number, y: number) => T): Grid<U>;
78
73
  region(x: number, y: number, width: number, height: number): Grid<T>;
79
74
  scroll(xDelta: number, yDelta: number, fill: T): this;
@@ -90,7 +85,6 @@ export declare class GridBase<T> extends Grid<T> {
90
85
  batchUpdate(fn: () => void): void;
91
86
  constructor(source: Source2D<T>);
92
87
  on<K extends keyof EventMap<T>>(eventName: K, handler: (data: EventMap<T>[K]) => void): () => void;
93
- private xyToIndex;
94
88
  private _set;
95
89
  private triggerChange;
96
90
  }
package/lib/grid.js CHANGED
@@ -215,6 +215,9 @@ export class Grid {
215
215
  this.parentSet = parentSet;
216
216
  this.batch = batch;
217
217
  this.cells = new Pipe2D(this.width, this.height, (x, y) => {
218
+ if (x < 0 || x >= this.width || y < 0 || y >= this.height || !Number.isInteger(x) || !Number.isInteger(y)) {
219
+ throw new RangeError(`Cell coordinates must be bounded integers; got (${x}, ${y})`);
220
+ }
218
221
  return new Cell(x, y, this);
219
222
  }).strict().withCache();
220
223
  this.pipe = new Pipe2D(this);
@@ -261,7 +264,7 @@ export class Grid {
261
264
  this.batchUpdate(() => {
262
265
  for (let y = 0; y < this.height; y++) {
263
266
  for (let x = 0; x < this.width; x++) {
264
- this.trySet(x, y, value);
267
+ this.set(x, y, value);
265
268
  }
266
269
  }
267
270
  });
@@ -271,7 +274,10 @@ export class Grid {
271
274
  this.batchUpdate(() => {
272
275
  for (let oy = 0; oy < source.height; oy++) {
273
276
  for (let ox = 0; ox < source.width; ox++) {
274
- this.trySet(ox + x, oy + y, cachedSource.get(ox, oy));
277
+ const tx = ox + x, ty = oy + y;
278
+ if (tx < 0 || tx >= this.width || ty < 0 || ty >= this.height)
279
+ continue;
280
+ this.set(tx, ty, cachedSource.get(ox, oy));
275
281
  }
276
282
  }
277
283
  });
@@ -290,7 +296,7 @@ export class Grid {
290
296
  *[Symbol.iterator]() {
291
297
  for (let y = 0; y < this.height; y++) {
292
298
  for (let x = 0; x < this.width; x++) {
293
- yield { x, y, value: this.get(x, y) };
299
+ yield this.get(x, y);
294
300
  }
295
301
  }
296
302
  }
@@ -301,22 +307,11 @@ export class Grid {
301
307
  }
302
308
  }
303
309
  }
304
- combine(aux, cb) {
305
- const width = Math.min(this.width, aux.width);
306
- const height = Math.min(this.height, aux.height);
307
- return new GridBase({
308
- width,
309
- height,
310
- get: (x, y) => {
311
- return cb(this.get(x, y), aux.get(x, y));
312
- }
313
- });
314
- }
315
310
  map(read, write) {
316
311
  return new Grid(this.width, this.height, (x, y) => read(this.parentGet(x, y), x, y), (x, y, value) => this.parentSet(x, y, write(value, x, y)), fn => this.batch(fn));
317
312
  }
318
313
  region(x, y, width, height) {
319
- if (!Number.isInteger(x) || !Number.isInteger(y) || !Number.isInteger(width) || !Number.isInteger(height)) {
314
+ if (!Number.isInteger(x) || !Number.isInteger(y)) {
320
315
  throw new Error(`Region boundaries must be integer; got (${x}, ${y}), (${width} x ${height})`);
321
316
  }
322
317
  if (x < 0 || y < 0 || x + width > this.width || y + height > this.height) {
@@ -384,11 +379,12 @@ export class GridBase extends Grid {
384
379
  if (this.batchState.level == 0) {
385
380
  const changed = this.batchState.changedCells;
386
381
  this.batchState = null;
387
- this.triggerChange(changed);
382
+ if (changed.size > 0)
383
+ this.triggerChange(changed);
388
384
  }
389
385
  }
390
386
  constructor(source) {
391
- super(source.width, source.height, (x, y) => this.data[this.xyToIndex(x, y)], (x, y, value) => this._set(x, y, value), fn => this.batchUpdate(fn));
387
+ super(source.width, source.height, (x, y) => this.data[y * this.width + x], (x, y, value) => this._set(x, y, value), fn => this.batchUpdate(fn));
392
388
  this.eventHandlers = {};
393
389
  this.batchState = null;
394
390
  const sourcePipe = source instanceof Pipe2D
@@ -408,20 +404,11 @@ export class GridBase extends Grid {
408
404
  this.eventHandlers[eventName].splice(idx, 1);
409
405
  };
410
406
  }
411
- xyToIndex(x, y) {
412
- if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
413
- throw new Error(`Coordinates out of bounds: (${x}, ${y})`);
414
- }
415
- if (!Number.isInteger(x) || !Number.isInteger(y)) {
416
- throw new Error(`Coordinates must be integer; got (${x}, ${y})`);
417
- }
418
- return y * this.width + x;
419
- }
420
407
  _set(x, y, value) {
421
- const idx = this.xyToIndex(x, y);
408
+ const idx = y * this.width + x;
422
409
  if (this.data[idx] === value)
423
410
  return;
424
- this.data[this.xyToIndex(x, y)] = value;
411
+ this.data[idx] = value;
425
412
  if (this.batchState) {
426
413
  this.batchState.changedCells.add(this.cells.get(x, y));
427
414
  return;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.13",
2
+ "version": "0.1.1",
3
3
  "description": "2D store and utilities, with zero-copy regions and transform layers, pathfinding, Pipe2D interop",
4
4
  "name": "@xtia/grid",
5
5
  "exports": {
@@ -12,8 +12,7 @@
12
12
  "keywords": [
13
13
  "grid",
14
14
  "game-dev",
15
- "pathfinding",
16
- "cellular-automata"
15
+ "pathfinding"
17
16
  ],
18
17
  "scripts": {
19
18
  "build": "npx tsc",