77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
import { content } from "@deadhead/content";
|
|
import { describe, expect, it } from "vitest";
|
|
import { checkRoute } from "../src/index";
|
|
|
|
/**
|
|
* CR-015 §4: reach for base ships on the fixed map, a plain yes or no per leg
|
|
* (decision 0.5.81 as amended). Replaces CR-012's date-sampled table.
|
|
*/
|
|
const NAMES: Record<string, string> = {
|
|
earth: "Earth",
|
|
moon: "Moon",
|
|
mars: "Mars",
|
|
"ceres-station": "Ceres",
|
|
"jupiter-cloud-platform": "Jupiter",
|
|
};
|
|
const ids = Object.keys(NAMES);
|
|
|
|
function reaches(modelId: string, fromId: string, toId: string): boolean {
|
|
const ship = content.shipModel(modelId)!;
|
|
return checkRoute(ship, content.location(fromId)!, content.location(toId)!).ok;
|
|
}
|
|
|
|
/** [model, from, to] for every leg the table says yes or no to. */
|
|
type Leg = [string, string, string];
|
|
const both = (model: string, a: string, b: string): Leg[] => [
|
|
[model, a, b],
|
|
[model, b, a],
|
|
];
|
|
const toJupiterFromAnywhere = (model: string): Leg[] =>
|
|
ids
|
|
.filter((id) => id !== "jupiter-cloud-platform")
|
|
.map((from) => [model, from, "jupiter-cloud-platform"]);
|
|
|
|
const yes: Leg[] = [
|
|
...both("courier", "earth", "moon"),
|
|
...both("lighter", "earth", "moon"),
|
|
...both("clipper", "earth", "moon"),
|
|
...both("clipper", "earth", "mars"),
|
|
["clipper", "moon", "mars"],
|
|
["clipper", "mars", "ceres-station"],
|
|
// The Freighter does everything the Clipper does, plus Earth↔Ceres and Ceres↔Jupiter.
|
|
...both("freighter", "earth", "moon"),
|
|
...both("freighter", "earth", "mars"),
|
|
["freighter", "moon", "mars"],
|
|
["freighter", "mars", "ceres-station"],
|
|
...both("freighter", "earth", "ceres-station"),
|
|
...both("freighter", "ceres-station", "jupiter-cloud-platform"),
|
|
...ids.flatMap((from) =>
|
|
ids.filter((to) => to !== from).map((to): Leg => ["bulk-hauler", from, to]),
|
|
),
|
|
];
|
|
|
|
const no: Leg[] = [
|
|
["courier", "earth", "mars"],
|
|
["courier", "moon", "mars"],
|
|
["lighter", "earth", "mars"],
|
|
["lighter", "moon", "mars"],
|
|
["clipper", "earth", "ceres-station"],
|
|
["clipper", "moon", "ceres-station"],
|
|
...toJupiterFromAnywhere("clipper"),
|
|
["freighter", "earth", "jupiter-cloud-platform"],
|
|
["freighter", "moon", "jupiter-cloud-platform"],
|
|
["freighter", "mars", "jupiter-cloud-platform"],
|
|
];
|
|
|
|
const label = ([model, from, to]: Leg) => `${model} ${NAMES[from]}→${NAMES[to]}`;
|
|
|
|
describe("reach table (CR-015 §4)", () => {
|
|
it.each(yes.map((leg) => [label(leg), leg] as const))("yes: %s", (_name, [m, from, to]) => {
|
|
expect(reaches(m, from, to)).toBe(true);
|
|
});
|
|
|
|
it.each(no.map((leg) => [label(leg), leg] as const))("no: %s", (_name, [m, from, to]) => {
|
|
expect(reaches(m, from, to)).toBe(false);
|
|
});
|
|
});
|