feat: add findNearestWalkable method to GameMap

Adds a method that searches outward from a center position in Manhattan
distance rings to find the nearest walkable tile within a given radius.
Returns null if no walkable tile is found. Includes 5 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-07 13:35:00 +00:00
parent 4ff6f14746
commit fa02a6e93e
2 changed files with 68 additions and 0 deletions
+19
View File
@@ -45,6 +45,25 @@ export class GameMap {
});
}
findNearestWalkable(centerX: number, centerY: number, radius: number): Position | null {
if (this.isWalkable(centerX, centerY)) {
return { x: centerX, y: centerY };
}
for (let dist = 1; dist <= radius; dist++) {
for (let dx = -dist; dx <= dist; dx++) {
const dyRange = dist - Math.abs(dx);
for (const dy of [-dyRange, dyRange]) {
const x = centerX + dx;
const y = centerY + dy;
if (this.isWalkable(x, y)) {
return { x, y };
}
}
}
}
return null;
}
getRandomWalkable(): Position {
let x: number, y: number;
do {
+49
View File
@@ -0,0 +1,49 @@
import { describe, it, expect } from 'vitest';
import { GameMap } from '../GameMap.js';
describe('GameMap.findNearestWalkable', () => {
it('returns the exact tile if it is walkable', () => {
const map = new GameMap(10, 10);
const result = map.findNearestWalkable(5, 5, 3);
expect(result).toEqual({ x: 5, y: 5 });
});
it('returns a nearby walkable tile if center is obstacle', () => {
const map = new GameMap(10, 10);
map.setObstacle(5, 5);
const result = map.findNearestWalkable(5, 5, 3);
expect(result).not.toBeNull();
const dx = Math.abs(result!.x - 5);
const dy = Math.abs(result!.y - 5);
expect(dx + dy).toBeLessThanOrEqual(3);
expect(map.isWalkable(result!.x, result!.y)).toBe(true);
});
it('returns null if no walkable tile within radius', () => {
const map = new GameMap(5, 5);
for (let x = 1; x <= 3; x++) {
for (let y = 1; y <= 3; y++) {
map.setObstacle(x, y);
}
}
const result = map.findNearestWalkable(2, 2, 1);
expect(result).toBeNull();
});
it('returns null for out-of-bounds center', () => {
const map = new GameMap(10, 10);
const result = map.findNearestWalkable(-5, -5, 1);
expect(result).toBeNull();
});
it('clamps search to map boundaries', () => {
const map = new GameMap(10, 10);
map.setObstacle(0, 0);
const result = map.findNearestWalkable(0, 0, 3);
expect(result).not.toBeNull();
expect(result!.x).toBeGreaterThanOrEqual(0);
expect(result!.y).toBeGreaterThanOrEqual(0);
expect(result!.x).toBeLessThan(10);
expect(result!.y).toBeLessThan(10);
});
});