@xtia/grid 0.0.6 → 0.0.7
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 +5 -5
- package/lib/grid.d.ts +7 -6
- package/lib/grid.js +28 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@ A mutable 2D grid with efficient region views, spatial operations, and seamless
|
|
|
11
11
|
- **Mutable 2D storage** with type safety
|
|
12
12
|
- **Zero-copy region views** - edit or provide subgrids and transformation layers without copying
|
|
13
13
|
- **Spatial operations** - fill, paste, flood fill, pathfinding
|
|
14
|
-
- **Pipe2D
|
|
15
|
-
- **Consistent API** - for grids and
|
|
14
|
+
- **First-class Pipe2D interoperability** – use grids as sources for pipes, or pipes as sources for grids
|
|
15
|
+
- **Consistent API** - for grids, regions, and your existing 2D structures
|
|
16
16
|
- **Mask support** - apply operations to arbitrary shapes
|
|
17
17
|
|
|
18
18
|
## Example
|
|
@@ -134,7 +134,7 @@ const mountainCells = world.cells.toFlatArrayXY()
|
|
|
134
134
|
|
|
135
135
|
## Cell interface
|
|
136
136
|
|
|
137
|
-
`grid.cells` provides a Pipe2D, for convenient transformation, of
|
|
137
|
+
`grid.cells` provides a Pipe2D, for convenient transformation, of Cell objects, each representing a live view into a grid location.
|
|
138
138
|
|
|
139
139
|
```ts
|
|
140
140
|
const topLeft = world.cells.get(0, 0);
|
|
@@ -210,9 +210,9 @@ Unlike visibility maps, which are lazily evaluated according to the supplied `is
|
|
|
210
210
|
|
|
211
211
|
`Grid` itself is an interface for reading and writing 2D data. `GridBase` - a subclass of `Grid` - maintains the actual storage of such data.
|
|
212
212
|
|
|
213
|
-
Although the Grid factory methods (`Grid.solid()`, `Grid.from()`, `Grid.init()`) return a `GridBase<T
|
|
213
|
+
Although the Grid factory methods (`Grid.solid<T>()`, `Grid.from<T>()`, `Grid.init<T>()`) belong to `Grid`, they return a `GridBase<T>`. `Grid.wrap<T>()` is an exception, returning `Grid<T>`, as it uses a storage layer provided by the user. The only API distinction is that `GridBase` provides a 'change' event, via `grid.on("change", handler)`.
|
|
214
214
|
|
|
215
|
-
|
|
215
|
+
We can perform batched updates, suppressing the 'change' event until a process concludes, with `grid.batchUpdate(callback)`.
|
|
216
216
|
|
|
217
217
|
## Save and load
|
|
218
218
|
|
package/lib/grid.d.ts
CHANGED
|
@@ -16,12 +16,13 @@ type PathFindOptions<T> = {
|
|
|
16
16
|
shortcutMap?: Source2D<Cell<T>[] | undefined>;
|
|
17
17
|
};
|
|
18
18
|
type CostMapOptions<T> = PathFindOptions<T> & {
|
|
19
|
-
stopAt?:
|
|
19
|
+
stopAt?: LocationSpec<T>;
|
|
20
20
|
};
|
|
21
21
|
type VisibilityOptions = {
|
|
22
22
|
maxDistance?: number;
|
|
23
23
|
boundariesVisible?: boolean;
|
|
24
24
|
};
|
|
25
|
+
type LocationSpec<T> = Cell<T> | [number, number];
|
|
25
26
|
export declare enum TraversalType {
|
|
26
27
|
cardinal = 0,
|
|
27
28
|
diagonal = 1,
|
|
@@ -38,16 +39,16 @@ export declare class Cell<T> {
|
|
|
38
39
|
constructor(x: number, y: number, gridView: Grid<T>);
|
|
39
40
|
get value(): T;
|
|
40
41
|
set value(v: T);
|
|
42
|
+
private getSiblingCell;
|
|
43
|
+
private getSiblingXY;
|
|
41
44
|
getNeighbours(includeDiagonals?: boolean): Cell<T>[];
|
|
42
45
|
look(xDelta: number, yDelta: number): Cell<T> | undefined;
|
|
43
|
-
findPath(target:
|
|
46
|
+
findPath(target: LocationSpec<T>, getCost: CostFunc<T>, options?: PathFindOptions<T>): Cell<T>[] | null;
|
|
44
47
|
getPathMap(getCost: CostFunc<T>, options?: PathFindOptions<T>): Pipe2D<Cell<T>[] | null>;
|
|
45
48
|
getCostMap(getCost: CostFunc<T>, options?: CostMapOptions<T>): Pipe2D<number>;
|
|
46
49
|
private calculateCosts;
|
|
47
|
-
getLineTo(target:
|
|
48
|
-
|
|
49
|
-
y: number;
|
|
50
|
-
} | [number, number]): IterableIterator<Cell<T>>;
|
|
50
|
+
getLineTo(target: LocationSpec<T>): IterableIterator<Cell<T>>;
|
|
51
|
+
getLineTo(x: number, y: number): IterableIterator<Cell<T>>;
|
|
51
52
|
createVisibilityMap(isClear: (cell: Cell<T>) => boolean, options?: VisibilityOptions): Pipe2D<boolean>;
|
|
52
53
|
}
|
|
53
54
|
export declare class Grid<T> {
|
package/lib/grid.js
CHANGED
|
@@ -18,6 +18,22 @@ export class Cell {
|
|
|
18
18
|
set value(v) {
|
|
19
19
|
this.gridView.set(this.x, this.y, v);
|
|
20
20
|
}
|
|
21
|
+
getSiblingCell(location) {
|
|
22
|
+
if (Array.isArray(location))
|
|
23
|
+
return this.gridView.cells.get(...location);
|
|
24
|
+
if (location.gridView !== this.gridView) {
|
|
25
|
+
throw new Error("Target cell belongs to a different Grid");
|
|
26
|
+
}
|
|
27
|
+
return location;
|
|
28
|
+
}
|
|
29
|
+
getSiblingXY(location) {
|
|
30
|
+
if (Array.isArray(location))
|
|
31
|
+
return location;
|
|
32
|
+
if (location.gridView !== this.gridView) {
|
|
33
|
+
throw new Error("Target cell belongs to a different Grid");
|
|
34
|
+
}
|
|
35
|
+
return [location.x, location.y];
|
|
36
|
+
}
|
|
21
37
|
getNeighbours(includeDiagonals = false) {
|
|
22
38
|
const offsets = includeDiagonals
|
|
23
39
|
? [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
|
|
@@ -34,15 +50,12 @@ export class Cell {
|
|
|
34
50
|
return this.gridView.cells.get(xDelta + this.x, yDelta + this.y);
|
|
35
51
|
}
|
|
36
52
|
findPath(target, getCost, options = {}) {
|
|
37
|
-
const targetXY = Array.isArray(target)
|
|
38
|
-
? target
|
|
39
|
-
: [target.x, target.y];
|
|
40
53
|
const pathMap = this.calculateCosts(getCost, {
|
|
41
|
-
stopAt:
|
|
54
|
+
stopAt: target,
|
|
42
55
|
allowDiagonal: options.allowDiagonal,
|
|
43
56
|
maxCost: options.maxCost,
|
|
44
57
|
}, true);
|
|
45
|
-
return pathMap === null || pathMap === void 0 ? void 0 : pathMap.get(...
|
|
58
|
+
return pathMap === null || pathMap === void 0 ? void 0 : pathMap.get(...this.getSiblingXY(target));
|
|
46
59
|
}
|
|
47
60
|
getPathMap(getCost, options = {}) {
|
|
48
61
|
return this.calculateCosts(getCost, options, true);
|
|
@@ -61,24 +74,21 @@ export class Cell {
|
|
|
61
74
|
: null;
|
|
62
75
|
costs.set(this, 0);
|
|
63
76
|
const queue = new OrderedQueue(cell => { var _a; return (_a = costs.get(cell)) !== null && _a !== void 0 ? _a : Infinity; }, this);
|
|
64
|
-
const
|
|
65
|
-
? this.gridView.cells.get(options.stopAt[0], options.stopAt[1])
|
|
66
|
-
: options.stopAt;
|
|
67
|
-
if (targetCell && targetCell.gridView !== this.gridView) {
|
|
68
|
-
throw new Error("Target cell belongs to a different Grid");
|
|
69
|
-
}
|
|
77
|
+
const stopAtCell = options.stopAt && this.getSiblingCell(options.stopAt);
|
|
70
78
|
while (queue.length > 0) {
|
|
71
79
|
const current = queue.take();
|
|
72
80
|
(_a = options.onVisit) === null || _a === void 0 ? void 0 : _a.call(options, { cell: current, cost: costs.get(current) });
|
|
73
81
|
if (visited.has(current))
|
|
74
82
|
continue;
|
|
75
83
|
visited.add(current);
|
|
76
|
-
if (
|
|
84
|
+
if (stopAtCell && current === stopAtCell) {
|
|
77
85
|
break;
|
|
78
86
|
}
|
|
79
87
|
const currentCost = costs.get(current);
|
|
80
88
|
const neighbours = current.getNeighbours(options.allowDiagonal).map(cell => ({
|
|
81
|
-
traversalType: cell.x == current.x && cell.y == current.y
|
|
89
|
+
traversalType: cell.x == current.x && cell.y == current.y
|
|
90
|
+
? TraversalType.cardinal
|
|
91
|
+
: TraversalType.diagonal,
|
|
82
92
|
cell
|
|
83
93
|
}));
|
|
84
94
|
if (options.shortcutMap) {
|
|
@@ -135,10 +145,10 @@ export class Cell {
|
|
|
135
145
|
return this.gridView.cells.map(costs, () => Infinity)
|
|
136
146
|
.strict();
|
|
137
147
|
}
|
|
138
|
-
*getLineTo(
|
|
139
|
-
const [targetX, targetY] =
|
|
140
|
-
?
|
|
141
|
-
:
|
|
148
|
+
*getLineTo(targetOrX, _targetY) {
|
|
149
|
+
const [targetX, targetY] = typeof targetOrX == "number"
|
|
150
|
+
? [targetOrX, _targetY]
|
|
151
|
+
: this.getSiblingXY(targetOrX);
|
|
142
152
|
if (this.x === targetX && this.y === targetY) {
|
|
143
153
|
yield this;
|
|
144
154
|
return;
|
|
@@ -182,7 +192,7 @@ export class Cell {
|
|
|
182
192
|
return false;
|
|
183
193
|
}
|
|
184
194
|
}
|
|
185
|
-
for (const cell of this.getLineTo(
|
|
195
|
+
for (const cell of this.getLineTo([x, y])) {
|
|
186
196
|
if (isClear(cell))
|
|
187
197
|
continue;
|
|
188
198
|
return cell.x === x && cell.y === y
|
package/package.json
CHANGED