Make stepper authoritative for sparse motion segments

This commit is contained in:
scamiv
2026-02-28 18:20:33 +01:00
parent 5e0b2f9adb
commit c1936fb289
9 changed files with 322 additions and 449 deletions
+5 -76
View File
@@ -1,67 +1,13 @@
import { describe, expect, it } from "vitest";
import { GameMapImpl } from "../src/core/game/GameMap";
import { densePathToKeypointSegments } from "../src/core/game/MotionPlans";
import { MiniMapTransformer } from "../src/core/pathfinding/transformers/MiniMapTransformer";
function makeMap(width: number, height: number): GameMapImpl {
return new GameMapImpl(width, height, new Uint8Array(width * height), 0);
}
function expandPlanDda(
map: GameMapImpl,
points: Uint32Array,
segmentSteps: Uint32Array,
): number[] {
const out: number[] = [];
if (points.length === 0) return out;
out.push(points[0] >>> 0);
for (let i = 0; i < segmentSteps.length; i++) {
const steps = segmentSteps[i] >>> 0;
const a = points[i] >>> 0;
const b = points[i + 1] >>> 0;
const ax = map.x(a);
const ay = map.y(a);
const bx = map.x(b);
const by = map.y(b);
const dx = bx - ax;
const dy = by - ay;
for (let t = 1; t <= steps; t++) {
out.push(
map.ref(
Math.round(ax + (dx * t) / steps),
Math.round(ay + (dy * t) / steps),
) >>> 0,
);
}
}
return out;
}
describe("densePathToKeypointSegments", () => {
it("expands back to the dense path for axis segments", () => {
const map = makeMap(10, 10);
const dense = [
map.ref(1, 1),
map.ref(2, 1),
map.ref(3, 1),
map.ref(4, 1),
map.ref(4, 2),
map.ref(4, 3),
map.ref(4, 4),
];
const plan = densePathToKeypointSegments(dense);
expect(plan).not.toBeNull();
if (!plan) return;
const expanded = expandPlanDda(map, plan.points, plan.segmentSteps);
expect(expanded).toEqual(dense.map((t) => t >>> 0));
});
});
describe("MiniMapTransformer planSegments compression", () => {
it("preserves endpoints and total steps while merging collinear runs", () => {
describe("MiniMapTransformer", () => {
it("preserves dense path endpoints after upscaling/fixing extremes", () => {
const map = makeMap(10, 10);
const miniMap = makeMap(5, 5);
@@ -77,12 +23,6 @@ describe("MiniMapTransformer planSegments compression", () => {
findPath() {
return miniPath.slice();
},
planSegments() {
return {
points: Uint32Array.from(miniPath),
segmentSteps: Uint32Array.from([1, 1, 1, 1]),
};
},
};
const transformer = new MiniMapTransformer(inner as any, map, miniMap);
@@ -91,19 +31,8 @@ describe("MiniMapTransformer planSegments compression", () => {
const dense = transformer.findPath(from, to);
expect(dense).not.toBeNull();
const plan = transformer.planSegments(from, to);
expect(plan).not.toBeNull();
if (!plan) return;
expect(Array.from(plan.points)).toEqual([
from >>> 0,
map.ref(4, 0) >>> 0,
to >>> 0,
]);
expect(Array.from(plan.segmentSteps)).toEqual([4, 4]);
const totalSteps = Array.from(plan.segmentSteps).reduce((a, b) => a + b, 0);
expect(totalSteps).toBe(8);
if (!dense) return;
expect(dense[0]).toBe(from);
expect(dense[dense.length - 1]).toBe(to);
});
});