Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions gameblocks/modules/behavior/GridPathPlanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ function wrapDelta(delta, size) {
return Math.min(Math.abs(delta), size - Math.abs(delta));
}

function wrapCoord(value, size) {
if (!Number.isFinite(size) || size <= 0) return 0;
let wrapped = value % size;
if (wrapped < 0) wrapped += size;
return wrapped;
}

function priorityInsert(open, entry) {
let index = open.length;
while (index > 0 && open[index - 1].f > entry.f) {
Expand All @@ -43,10 +50,8 @@ function stepCell(cell, direction, board, wrap, navigation) {
};

if (wrap) {
if (next.right < 0) next.right = board.columns - 1;
if (next.right >= board.columns) next.right = 0;
if (next.forward < 0) next.forward = board.rows - 1;
if (next.forward >= board.rows) next.forward = 0;
next.right = wrapCoord(next.right, board.columns);
next.forward = wrapCoord(next.forward, board.rows);
return next;
}

Expand Down
33 changes: 33 additions & 0 deletions gameblocks/modules/behavior/GridPathPlanner.wrap-neighbors.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { GridPathPlanner } from './GridPathPlanner.js';

const navigation = {
vectors: {
north: { right: 0, forward: 1 },
east: { right: 1, forward: 0 },
south: { right: 0, forward: -1 },
west: { right: -1, forward: 0 },
},
neighborOrder: ['north', 'east', 'south', 'west'],
};

test('wrap neighbors from the origin use torus edges, not clamp', () => {
const planner = new GridPathPlanner({ navigation, columns: 10, rows: 10, wrap: true });
const neighbors = Object.fromEntries(
planner.getNeighbors({ right: 0, forward: 0 }).map((entry) => [entry.direction, entry.cell])
);
assert.deepEqual(neighbors.west, { right: 9, forward: 0 });
assert.deepEqual(neighbors.south, { right: 0, forward: 9 });
assert.deepEqual(neighbors.east, { right: 1, forward: 0 });
});

test('wrap neighbors from far out-of-board cells use modulo, not the far edge', () => {
const planner = new GridPathPlanner({ navigation, columns: 10, rows: 10, wrap: true });
const neighbors = Object.fromEntries(
planner.getNeighbors({ right: -5, forward: 0 }).map((entry) => [entry.direction, entry.cell])
);
// -5 + 1 = -4 → 6 on a period-10 torus. Clamp-to-edge would have produced 9.
assert.deepEqual(neighbors.east, { right: 6, forward: 0 });
assert.deepEqual(neighbors.west, { right: 4, forward: 0 });
});