mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-28 14:27:54 +00:00
Pathfinding Refactor
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { ComponentCheckTransformer } from "../../../../src/core/pathfinding/transformers/ComponentCheckTransformer";
|
||||
import { PathFinder } from "../../../../src/core/pathfinding/types";
|
||||
|
||||
describe("ComponentCheckTransformer", () => {
|
||||
// Mock PathFinder that records calls and returns a simple path
|
||||
function createMockPathFinder(): PathFinder<number> & {
|
||||
calls: Array<{ from: number | number[]; to: number }>;
|
||||
} {
|
||||
const calls: Array<{ from: number | number[]; to: number }> = [];
|
||||
|
||||
return {
|
||||
calls,
|
||||
findPath(from: number | number[], to: number): number[] | null {
|
||||
calls.push({ from, to });
|
||||
const start = Array.isArray(from) ? from[0] : from;
|
||||
return [start, to];
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Component function: even numbers → component 0, odd → component 1
|
||||
const evenOddComponent = (t: number) => t % 2;
|
||||
|
||||
describe("findPath", () => {
|
||||
it("delegates when source and destination in same component", () => {
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
const result = transformer.findPath(2, 4); // both even → component 0
|
||||
|
||||
expect(result).toEqual([2, 4]);
|
||||
expect(inner.calls).toHaveLength(1);
|
||||
expect(inner.calls[0]).toEqual({ from: 2, to: 4 });
|
||||
});
|
||||
|
||||
it("returns null when source and destination in different components", () => {
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
const result = transformer.findPath(2, 3); // even → odd
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(inner.calls).toHaveLength(0); // inner not called
|
||||
});
|
||||
|
||||
it("filters multiple sources to only valid ones", () => {
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
// Sources: 1, 2, 3, 4 → odd, even, odd, even
|
||||
// Destination: 4 → even
|
||||
// Valid sources: 2, 4
|
||||
const result = transformer.findPath([1, 2, 3, 4], 4);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(inner.calls).toHaveLength(1);
|
||||
expect(inner.calls[0].from).toEqual([2, 4]); // filtered to valid
|
||||
expect(inner.calls[0].to).toBe(4);
|
||||
});
|
||||
|
||||
it("returns null when no source in same component", () => {
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
// All sources odd, destination even
|
||||
const result = transformer.findPath([1, 3, 5], 4);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(inner.calls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("unwraps single valid source from array", () => {
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
// Only one source matches
|
||||
const result = transformer.findPath([1, 2, 3], 4);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(inner.calls).toHaveLength(1);
|
||||
expect(inner.calls[0].from).toBe(2);
|
||||
});
|
||||
|
||||
it("handles single source (not array)", () => {
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
const result = transformer.findPath(4, 6);
|
||||
|
||||
expect(result).toEqual([4, 6]);
|
||||
expect(inner.calls[0].from).toBe(4);
|
||||
});
|
||||
|
||||
it("propagates null from inner pathfinder", () => {
|
||||
const inner: PathFinder<number> = {
|
||||
findPath: () => null,
|
||||
};
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
const result = transformer.findPath(2, 4);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("propagates path from inner pathfinder", () => {
|
||||
const inner: PathFinder<number> = {
|
||||
findPath: () => [10, 20, 30, 40],
|
||||
};
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
const result = transformer.findPath(2, 4);
|
||||
|
||||
expect(result).toEqual([10, 20, 30, 40]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("edge cases", () => {
|
||||
it("handles empty source array", () => {
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ComponentCheckTransformer(
|
||||
inner,
|
||||
evenOddComponent,
|
||||
);
|
||||
|
||||
const result = transformer.findPath([], 4);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(inner.calls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("works with custom component function", () => {
|
||||
const inner = createMockPathFinder();
|
||||
// Component by tens digit: 10-19 → 1, 20-29 → 2, etc.
|
||||
const tensComponent = (t: number) => Math.floor(t / 10);
|
||||
const transformer = new ComponentCheckTransformer(inner, tensComponent);
|
||||
|
||||
// Same component
|
||||
expect(transformer.findPath(15, 18)).not.toBeNull();
|
||||
|
||||
// Different component
|
||||
expect(transformer.findPath(15, 25)).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { GameMapImpl } from "../../../../src/core/game/GameMap";
|
||||
import { MiniMapTransformer } from "../../../../src/core/pathfinding/transformers/MiniMapTransformer";
|
||||
import { PathFinder } from "../../../../src/core/pathfinding/types";
|
||||
|
||||
describe("MiniMapTransformer", () => {
|
||||
// Create test maps: main map is 10x10, minimap is 5x5 (2x downscale)
|
||||
function createTestMaps() {
|
||||
const W = 0x20; // Water
|
||||
const mainTerrain = new Uint8Array(100).fill(W); // 10x10 all water
|
||||
const miniTerrain = new Uint8Array(25).fill(W); // 5x5 all water
|
||||
|
||||
const map = new GameMapImpl(10, 10, mainTerrain, 0);
|
||||
const miniMap = new GameMapImpl(5, 5, miniTerrain, 0);
|
||||
|
||||
return { map, miniMap };
|
||||
}
|
||||
|
||||
function createMockPathFinder(): PathFinder<number> & {
|
||||
calls: Array<{ from: number | number[]; to: number }>;
|
||||
returnPath: number[] | null | undefined;
|
||||
} {
|
||||
const mock = {
|
||||
calls: [] as Array<{ from: number | number[]; to: number }>,
|
||||
returnPath: undefined as number[] | null | undefined,
|
||||
findPath(from: number | number[], to: number): number[] | null {
|
||||
mock.calls.push({ from, to });
|
||||
if (mock.returnPath !== undefined) return mock.returnPath;
|
||||
const start = Array.isArray(from) ? from[0] : from;
|
||||
return [start, to];
|
||||
},
|
||||
};
|
||||
return mock;
|
||||
}
|
||||
|
||||
describe("findPath", () => {
|
||||
it("converts coordinates to minimap scale", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
const from = map.ref(4, 6);
|
||||
const to = map.ref(8, 2);
|
||||
|
||||
const miniFrom = miniMap.ref(2, 3);
|
||||
const miniTo = miniMap.ref(4, 1);
|
||||
inner.returnPath = [miniFrom, miniTo];
|
||||
|
||||
transformer.findPath(from, to);
|
||||
|
||||
expect(inner.calls).toHaveLength(1);
|
||||
expect(inner.calls[0].from).toBe(miniFrom);
|
||||
expect(inner.calls[0].to).toBe(miniTo);
|
||||
});
|
||||
|
||||
it("upscales minimap path back to full resolution", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
const from = map.ref(0, 0);
|
||||
const to = map.ref(8, 0);
|
||||
|
||||
// Minimap path: (0,0) → (4,0) - straight horizontal
|
||||
inner.returnPath = [
|
||||
miniMap.ref(0, 0),
|
||||
miniMap.ref(1, 0),
|
||||
miniMap.ref(2, 0),
|
||||
miniMap.ref(3, 0),
|
||||
miniMap.ref(4, 0),
|
||||
];
|
||||
|
||||
const result = transformer.findPath(from, to);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result![0]).toBe(from);
|
||||
expect(result![result!.length - 1]).toBe(to);
|
||||
});
|
||||
|
||||
it("returns null when inner returns null", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
inner.returnPath = null;
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
const result = transformer.findPath(map.ref(0, 0), map.ref(8, 8));
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when inner returns empty path", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
inner.returnPath = [];
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
const result = transformer.findPath(map.ref(0, 0), map.ref(8, 8));
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("handles multiple sources", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
const from1 = map.ref(0, 0);
|
||||
const from2 = map.ref(2, 0);
|
||||
const to = map.ref(8, 0);
|
||||
|
||||
inner.returnPath = [miniMap.ref(0, 0), miniMap.ref(4, 0)];
|
||||
|
||||
const result = transformer.findPath([from1, from2], to);
|
||||
|
||||
expect(inner.calls).toHaveLength(1);
|
||||
expect(Array.isArray(inner.calls[0].from)).toBe(true);
|
||||
expect(result).not.toBeNull();
|
||||
});
|
||||
|
||||
it("fixes path extremes to match original from/to", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
// From odd coords - won't exactly map to minimap
|
||||
const from = map.ref(1, 1);
|
||||
const to = map.ref(9, 9);
|
||||
|
||||
inner.returnPath = [miniMap.ref(0, 0), miniMap.ref(4, 4)];
|
||||
|
||||
const result = transformer.findPath(from, to);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result![0]).toBe(from);
|
||||
expect(result![result!.length - 1]).toBe(to);
|
||||
});
|
||||
});
|
||||
|
||||
describe("coordinate mapping", () => {
|
||||
it("maps main coords (0,0) to mini coords (0,0)", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
inner.returnPath = [miniMap.ref(0, 0)];
|
||||
|
||||
transformer.findPath(map.ref(0, 0), map.ref(0, 0));
|
||||
|
||||
expect(inner.calls[0].from).toBe(miniMap.ref(0, 0));
|
||||
expect(inner.calls[0].to).toBe(miniMap.ref(0, 0));
|
||||
});
|
||||
|
||||
it("maps main coords (1,1) to mini coords (0,0) (floor division)", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
inner.returnPath = [miniMap.ref(0, 0)];
|
||||
|
||||
transformer.findPath(map.ref(1, 1), map.ref(1, 1));
|
||||
|
||||
expect(inner.calls[0].from).toBe(miniMap.ref(0, 0));
|
||||
expect(inner.calls[0].to).toBe(miniMap.ref(0, 0));
|
||||
});
|
||||
|
||||
it("maps main coords (2,2) to mini coords (1,1)", () => {
|
||||
const { map, miniMap } = createTestMaps();
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new MiniMapTransformer(inner, map, miniMap);
|
||||
|
||||
inner.returnPath = [miniMap.ref(1, 1)];
|
||||
|
||||
transformer.findPath(map.ref(2, 2), map.ref(2, 2));
|
||||
|
||||
expect(inner.calls[0].from).toBe(miniMap.ref(1, 1));
|
||||
expect(inner.calls[0].to).toBe(miniMap.ref(1, 1));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,245 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { ShoreCoercingTransformer } from "../../../../src/core/pathfinding/transformers/ShoreCoercingTransformer";
|
||||
import { PathFinder } from "../../../../src/core/pathfinding/types";
|
||||
import { createGameMap, createIslandMap, L, W } from "../_fixtures";
|
||||
|
||||
describe("ShoreCoercingTransformer", () => {
|
||||
// Mock PathFinder that records calls and returns configurable path
|
||||
function createMockPathFinder(): PathFinder<number> & {
|
||||
calls: Array<{ from: number | number[]; to: number }>;
|
||||
returnPath: number[] | null | undefined;
|
||||
} {
|
||||
const mock = {
|
||||
calls: [] as Array<{ from: number | number[]; to: number }>,
|
||||
returnPath: undefined as number[] | null | undefined,
|
||||
findPath(from: number | number[], to: number): number[] | null {
|
||||
mock.calls.push({ from, to });
|
||||
if (mock.returnPath !== undefined) return mock.returnPath;
|
||||
const start = Array.isArray(from) ? from[0] : from;
|
||||
return [start, to];
|
||||
},
|
||||
};
|
||||
return mock;
|
||||
}
|
||||
|
||||
describe("findPath", () => {
|
||||
it("passes water tiles unchanged", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
const water1 = map.ref(0, 0);
|
||||
const water2 = map.ref(4, 0);
|
||||
inner.returnPath = [water1, water2];
|
||||
|
||||
const result = transformer.findPath(water1, water2);
|
||||
|
||||
expect(result).toEqual([water1, water2]);
|
||||
expect(inner.calls).toHaveLength(1);
|
||||
expect(inner.calls[0].from).toBe(water1);
|
||||
expect(inner.calls[0].to).toBe(water2);
|
||||
});
|
||||
|
||||
it("coerces shore start to water and prepends original", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
const shore = map.ref(1, 1);
|
||||
const water = map.ref(4, 4);
|
||||
const shoreWaterNeighbor = map.ref(1, 0);
|
||||
|
||||
const result = transformer.findPath(shore, water);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result![0]).toBe(shore);
|
||||
expect(result![1]).toBe(shoreWaterNeighbor);
|
||||
});
|
||||
|
||||
it("coerces shore destination to water and appends original", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
const water = map.ref(0, 0);
|
||||
const shore = map.ref(1, 1);
|
||||
const shoreWaterNeighbor = map.ref(1, 0);
|
||||
|
||||
const result = transformer.findPath(water, shore);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result![0]).toBe(water);
|
||||
expect(result![result!.length - 2]).toBe(shoreWaterNeighbor);
|
||||
expect(result![result!.length - 1]).toBe(shore);
|
||||
});
|
||||
|
||||
it("coerces both shore start and destination", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
const shore1 = map.ref(1, 1);
|
||||
const shore1WaterNeighbor = map.ref(1, 0);
|
||||
const shore2 = map.ref(3, 3);
|
||||
const shore2WaterNeighbor = map.ref(3, 4);
|
||||
|
||||
const result = transformer.findPath(shore1, shore2);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result![0]).toBe(shore1);
|
||||
expect(result![1]).toBe(shore1WaterNeighbor);
|
||||
expect(result![result!.length - 2]).toBe(shore2WaterNeighbor);
|
||||
expect(result![result!.length - 1]).toBe(shore2);
|
||||
});
|
||||
|
||||
it("returns null when source has no water neighbor", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
// Center land tile (2,2) has no water neighbors
|
||||
const land = map.ref(2, 2);
|
||||
const water = map.ref(0, 0);
|
||||
|
||||
const result = transformer.findPath(land, water);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(inner.calls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns null when destination has no water neighbor", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
// Center land tile (2,2) has no water neighbors
|
||||
const land = map.ref(2, 2);
|
||||
const water = map.ref(0, 0);
|
||||
|
||||
const result = transformer.findPath(water, land);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(inner.calls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns null when inner pathfinder returns null", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
inner.returnPath = null;
|
||||
const result = transformer.findPath(map.ref(0, 0), map.ref(4, 4));
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when inner pathfinder returns empty path", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
inner.returnPath = [];
|
||||
const result = transformer.findPath(map.ref(0, 0), map.ref(4, 4));
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("handles multiple sources, filters invalid ones", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
const waterSrc = map.ref(0, 0);
|
||||
const shoreSrc = map.ref(1, 1);
|
||||
const landSrc = map.ref(2, 2);
|
||||
const waterDest = map.ref(4, 4);
|
||||
|
||||
inner.returnPath = [waterSrc, waterDest];
|
||||
|
||||
const result = transformer.findPath(
|
||||
[waterSrc, shoreSrc, landSrc],
|
||||
waterDest,
|
||||
);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(inner.calls).toHaveLength(1);
|
||||
|
||||
const fromArg = inner.calls[0].from;
|
||||
expect(Array.isArray(fromArg)).toBe(true);
|
||||
expect((fromArg as number[]).length).toBe(2);
|
||||
});
|
||||
|
||||
it("returns null when all sources are invalid", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
const land = map.ref(2, 2);
|
||||
|
||||
const result = transformer.findPath([land], map.ref(0, 0));
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(inner.calls).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("determinism", () => {
|
||||
it("shore with multiple water neighbors selects consistently", () => {
|
||||
// prettier-ignore
|
||||
const map = createGameMap({
|
||||
width: 5, height: 5, grid: [
|
||||
L, L, W, W, W,
|
||||
L, L, W, W, W,
|
||||
L, L, W, L, L,
|
||||
W, W, W, L, L,
|
||||
W, W, W, L, L,
|
||||
],
|
||||
});
|
||||
|
||||
const shoreWithMultipleWater = map.ref(1, 2);
|
||||
const expectedWaterNeighbor = map.ref(1, 3);
|
||||
|
||||
const inner1 = createMockPathFinder();
|
||||
const inner2 = createMockPathFinder();
|
||||
const transformer1 = new ShoreCoercingTransformer(inner1, map);
|
||||
const transformer2 = new ShoreCoercingTransformer(inner2, map);
|
||||
|
||||
const waterDest = map.ref(2, 4);
|
||||
|
||||
transformer1.findPath(shoreWithMultipleWater, waterDest);
|
||||
transformer2.findPath(shoreWithMultipleWater, waterDest);
|
||||
|
||||
// Both select the same water neighbor: (1,3)
|
||||
expect(inner1.calls[0].from).toBe(expectedWaterNeighbor);
|
||||
expect(inner2.calls[0].from).toBe(expectedWaterNeighbor);
|
||||
});
|
||||
|
||||
it("corner shore with water neighbors works correctly", () => {
|
||||
const mapData = createIslandMap();
|
||||
const map = createGameMap(mapData);
|
||||
const inner = createMockPathFinder();
|
||||
const transformer = new ShoreCoercingTransformer(inner, map);
|
||||
|
||||
const cornerShore = map.ref(1, 1);
|
||||
const waterNeighbor = map.ref(1, 0);
|
||||
const waterDest = map.ref(4, 4);
|
||||
|
||||
inner.returnPath = [waterNeighbor, waterDest];
|
||||
|
||||
const result = transformer.findPath(cornerShore, waterDest);
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result).toEqual([cornerShore, waterNeighbor, waterDest]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user