60 lines
2.5 KiB
TypeScript
60 lines
2.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { hexSpiral, separateShips, shipRotation, type FlightLayout } from "../src/map/layout";
|
|
import { mapStyle } from "../src/map/style";
|
|
|
|
const deg = (radians: number) => (radians * 180) / Math.PI;
|
|
|
|
describe("ships in flight (Step 10C.8)", () => {
|
|
it("turns the up-pointing art to face the direction of travel", () => {
|
|
expect(deg(shipRotation({ x: 0, y: 0 }, { x: 10, y: 0 }))).toBeCloseTo(90);
|
|
expect(deg(shipRotation({ x: 0, y: 0 }, { x: 0, y: 10 }))).toBeCloseTo(180);
|
|
expect(deg(shipRotation({ x: 0, y: 10 }, { x: 0, y: 0 }))).toBeCloseTo(0);
|
|
expect(deg(shipRotation({ x: 10, y: 0 }, { x: 0, y: 0 }))).toBeCloseTo(270); // = -90°
|
|
});
|
|
|
|
const flight = (dispatchId: string, x = 100, y = 100): FlightLayout => ({
|
|
dispatchId,
|
|
from: { x: 0, y: 100 },
|
|
to: { x: 200, y: 100 },
|
|
center: { x, y },
|
|
rotation: Math.PI / 2,
|
|
size: 24,
|
|
tap: 44,
|
|
});
|
|
|
|
it("spreads three ships at the same spot apart, at least a tap target apart", () => {
|
|
const spread = separateShips([flight("a"), flight("b"), flight("c")]);
|
|
const points = spread.map((f) => f.center);
|
|
for (let i = 0; i < points.length; i++) {
|
|
for (let j = i + 1; j < points.length; j++) {
|
|
const d = Math.hypot(points[i]!.x - points[j]!.x, points[i]!.y - points[j]!.y);
|
|
expect(d).toBeGreaterThanOrEqual(mapStyle.minTapPx);
|
|
}
|
|
}
|
|
// Perpendicular to the (horizontal) route, centred on where they were.
|
|
expect(points.map((p) => p.x)).toEqual([100, 100, 100]);
|
|
expect(points.map((p) => p.y).reduce((a, b) => a + b) / 3).toBeCloseTo(100);
|
|
});
|
|
|
|
it("leaves ships that are already apart where they are", () => {
|
|
const apart = [flight("a", 20), flight("b", 180)];
|
|
expect(separateShips(apart)).toEqual(apart);
|
|
});
|
|
|
|
it("packs a crowd of ten compactly, every pair a tap target apart", () => {
|
|
const crowd = Array.from({ length: 10 }, (_, i) => flight(`s${i}`));
|
|
const points = separateShips(crowd).map((f) => f.center);
|
|
for (let i = 0; i < points.length; i++) {
|
|
for (let j = i + 1; j < points.length; j++) {
|
|
const d = Math.hypot(points[i]!.x - points[j]!.x, points[i]!.y - points[j]!.y);
|
|
expect(d).toBeGreaterThanOrEqual(mapStyle.minTapPx - 1e-9);
|
|
}
|
|
// Within two hex rings of where they were.
|
|
expect(Math.hypot(points[i]!.x - 100, points[i]!.y - 100)).toBeLessThanOrEqual(
|
|
2 * mapStyle.shipSeparationPx + 1e-9,
|
|
);
|
|
}
|
|
expect(hexSpiral(19, 10)).toHaveLength(19);
|
|
});
|
|
});
|