import { describe, it, expect } from 'vitest';
import { findPath, findPathToNeighbor, type Grid } from '../pathfinding';
function makeGrid(width: number, height: number, walls: string[] = []): Grid {
const wallSet = new Set(walls);
return {
width,
height,
isWalkable: (x, y) => !wallSet.has(`${x},${y}`)
};
}
describe('A*', () => {
it('прямой путь по пустой сетке', () => {
const path = findPath(makeGrid(10, 10), { x: 0, y: 0 }, { x: 3, y: 0 });
expect(path).toEqual([
{ x: 1, y: 0 },
{ x: 2, y: 0 },
{ x: 3, y: 0 }
]);
});
it('обходит стену', () => {
const grid = makeGrid(5, 5, ['1,0', '1,1', '1,2']);
const path = findPath(grid, { x: 0, y: 0 }, { x: 2, y: 0 });
expect(path).not.toBeNull();
expect(path!.some((p) => p.x === 1 && (p.y === 0 || p.y === 1 || p.y === 2))).toBe(false);
expect(path![path!.length - 1]).toEqual({ x: 2, y: 0 });
});
it('цель заблокирована — null', () => {
const grid = makeGrid(5, 5, ['2,2']);
expect(findPath(grid, { x: 0, y: 0 }, { x: 2, y: 2 })).toBeNull();
});
it('цель вне сетки — null', () => {
const grid = makeGrid(5, 5);
expect(findPath(grid, { x: 0, y: 0 }, { x: 9, y: 9 })).toBeNull();
});
it('старт == цель — пустой путь', () => {
const grid = makeGrid(5, 5);
expect(findPath(grid, { x: 2, y: 2 }, { x: 2, y: 2 })).toEqual([]);
});
it('диагональ без среза углов', () => {
// Стена (1,0) срезает угол диагонали (0,0)->(1,1) — она запрещена,
// путь идёт в обход через (0,1).
const grid = makeGrid(5, 5, ['1,0']);
const path = findPath(grid, { x: 0, y: 0 }, { x: 1, y: 1 }, true);
expect(path).not.toBeNull();
expect(path![0]).toEqual({ x: 0, y: 1 });
});
it('угол срезан со всех сторон — пути нет', () => {
// Из (0,0) заблокированы оба ортогональных соседа: без среза углов
// ни шага, ни диагонали сделать нельзя.
const grid = makeGrid(5, 5, ['1,0', '0,1']);
expect(findPath(grid, { x: 0, y: 0 }, { x: 2, y: 2 }, true)).toBeNull();
});
it('диагональ разрешена, когда соседи свободны', () => {
const grid = makeGrid(5, 5);
const path = findPath(grid, { x: 0, y: 0 }, { x: 1, y: 1 }, true);
expect(path).toEqual([{ x: 1, y: 1 }]);
});
});
describe('findPathToNeighbor', () => {
it('цель проходима — всё равно останавливаемся рядом', () => {
const path = findPathToNeighbor(makeGrid(10, 10), { x: 0, y: 0 }, { x: 2, y: 0 });
const end = path!.at(-1)!;
expect(Math.max(Math.abs(end.x - 2), Math.abs(end.y - 0))).toBe(1);
});
it('цель занята — путь к соседней клетке', () => {
const grid = makeGrid(10, 10, ['5,5']);
const path = findPathToNeighbor(grid, { x: 0, y: 5 }, { x: 5, y: 5 });
expect(path).not.toBeNull();
const end = path!.at(-1)!;
expect(Math.max(Math.abs(end.x - 5), Math.abs(end.y - 5))).toBe(1);
});
it('цель окружена — путь не найден', () => {
const grid = makeGrid(5, 5, [
'1,1', '2,1', '3,1',
'1,2', '2,2', '3,2',
'1,3', '2,3', '3,3'
]);
expect(findPathToNeighbor(grid, { x: 0, y: 4 }, { x: 2, y: 2 })).toBeNull();
});
});