deadhead-space-freight-tycoon/packages/sim/test/fuel-share.test.ts

65 lines
2.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { content } from "@deadhead/content";
import { beforeAll, describe, expect, it } from "vitest";
import { formatFuelShares, fuelShares, type FuelShare } from "../balance/fuel-share";
import { checkRoute, fuelPriceAt, legFuel, routeDistance } from "../src/index";
const loc = (id: string) => content.location(id)!;
let rows: FuelShare[];
beforeAll(() => {
rows = fuelShares(content);
});
describe("fuel-to-payout check (CR-018 Step 18.1, decision 0.5.110)", () => {
it("reports every purchasable ship on every route it can fly", () => {
const models = content.shipModels.filter((m) => m.purchasable);
expect(new Set(rows.map((r) => r.modelId))).toEqual(new Set(models.map((m) => m.id)));
for (const row of rows) {
const model = content.shipModel(row.modelId)!;
expect(checkRoute(model, loc(row.originId), loc(row.destinationId), content.config).ok).toBe(
true,
);
expect(row.contracts).toBeGreaterThan(0);
}
// Every Earth–Moon leg is flown by every purchasable ship, and boards always offer it.
for (const model of models) {
expect(
rows.some(
(r) => r.modelId === model.id && r.originId === "earth" && r.destinationId === "moon",
),
).toBe(true);
}
});
it("prices a leg's fuel at the origin and divides by the median fitting payout", () => {
const row = rows.find(
(r) => r.modelId === "courier" && r.originId === "earth" && r.destinationId === "moon",
)!;
const courier = content.shipModel("courier")!;
const fuel =
legFuel(courier, loc("earth"), routeDistance(loc("earth"), loc("moon")), content.config) *
fuelPriceAt(loc("earth"), content.config);
expect(row.fuelCost).toBeCloseTo(fuel, 9);
expect(row.share).toBeCloseTo(row.fuelCost / row.medianPayout, 12);
expect(row.medianPayout).toBeGreaterThan(0);
});
it("keeps fuel at most 25% of the median payout on every route (Step 18.2)", () => {
// One price can't put every row in 15–25% (user decision, CR-018): only the top is gated.
// The Clipper's Mars → Earth was the one exception until boards kept only jobs the
// fleet can complete (CR-019): fitted boards offer it more jobs its 30 t hold takes.
const over = rows
.filter((r) => r.share > 0.25)
.map((r) => `${r.modelId} ${r.originId} → ${r.destinationId}`);
expect(over).toEqual([]);
});
it("reports the share for each ship and route as a table", () => {
const table = formatFuelShares(rows).split("\n");
expect(table).toHaveLength(rows.length + 1);
expect(
table.find((line) => line.startsWith("courier") && line.includes("earth → moon")),
).toMatch(/\d+\.\d%$/);
});
});