/// /** * Prints a balance run for both first-purchase policies (plan Step 12.1), then * the fuel-to-payout check (CR-018 Step 18.1): * pnpm --filter @deadhead/sim balance [worldSeed] [hours] */ import { MS_PER_HOUR } from "../src/index"; import { content } from "@deadhead/content"; import { formatFuelShares, fuelShares } from "./fuel-share"; import { simulate, type PurchasePolicy } from "./simulate"; const worldSeed = Number(process.argv[2] ?? 12345); const hours = Number(process.argv[3] ?? 8); for (const policy of ["lighter-first", "freighter-first"] as PurchasePolicy[]) { const result = simulate({ worldSeed, policy, durationMs: hours * MS_PER_HOUR }); console.log(`\n=== ${policy} (seed ${worldSeed}) ===`); console.log("milestones (real minutes):", result.milestones); console.log( `tutorial runs ${result.tutorialRuns}, contracts ${result.contractsDelivered}, ` + `veteran contracts in first 2 h ${result.veteranContractsFirstSession}, purchases ${result.purchases.join(", ")}`, ); console.log("violations:", result.violations.length); for (const v of result.violations.slice(0, 10)) console.log(` ${v.minute} min ${v.rule} ${v.detail}`); console.log("minute credits loan ships pilot levels"); for (const s of result.samples.filter((_, i) => i % 3 === 0)) { console.log( `${String(s.minute).padStart(6)} ${String(s.credits).padStart(7)} ${String(s.loanBalance).padStart(6)} ${s.ships} ${s.pilotLevels.join(" ")}`, ); } } console.log("\n=== fuel share of median payout, per ship and route (CR-018) ==="); console.log(formatFuelShares(fuelShares(content))); // The away scenario (CR-021 Step 21.8): 3 hours of play, then 8 hours either way. const window = (mode: "active" | "away") => simulate({ worldSeed, policy: "lighter-first", durationMs: 12 * MS_PER_HOUR, scenario: { atMinute: 180, minutes: 8 * 60, mode }, }); const active = window("active"); const away = window("away"); console.log("\n=== away scenario: 8 h with Independent pilots vs active play (CR-021) ==="); console.log( `active ${active.scenarioEarnings} cr, away ${away.scenarioEarnings} cr, ` + `ratio ${((away.scenarioEarnings! / active.scenarioEarnings!) * 100).toFixed(0)}% (target 40–80%), ` + `violations ${away.violations.length}`, );