import { content } from "@deadhead/content"; import { describe, expect, it } from "vitest"; import { economicDistance, fuelCost, fullTankReach, legFuel, plainDistance, routeDistance, } from "../src/index"; const { config } = content; const courier = content.shipModel("courier")!; const earth = content.location("earth")!; const moon = content.location("moon")!; const { referenceMillionKm: ref, exponent } = config.economicDistance; describe("economic distance (decision 0.5.84)", () => { it("leaves an Earth–Moon length leg unchanged", () => { expect(economicDistance(ref, config)).toBeCloseTo(ref); }); it("grows more slowly than distance past the reference, and keeps order", () => { expect(economicDistance(130, config)).toBeLessThan(130); expect(economicDistance(130, config)).toBeGreaterThan(economicDistance(60, config)); // Doubling the distance multiplies it by 2^exponent. expect(economicDistance(20, config) / economicDistance(10, config)).toBeCloseTo(2 ** exponent); }); it("is the plain distance with an exponent of 1", () => { const linear = { ...config, economicDistance: { referenceMillionKm: ref, exponent: 1 } }; expect(economicDistance(130, linear)).toBeCloseTo(130); }); }); describe("fuel cost", () => { it("costs more Earth→Moon than Moon→Earth for the same ship", () => { const distance = routeDistance(earth, moon); expect(fuelCost(courier, earth, distance, config)).toBeGreaterThan( fuelCost(courier, moon, distance, config), ); }); it("scales with economic distance", () => { expect(fuelCost(courier, earth, 10, config) / fuelCost(courier, earth, 5, config)).toBeCloseTo( 2 ** exponent, ); }); it("matches a hand calculation (Step 15.3: the leg's fuel at the origin's price)", () => { // 20 fu per M km × economic distance of 0.5M km, at 10 cr/fu × Earth's 1.6. const expected = 20 * ref * (0.5 / ref) ** exponent * 10 * 1.6; expect(fuelCost(courier, earth, 0.5, config)).toBeCloseTo(expected); }); }); describe("tanks and reach (decisions 0.5.94, 0.5.95)", () => { it("burns the burn rate × the economic distance of the leg ÷ the origin's range factor", () => { expect(legFuel(courier, earth, 0.5, config)).toBeCloseTo(20 * economicDistance(0.5, config)); expect(legFuel(courier, moon, 0.5, config)).toBeCloseTo( 20 * economicDistance(0.5 / 1.3, config), ); }); it("inverts the economic-distance curve", () => { for (const d of [0.2, 0.384, 5, 201, 792]) { expect(plainDistance(economicDistance(d, config), config)).toBeCloseTo(d, 6); } }); it("reaches exactly as far as a full tank burns, stretched by the origin's factor", () => { for (const origin of content.locations) { for (const ship of content.shipModels) { const reach = fullTankReach(ship, origin, config); expect(legFuel(ship, origin, reach, config), `${ship.id} from ${origin.id}`).toBeCloseTo( ship.tankCapacityFu, 6, ); expect(reach).toBeCloseTo(fullTankReach(ship, earth, config) * origin.launchRangeFactor, 6); } } }); });