Step 3.4: add route distance
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
301c0934e1
commit
ccd571fdd0
|
|
@ -94,3 +94,7 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md`
|
|||
- **The Moon is Earth plus 0.384M km on the +x axis**, as the plan specifies; its real orbit is ignored.
|
||||
- **Ceres uses a circular orbit** (astronomy-engine has no Ceres): radius 2.7675 AU (~414M km), period 1,680.5 days, mean longitude ~160° at J2000. The angle is approximate, which is fine for gameplay.
|
||||
- **Test date is 2100-03-01**, close to the placeholder game epoch.
|
||||
|
||||
## Step 3.4
|
||||
|
||||
- **Route distance is the straight line between the two positions at one game time.** Orbital transfer paths are not modelled.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
- [x] **Step 3.1 — Game clock conversion.** `src/clock.ts`: `realToGame` / `gameToReal` using the config epoch and compression; times are Unix-ms numbers.
|
||||
- [x] **Step 3.2 — Seeded RNG.** `src/rng.ts`: `createRng(seed)` (mulberry32) with `next`, `int`, `pick`; `deriveSeed(parent, label)` for child seeds.
|
||||
- [x] **Step 3.3 — Location positions.** `src/positions.ts`: heliocentric ecliptic positions (million km) from `astronomy-engine` for Earth, Mars and Jupiter; Moon = Earth + fixed offset; Ceres on a circular orbit.
|
||||
- [ ] Step 3.4 — Route distance
|
||||
- [x] **Step 3.4 — Route distance.** `src/distance.ts`: `routeDistance(from, to, gameTime)`, straight-line million km.
|
||||
- [ ] Step 3.5 — Travel time
|
||||
- [ ] Step 3.6 — Fuel cost
|
||||
- [ ] Step 3.7 — Range and landing eligibility
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
import type { Location } from "@deadhead/content";
|
||||
import type { GameTime } from "./clock";
|
||||
import { locationPosition } from "./positions";
|
||||
|
||||
/** Straight-line distance between two locations at a game time, in million km. */
|
||||
export function routeDistance(from: Location, to: Location, gameTime: GameTime): number {
|
||||
const a = locationPosition(from, gameTime);
|
||||
const b = locationPosition(to, gameTime);
|
||||
return Math.hypot(b.x - a.x, b.y - a.y);
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./clock";
|
||||
export * from "./rng";
|
||||
export * from "./positions";
|
||||
export * from "./distance";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { content } from "@deadhead/content";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { routeDistance } from "../src/index";
|
||||
|
||||
const earth = content.location("earth")!;
|
||||
const moon = content.location("moon")!;
|
||||
const mars = content.location("mars")!;
|
||||
|
||||
const start = Date.parse("2100-01-01T00:00:00Z");
|
||||
const MS_PER_DAY = 86_400_000;
|
||||
/** Game times sampled every ~30 days across two years. */
|
||||
const monthly = Array.from({ length: 25 }, (_, i) => start + i * 30 * MS_PER_DAY);
|
||||
|
||||
describe("route distance", () => {
|
||||
it("keeps Earth→Moon under 1 million km at any time", () => {
|
||||
for (const t of monthly) {
|
||||
expect(routeDistance(earth, moon, t)).toBeLessThan(1);
|
||||
}
|
||||
});
|
||||
|
||||
it("varies Earth→Mars by at least 200 million km over two years", () => {
|
||||
const distances = monthly.map((t) => routeDistance(earth, mars, t));
|
||||
expect(Math.max(...distances) - Math.min(...distances)).toBeGreaterThanOrEqual(200);
|
||||
});
|
||||
|
||||
it("is symmetric", () => {
|
||||
for (const a of content.locations) {
|
||||
for (const b of content.locations) {
|
||||
expect(routeDistance(a, b, start)).toBe(routeDistance(b, a, start));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue