Step 16.3: content tuning: reach
CI / check (push) Has been cancelled
Details
CI / check (push) Has been cancelled
Details
Every cell of the CR-015 reach table and the CR-016 additions holds with the existing tanks, so no content changes: the step adds one test per new cell, the Bulk Hauler's 900M km minimum, and the Courier's Jupiter-system loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
026947ebe9
commit
d626989779
|
|
@ -1512,3 +1512,7 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md`
|
||||||
- **Each new place's Standard good came with the locations**, ahead of 16.2: the board generator refuses a place that makes nothing Standard. The rest of the goods changes stay in 16.2.
|
- **Each new place's Standard good came with the locations**, ahead of 16.2: the board generator refuses a place that makes nothing Standard. The rest of the goods changes stay in 16.2.
|
||||||
- **First Market purchase target widened to 45–95 min** (user decision). With Venus as a second first-contact destination, the median moved from 64 to ~92 min. Purchases happen at the Clipper's long landings, so the median jumps between about 49, 64 and 92 min with small content changes; no tank-share, Lighter-price or first-contact-pay change landed it reliably inside 75.
|
- **First Market purchase target widened to 45–95 min** (user decision). With Venus as a second first-contact destination, the median moved from 64 to ~92 min. Purchases happen at the Clipper's long landings, so the median jumps between about 49, 64 and 92 min with small content changes; no tank-share, Lighter-price or first-contact-pay change landed it reliably inside 75.
|
||||||
- **CR-007's class-mix regression is measured on its original five places**: new destinations change the mix legitimately (and so do first contacts to undiscovered places), so the baseline is compared against the content it was taken from.
|
- **CR-007's class-mix regression is measured on its original five places**: new destinations change the mix legitimately (and so do first contacts to undiscovered places), so the baseline is compared against the content it was taken from.
|
||||||
|
|
||||||
|
## Step 16.3
|
||||||
|
|
||||||
|
- **No content changed**: the Phase 15 tank sizes already satisfy CR-016 §3 with margins (the closest call is a Freighter from Mars to Io, ≈ 529M km of reach for ≈ 592). The step adds the tests only.
|
||||||
|
|
|
||||||
|
|
@ -395,7 +395,7 @@ Spec: `memory-bank/change-requests/CR-016-venus-io-europa-belt.md` (received as
|
||||||
|
|
||||||
- [x] **Step 16.1 — Content: new locations.** Venus Cloud City (cloud platform, atmospheric, 108M km at 110°, range factor 1.0, fuel × 1.3, bay 20,000), Io Sulfur Works (new type `orbital-station`, `vacuum` landing so any ship can land, 0.42M km out from Jupiter, factor 1.2, fuel × 1.0, bay 70,000) and Europa Ice Station (new type `surface-base`, `vacuum`, 0.67M km out from Jupiter, factor 1.3, fuel × 0.7, bay 70,000); all undiscovered, selling fuel, with the CR's shippers and class mixes. Pulled forward so the game keeps working: each new place's Standard good (Cloud-Grown Botanicals at Venus, a new good; Mail & Parcels also produced at Io and Europa), since boards can't be generated where nothing Standard is made; and the three body sprites in the art manifest, with their generated art (the belt is still 16.5). The balance check's first Market purchase moved from 64 to ~92 min (the Clipper's landings decide it, and Venus changed which first contacts boards offer); the user widened the window to 45–95. Tests: `packages/content/test/fixed-map.test.ts` (Earth/Moon–Venus ≈ 200, Venus–Mars ≈ 332, Venus–Ceres ≈ 520, Venus–Jupiter ≈ 885, Ceres–Io/Europa ≈ 393, all within 2 %; the Jupiter system within 1.1M km; Io and Europa ride with Jupiter at their offsets; the three undiscovered, selling fuel, not Hardened; only Earth and the Moon start discovered); `locations.test.ts` (eight locations; fuel prices ordered Jupiter < Europa < Ceres < Io < Moon < Venus < Mars < Earth). Updated: bundle count, first contacts may go to Mars or Venus, the CR-007 class-mix baseline measured on its original five places, orbit rings for every body but those riding a parent, the Market reach line now listing Venus.
|
- [x] **Step 16.1 — Content: new locations.** Venus Cloud City (cloud platform, atmospheric, 108M km at 110°, range factor 1.0, fuel × 1.3, bay 20,000), Io Sulfur Works (new type `orbital-station`, `vacuum` landing so any ship can land, 0.42M km out from Jupiter, factor 1.2, fuel × 1.0, bay 70,000) and Europa Ice Station (new type `surface-base`, `vacuum`, 0.67M km out from Jupiter, factor 1.3, fuel × 0.7, bay 70,000); all undiscovered, selling fuel, with the CR's shippers and class mixes. Pulled forward so the game keeps working: each new place's Standard good (Cloud-Grown Botanicals at Venus, a new good; Mail & Parcels also produced at Io and Europa), since boards can't be generated where nothing Standard is made; and the three body sprites in the art manifest, with their generated art (the belt is still 16.5). The balance check's first Market purchase moved from 64 to ~92 min (the Clipper's landings decide it, and Venus changed which first contacts boards offer); the user widened the window to 45–95. Tests: `packages/content/test/fixed-map.test.ts` (Earth/Moon–Venus ≈ 200, Venus–Mars ≈ 332, Venus–Ceres ≈ 520, Venus–Jupiter ≈ 885, Ceres–Io/Europa ≈ 393, all within 2 %; the Jupiter system within 1.1M km; Io and Europa ride with Jupiter at their offsets; the three undiscovered, selling fuel, not Hardened; only Earth and the Moon start discovered); `locations.test.ts` (eight locations; fuel prices ordered Jupiter < Europa < Ceres < Io < Moon < Venus < Mars < Earth). Updated: bundle count, first contacts may go to Mars or Venus, the CR-007 class-mix baseline measured on its original five places, orbit rings for every body but those riding a parent, the Market reach line now listing Venus.
|
||||||
- [x] **Step 16.2 — Content: goods.** New goods: Atmospheric Data Cores (High-Value tier 2, Venus → Earth), Refined Sulfur (Heavy, Io → Earth, Mars, Venus), Volcanic Isotopes (High-Value tier 3, Io → Earth), Subsurface Ocean Samples (High-Value tier 3, Priority, Europa → Earth); Cloud-Grown Botanicals came in 16.1. Water Ice and Liquid Oxygen are also made at Europa, Industrial Chemicals at Venus; Water Ice goes to Io and Venus, Liquid Oxygen to Io, Habitat Prefabs to Io and Europa, and Packaged Food, Consumer Goods, Mail & Parcels, Medical Supplies, Electronics and Machine Parts to all three new places. Balance medians: first purchase 92.3, discovery 48.9, loan 160.5, four ships 147 vs 156. Tests (`packages/content/test/goods.test.ts`): the five new goods with their classes, tiers and routes (Sulfur has no tier of its own); every location makes a Standard good and wants at least one; each new place is a destination for at least five goods; the new producers on existing goods.
|
- [x] **Step 16.2 — Content: goods.** New goods: Atmospheric Data Cores (High-Value tier 2, Venus → Earth), Refined Sulfur (Heavy, Io → Earth, Mars, Venus), Volcanic Isotopes (High-Value tier 3, Io → Earth), Subsurface Ocean Samples (High-Value tier 3, Priority, Europa → Earth); Cloud-Grown Botanicals came in 16.1. Water Ice and Liquid Oxygen are also made at Europa, Industrial Chemicals at Venus; Water Ice goes to Io and Venus, Liquid Oxygen to Io, Habitat Prefabs to Io and Europa, and Packaged Food, Consumer Goods, Mail & Parcels, Medical Supplies, Electronics and Machine Parts to all three new places. Balance medians: first purchase 92.3, discovery 48.9, loan 160.5, four ships 147 vs 156. Tests (`packages/content/test/goods.test.ts`): the five new goods with their classes, tiers and routes (Sulfur has no tier of its own); every location makes a Standard good and wants at least one; each new place is a destination for at least five goods; the new producers on existing goods.
|
||||||
- [ ] Step 16.3 — Content tuning: reach
|
- [x] **Step 16.3 — Content tuning: reach.** No tuning needed: with Phase 15's tanks every cell of CR-015 §4 and of CR-016 §3 already holds (Clipper ≈ 252M km reaches Venus at ≈ 200 but not Mars from Venus at ≈ 332; Freighter ≈ 460 reaches Mars from Venus and Io/Europa from Ceres at ≈ 393 but not Ceres from Venus at ≈ 520, nor Io from Mars at ≈ 592 × 1.15 short; Bulk Hauler ≈ 1,251 covers Venus–Jupiter at ≈ 885). Tests (`reach-table.test.ts`, CR-016 §3): one test per new cell (the Jupiter-system loop for Courier, Lighter, Clipper and Freighter; Earth↔Venus and Moon→Venus for Clipper and Freighter, not Courier or Lighter; Venus→Mars only from the Freighter up; Ceres↔Io/Europa for the Freighter; nothing from the inner system to the Jupiter system short of the Bulk Hauler, which flies every leg between all eight); the Bulk Hauler's full-tank reach ≥ 900M km; a Courier at the platform flies to Io and Europa and back without stranding. The no-strand test already covers every leg between all eight places.
|
||||||
- [ ] Step 16.4 — Engine: save migration and boards
|
- [ ] Step 16.4 — Engine: save migration and boards
|
||||||
- [ ] Step 16.5 — Assets: sprites and belt rocks
|
- [ ] Step 16.5 — Assets: sprites and belt rocks
|
||||||
- [ ] Step 16.6 — Map: belt haze
|
- [ ] Step 16.6 — Map: belt haze
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { content } from "@deadhead/content";
|
import { content } from "@deadhead/content";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { checkRoute } from "../src/index";
|
import { checkRoute, fullTankReach, wouldStrand } from "../src/index";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CR-015 §4: reach for base ships on the fixed map, a plain yes or no per leg
|
* CR-015 §4: reach for base ships on the fixed map, a plain yes or no per leg
|
||||||
|
|
@ -74,3 +74,80 @@ describe("reach table (CR-015 §4)", () => {
|
||||||
expect(reaches(m, from, to)).toBe(false);
|
expect(reaches(m, from, to)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** CR-016 §3: additions for Venus and the Jupiter system (decision 0.5.102). */
|
||||||
|
const NEW_NAMES: Record<string, string> = {
|
||||||
|
"venus-cloud-city": "Venus",
|
||||||
|
"io-sulfur-works": "Io",
|
||||||
|
"europa-ice-station": "Europa",
|
||||||
|
};
|
||||||
|
const allNames = { ...NAMES, ...NEW_NAMES };
|
||||||
|
const allIds = Object.keys(allNames);
|
||||||
|
const label16 = ([model, from, to]: Leg) => `${model} ${allNames[from]}→${allNames[to]}`;
|
||||||
|
|
||||||
|
const loop = ["jupiter-cloud-platform", "io-sulfur-works", "europa-ice-station"];
|
||||||
|
const localLoop = (model: string): Leg[] =>
|
||||||
|
loop.flatMap((from) => loop.filter((to) => to !== from).map((to): Leg => [model, from, to]));
|
||||||
|
const inner = ["earth", "moon", "mars", "venus-cloud-city"];
|
||||||
|
const innerToJupiterSystem = (model: string): Leg[] =>
|
||||||
|
inner.flatMap((from) => loop.map((to): Leg => [model, from, to]));
|
||||||
|
|
||||||
|
const yes16: Leg[] = [
|
||||||
|
...localLoop("courier"),
|
||||||
|
...localLoop("lighter"),
|
||||||
|
...both("clipper", "earth", "venus-cloud-city"),
|
||||||
|
["clipper", "moon", "venus-cloud-city"],
|
||||||
|
...localLoop("clipper"),
|
||||||
|
// The Freighter does everything the Clipper does, plus these.
|
||||||
|
...both("freighter", "earth", "venus-cloud-city"),
|
||||||
|
["freighter", "moon", "venus-cloud-city"],
|
||||||
|
...localLoop("freighter"),
|
||||||
|
["freighter", "venus-cloud-city", "mars"],
|
||||||
|
...both("freighter", "ceres-station", "io-sulfur-works"),
|
||||||
|
...both("freighter", "ceres-station", "europa-ice-station"),
|
||||||
|
...allIds.flatMap((from) =>
|
||||||
|
allIds.filter((to) => to !== from).map((to): Leg => ["bulk-hauler", from, to]),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
const no16: Leg[] = [
|
||||||
|
["courier", "earth", "venus-cloud-city"],
|
||||||
|
["courier", "moon", "venus-cloud-city"],
|
||||||
|
["lighter", "earth", "venus-cloud-city"],
|
||||||
|
["lighter", "moon", "venus-cloud-city"],
|
||||||
|
["clipper", "venus-cloud-city", "mars"],
|
||||||
|
...innerToJupiterSystem("clipper"),
|
||||||
|
["freighter", "venus-cloud-city", "ceres-station"],
|
||||||
|
...innerToJupiterSystem("freighter"),
|
||||||
|
];
|
||||||
|
|
||||||
|
describe("reach additions (CR-016 §3)", () => {
|
||||||
|
it.each(yes16.map((leg) => [label16(leg), leg] as const))("yes: %s", (_name, [m, from, to]) => {
|
||||||
|
expect(reaches(m, from, to)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(no16.map((leg) => [label16(leg), leg] as const))("no: %s", (_name, [m, from, to]) => {
|
||||||
|
expect(reaches(m, from, to)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gives the Bulk Hauler at least 900M km on a full tank", () => {
|
||||||
|
const bulk = content.shipModel("bulk-hauler")!;
|
||||||
|
expect(fullTankReach(bulk, content.location("earth")!, content.config)).toBeGreaterThanOrEqual(
|
||||||
|
900,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("lets a Courier at Jupiter's platform fly to Io and Europa and back, without stranding", () => {
|
||||||
|
const courier = content.shipModel("courier")!;
|
||||||
|
const all = new Set(allIds);
|
||||||
|
for (const moon of ["io-sulfur-works", "europa-ice-station"]) {
|
||||||
|
for (const [from, to] of [
|
||||||
|
["jupiter-cloud-platform", moon],
|
||||||
|
[moon, "jupiter-cloud-platform"],
|
||||||
|
] as const) {
|
||||||
|
expect(reaches("courier", from, to), `${from}→${to}`).toBe(true);
|
||||||
|
expect(wouldStrand(courier, content.location(to)!, 0, all, content)).toBe(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue