@xtia/grid 0.0.11 → 0.0.13
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 +6 -1
- package/lib/grid.d.ts +1 -0
- package/lib/grid.js +40 -3
- package/lib/utils.d.ts +2 -3
- package/lib/utils.js +3 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -179,6 +179,9 @@ const numOfAdjacentMines = clickedCell.getNeighbours(true)
|
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
### Path finding
|
|
182
|
+
|
|
183
|
+
`findPath()` computes an optimal path from a cell to another location in the grid, accounting for cell/traversal costs according to a user-provided predicate or `Map<T, number>`.
|
|
184
|
+
|
|
182
185
|
```ts
|
|
183
186
|
const costs = {
|
|
184
187
|
grass: 1,
|
|
@@ -189,6 +192,7 @@ const costs = {
|
|
|
189
192
|
|
|
190
193
|
const start = world.cells.get(5, 5);
|
|
191
194
|
const destination = world.cells.get(90, 90);
|
|
195
|
+
|
|
192
196
|
const path = start.findPath(
|
|
193
197
|
destination, // or simply [90, 90]
|
|
194
198
|
(cell) => costs[cell.value]
|
|
@@ -197,13 +201,14 @@ const path = start.findPath(
|
|
|
197
201
|
|
|
198
202
|
### Visibility mapping
|
|
199
203
|
|
|
204
|
+
`createVisibilityMap()` returns a `Pipe2D<boolean>` that maps which cells are 'visible' from the starting point, according to a user-provided predicate to determine which cells block vision.
|
|
205
|
+
|
|
200
206
|
```ts
|
|
201
207
|
// createVisibilityMap(isClear);
|
|
202
208
|
const visibility = start.createVisibilityMap(
|
|
203
209
|
cell => cell.value === "grass" // anything except grass blocks vision
|
|
204
210
|
);
|
|
205
211
|
|
|
206
|
-
// writeMask() creates a live view that only allows writes at positions allowed by the mask Source2D/function
|
|
207
212
|
screenGrid.writeMask(visibility).paste(spriteMap, 0, 0);
|
|
208
213
|
```
|
|
209
214
|
|
package/lib/grid.d.ts
CHANGED
|
@@ -76,6 +76,7 @@ export declare class Grid<T> {
|
|
|
76
76
|
combine<U, R>(aux: Source2D<U>, cb: (source: T, aux: U) => R): GridBase<R>;
|
|
77
77
|
map<U>(read: (initial: T, x: number, y: number) => U, write: (local: U, x: number, y: number) => T): Grid<U>;
|
|
78
78
|
region(x: number, y: number, width: number, height: number): Grid<T>;
|
|
79
|
+
scroll(xDelta: number, yDelta: number, fill: T): this;
|
|
79
80
|
static init<T>(width: number, height: number, initCell: (x: number, y: number) => T): GridBase<T>;
|
|
80
81
|
static from<T>(source: Source2D<T>): GridBase<T>;
|
|
81
82
|
static solid<T>(width: number, height: number, fillValue: T): GridBase<T>;
|
package/lib/grid.js
CHANGED
|
@@ -72,7 +72,7 @@ export class Cell {
|
|
|
72
72
|
? (cell) => { var _a; return (_a = getCost.get(cell.value)) !== null && _a !== void 0 ? _a : Infinity; }
|
|
73
73
|
: getCost;
|
|
74
74
|
costs.set(this, 0);
|
|
75
|
-
const queue = new OrderedQueue(
|
|
75
|
+
const queue = new OrderedQueue([this, 0]);
|
|
76
76
|
const stopAtCell = options.stopAt && this.getSiblingCell(options.stopAt);
|
|
77
77
|
while (queue.length > 0) {
|
|
78
78
|
const current = queue.take();
|
|
@@ -115,7 +115,7 @@ export class Cell {
|
|
|
115
115
|
if (newCost < oldCost && newCost <= maxCost) {
|
|
116
116
|
costs.set(n.cell, newCost);
|
|
117
117
|
pathInfo === null || pathInfo === void 0 ? void 0 : pathInfo.set(n.cell, current);
|
|
118
|
-
queue.add(n.cell);
|
|
118
|
+
queue.add(n.cell, newCost);
|
|
119
119
|
}
|
|
120
120
|
});
|
|
121
121
|
}
|
|
@@ -218,17 +218,29 @@ export class Grid {
|
|
|
218
218
|
return new Cell(x, y, this);
|
|
219
219
|
}).strict().withCache();
|
|
220
220
|
this.pipe = new Pipe2D(this);
|
|
221
|
+
if (!Number.isInteger(width) || !Number.isInteger(height)) {
|
|
222
|
+
throw new Error(`Grid width & height must be integer; got (${width} x ${height})`);
|
|
223
|
+
}
|
|
224
|
+
if (width < 0 || height < 0) {
|
|
225
|
+
throw new Error(`Grid width/height may not be less than 0; got (${width} x ${height})`);
|
|
226
|
+
}
|
|
221
227
|
}
|
|
222
228
|
batchUpdate(fn) {
|
|
223
229
|
this.batch(fn);
|
|
224
230
|
}
|
|
225
231
|
get(x, y) {
|
|
232
|
+
if (!Number.isInteger(x) || !Number.isInteger(y)) {
|
|
233
|
+
throw new Error(`Coordinates must be integer; got (${x}, ${y})`);
|
|
234
|
+
}
|
|
226
235
|
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
|
|
227
236
|
throw new RangeError("Coordinates out of bounds");
|
|
228
237
|
}
|
|
229
238
|
return this.parentGet(x, y);
|
|
230
239
|
}
|
|
231
240
|
set(x, y, value) {
|
|
241
|
+
if (!Number.isInteger(x) || !Number.isInteger(y)) {
|
|
242
|
+
throw new Error(`Coordinates must be integer; got (${x}, ${y})`);
|
|
243
|
+
}
|
|
232
244
|
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
|
|
233
245
|
throw new RangeError("Coordinates out of bounds");
|
|
234
246
|
}
|
|
@@ -255,7 +267,7 @@ export class Grid {
|
|
|
255
267
|
});
|
|
256
268
|
}
|
|
257
269
|
paste(source, x = 0, y = 0) {
|
|
258
|
-
const cachedSource = new
|
|
270
|
+
const cachedSource = new Pipe2D(source).stash();
|
|
259
271
|
this.batchUpdate(() => {
|
|
260
272
|
for (let oy = 0; oy < source.height; oy++) {
|
|
261
273
|
for (let ox = 0; ox < source.width; ox++) {
|
|
@@ -304,12 +316,37 @@ export class Grid {
|
|
|
304
316
|
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));
|
|
305
317
|
}
|
|
306
318
|
region(x, y, width, height) {
|
|
319
|
+
if (!Number.isInteger(x) || !Number.isInteger(y) || !Number.isInteger(width) || !Number.isInteger(height)) {
|
|
320
|
+
throw new Error(`Region boundaries must be integer; got (${x}, ${y}), (${width} x ${height})`);
|
|
321
|
+
}
|
|
322
|
+
if (x < 0 || y < 0 || x + width > this.width || y + height > this.height) {
|
|
323
|
+
throw new Error("Requested region exceeds the parent's bounds");
|
|
324
|
+
}
|
|
307
325
|
return new Grid(width, height, (tx, ty) => {
|
|
308
326
|
return this.parentGet(tx + x, ty + y);
|
|
309
327
|
}, (tx, ty, value) => {
|
|
310
328
|
this.parentSet(tx + x, ty + y, value);
|
|
311
329
|
}, fn => this.batch(fn));
|
|
312
330
|
}
|
|
331
|
+
scroll(xDelta, yDelta, fill) {
|
|
332
|
+
if (!Number.isInteger(xDelta) || !Number.isInteger(yDelta)) {
|
|
333
|
+
throw new Error(`Scroll offsets must be integer; got (${xDelta}, ${yDelta})`);
|
|
334
|
+
}
|
|
335
|
+
this.paste(this, xDelta, yDelta);
|
|
336
|
+
if (xDelta > 0) {
|
|
337
|
+
this.region(0, 0, xDelta, this.height).fill(fill);
|
|
338
|
+
}
|
|
339
|
+
else if (xDelta < 0) {
|
|
340
|
+
this.region(this.width + xDelta, 0, -xDelta, this.height).fill(fill);
|
|
341
|
+
}
|
|
342
|
+
if (yDelta > 0) {
|
|
343
|
+
this.region(0, 0, this.width, yDelta).fill(fill);
|
|
344
|
+
}
|
|
345
|
+
else if (yDelta < 0) {
|
|
346
|
+
this.region(0, this.height + yDelta, this.width, -yDelta).fill(fill);
|
|
347
|
+
}
|
|
348
|
+
return this;
|
|
349
|
+
}
|
|
313
350
|
static init(width, height, initCell) {
|
|
314
351
|
return new GridBase({
|
|
315
352
|
width,
|
package/lib/utils.d.ts
CHANGED
|
@@ -5,10 +5,9 @@ export type Source2D<T> = {
|
|
|
5
5
|
get: GetXYFunc<T>;
|
|
6
6
|
};
|
|
7
7
|
export declare class OrderedQueue<T> {
|
|
8
|
-
private getCost;
|
|
9
8
|
private queue;
|
|
10
|
-
constructor(
|
|
11
|
-
add(value: T): void;
|
|
9
|
+
constructor(...items: [T, number][]);
|
|
10
|
+
add(value: T, priority: number): void;
|
|
12
11
|
get length(): number;
|
|
13
12
|
take(): T;
|
|
14
13
|
}
|
package/lib/utils.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
export class OrderedQueue {
|
|
2
|
-
constructor(
|
|
3
|
-
this.getCost = getCost;
|
|
2
|
+
constructor(...items) {
|
|
4
3
|
this.queue = [];
|
|
5
|
-
|
|
4
|
+
items.forEach(v => this.add(...v));
|
|
6
5
|
}
|
|
7
|
-
add(value) {
|
|
8
|
-
const priority = this.getCost(value);
|
|
6
|
+
add(value, priority) {
|
|
9
7
|
const item = { value, priority };
|
|
10
8
|
let low = 0, high = this.queue.length;
|
|
11
9
|
while (low < high) {
|
package/package.json
CHANGED