Add crosspoll_state table to persist per-island generation counters across evolver restarts. Load state on startup and save after each cross-pollination check. Add persistence pattern and translation structure tests. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
71 lines
1.9 KiB
JavaScript
71 lines
1.9 KiB
JavaScript
/**
|
|
* Grid utility functions for AI Code Battle.
|
|
*
|
|
* Provides toroidal distance calculations, neighbor enumeration,
|
|
* and BFS pathfinding on a wrapping grid.
|
|
*/
|
|
|
|
function toroidalManhattan(r1, c1, r2, c2, cols, rows) {
|
|
const dr = Math.min(Math.abs(r1 - r2), rows - Math.abs(r1 - r2));
|
|
const dc = Math.min(Math.abs(c1 - c2), cols - Math.abs(c1 - c2));
|
|
return dr + dc;
|
|
}
|
|
|
|
function toroidalChebyshev(r1, c1, r2, c2, cols, rows) {
|
|
const dr = Math.min(Math.abs(r1 - r2), rows - Math.abs(r1 - r2));
|
|
const dc = Math.min(Math.abs(c1 - c2), cols - Math.abs(c1 - c2));
|
|
return Math.max(dr, dc);
|
|
}
|
|
|
|
function neighbors(row, col, rows, cols) {
|
|
const offsets = [
|
|
[-1, -1], [-1, 0], [-1, 1],
|
|
[0, -1], [0, 1],
|
|
[1, -1], [1, 0], [1, 1],
|
|
];
|
|
return offsets.map(([dr, dc]) => [
|
|
(row + dr + rows) % rows,
|
|
(col + dc + cols) % cols,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* BFS pathfinding on a toroidal grid.
|
|
*
|
|
* @param {[number,number]} start - [row, col]
|
|
* @param {[number,number]} goal - [row, col]
|
|
* @param {function(number,number): boolean} passable - returns true if walkable
|
|
* @param {number} rows
|
|
* @param {number} cols
|
|
* @returns {[number,number][]|null} path from start to goal (excl. start), or null
|
|
*/
|
|
function bfs(start, goal, passable, rows, cols) {
|
|
const [sr, sc] = start;
|
|
const [gr, gc] = goal;
|
|
if (sr === gr && sc === gc) return [];
|
|
|
|
const key = (r, c) => `${r},${c}`;
|
|
const visited = new Set([key(sr, sc)]);
|
|
const queue = [{ r: sr, c: sc, path: [] }];
|
|
|
|
while (queue.length > 0) {
|
|
const { r, c, path } = queue.shift();
|
|
for (const [nr, nc] of neighbors(r, c, rows, cols)) {
|
|
const newPath = [...path, [nr, nc]];
|
|
if (nr === gr && nc === gc) return newPath;
|
|
const k = key(nr, nc);
|
|
if (!visited.has(k) && passable(nr, nc)) {
|
|
visited.add(k);
|
|
queue.push({ r: nr, c: nc, path: newPath });
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
module.exports = {
|
|
toroidalManhattan,
|
|
toroidalChebyshev,
|
|
neighbors,
|
|
bfs,
|
|
};
|