82 lines
3.0 KiB
TypeScript
82 lines
3.0 KiB
TypeScript
import { content } from "@deadhead/content";
|
||
import { describe, expect, it } from "vitest";
|
||
import {
|
||
economicDistance,
|
||
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("leg fuel", () => {
|
||
it("burns more Earth→Moon than Moon→Earth for the same ship", () => {
|
||
const distance = routeDistance(earth, moon);
|
||
expect(legFuel(courier, earth, distance, config)).toBeGreaterThan(
|
||
legFuel(courier, moon, distance, config),
|
||
);
|
||
});
|
||
|
||
it("scales with economic distance", () => {
|
||
expect(legFuel(courier, earth, 10, config) / legFuel(courier, earth, 5, config)).toBeCloseTo(
|
||
2 ** exponent,
|
||
);
|
||
});
|
||
|
||
it("matches a hand calculation", () => {
|
||
// 20 fu per M km × economic distance of 0.5M km.
|
||
expect(legFuel(courier, earth, 0.5, config)).toBeCloseTo(20 * ref * (0.5 / ref) ** exponent);
|
||
});
|
||
});
|
||
|
||
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);
|
||
}
|
||
}
|
||
});
|
||
});
|