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:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user