From 55e386a456c8e2ede29282a16f441dca55fb86c3 Mon Sep 17 00:00:00 2001 From: Eric J Date: Sat, 29 Aug 2026 11:32:40 -0700 Subject: [PATCH 1/2] Port the 1531/0/0/0 comparator check into Rust Hand the port the game's OWN destruction set in place of the lava and ore predicates, over all three oracle regions, and the applyCliffs model reproduces every one of the 1531 game cliffs - positions AND orientations. This is the Rust side of test/cliffDestructionResidual.spec.ts, and it is stronger than any arm of the_apply_stage_beats_the_crossing_stage_on_three_counts_and_loses_on_none: all three of those carry our own collision model, so each one measures the port and the model together. Removing the model from the comparison is what isolates the residual to Surface::wouldCollide. What is fitted and what is predicted, because that is the whole weight of the result. FITTED: the 225-cell destruction set, chosen as the raw cells the game lacks - 225 booleans. PREDICTED: all 1531 orientations, including the 14 the cascade actively rewrites; that the cascade destroys nothing beyond the 225, which would have shown as missing; and that the answer does not depend on what the halo does. The second arm is the anti-vacuity control. The first destroys nothing outside the region, because no fixture says what the game did out there. Running our own lava + ore predicate in the halo instead gives the identical answer, so "exact" is not an artifact of a quiet halo. Measured on Menehune, x86-64 WSL2, Rust 1.98.0 as rust-toolchain.toml pins: cargo test -p fmw-noise --release gives 423 passed, 0 failed. cargo fmt --check is clean and clippy --all-targets is silent. engine.wasm is byte-unchanged, as expected for a cfg(test) change. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018PuJPe8q6EKwAxgVUXCGPh --- crates/fmw-noise/src/fixtures.rs | 170 +++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/crates/fmw-noise/src/fixtures.rs b/crates/fmw-noise/src/fixtures.rs index 98227278..e4f03934 100644 --- a/crates/fmw-noise/src/fixtures.rs +++ b/crates/fmw-noise/src/fixtures.rs @@ -4279,6 +4279,176 @@ fn the_apply_stage_beats_the_crossing_stage_on_three_counts_and_loses_on_none() assert_eq!(totals[0].matched + totals[0].wrong, 1525); } +/// The game's own destruction set as an [`ApplyCollision`]: inside the region, +/// destroy exactly the raw cells the game does not have; outside it, defer to +/// `halo`. +/// +/// Fitting those booleans is the point rather than a flaw - see +/// [`the_games_own_destruction_set_reproduces_the_game_exactly`] for what is +/// fitted and what is predicted. +struct OracleKill<'a> { + /// The game's cliffs in this region, keyed as the scorer keys them. + game: &'a BTreeMap<(u64, u64), u8>, + /// `(x0, y0, x1, y1)`, half-open on the high edge as everywhere else here. + region: (f64, f64, f64, f64), + /// What runs OUTSIDE the region. `None` destroys nothing there. + halo: Option<&'a dyn ApplyCollision>, +} + +impl OracleKill<'_> { + fn in_region(&self, x: f64, y: f64) -> bool { + let (x0, y0, x1, y1) = self.region; + x >= x0 && x < x1 && y >= y0 && y < y1 + } +} + +impl ApplyCollision for OracleKill<'_> { + fn collides(&self, orientation: u8, x: f64, y: f64) -> bool { + if self.in_region(x, y) { + !self.game.contains_key(&(x.to_bits(), y.to_bits())) + } else { + self.halo.is_some_and(|h| h.collides(orientation, x, y)) + } + } +} + +/// **The whole Vulcanus cliff residual is 31 destruction decisions, and nothing +/// else** (#84). Hand the port the game's OWN destruction set in place of the +/// lava and ore predicates, over all three oracle regions, and `applyCliffs` +/// reproduces every one of the 1531 game cliffs - positions AND orientations. +/// +/// This is the Rust side of `test/cliffDestructionResidual.spec.ts`, and it is +/// STRONGER than any arm of +/// [`the_apply_stage_beats_the_crossing_stage_on_three_counts_and_loses_on_none`]: +/// all three of those carry our own collision model, so each one measures the +/// port and the model together. Removing the model from the comparison is what +/// isolates the residual to `Surface::wouldCollide`. +/// +/// **What is fitted and what is predicted**, because that is the whole weight of +/// the result: +/// +/// - FITTED: the 225-cell destruction set, chosen as the raw cells the game +/// lacks. 225 booleans. +/// - PREDICTED: all 1531 orientations, including the 14 the cascade actively +/// rewrites, each with 19 ways to be wrong; that the cascade destroys nothing +/// beyond the 225, which would show as `missing`; and that the answer does not +/// depend on what the halo does. +/// +/// The second arm is the anti-vacuity control. The first destroys nothing +/// outside the region, because no fixture says what the game did out there. +/// Running our own lava + ore predicate in the halo instead gives the identical +/// answer, so "exact" is not an artifact of a quiet halo. +#[test] +fn the_games_own_destruction_set_reproduces_the_game_exactly() { + let fixture = load_captured_at( + "test/fixtures/oracle-vulcanus-cliff-entities.seed123456.json", + "2.1.12", + ); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let seed0 = fixture.get("seed").as_f64() as u32; + + let ctx = crate::eval::ctx::EvalCtx::new(seed0); + let base = VulcanusBase::with_host_trig(&ctx); + let biomes = base.biomes_with_host_trig(); + let stack = VulcanusStack::with_host_trig(&base, &biomes); + let fields = VulcanusCliffFields::new(&stack, seed0); + let apply = LavaAndOre { + lava: VulcanusLavaTiles::new(&stack), + ore: VulcanusOreRejection::new(&stack, &ctx.vulcanus_resource_controls), + }; + let bands = CliffBands { + elevation0: VULCANUS_CLIFF_ELEVATION_0, + interval: VULCANUS_CLIFF_ELEVATION_INTERVAL, + smoothing: VULCANUS_CLIFF_SMOOTHING, + ..CliffBands::default() + }; + + // [0] = nothing runs in the halo. [1] = our own lava + ore runs there. + let mut totals = [OrientationScore::default(); 2]; + for case in fixture.get("cases").as_array() { + let r = case.get("region"); + let (x0, y0) = (r.get("x0").as_f64(), r.get("y0").as_f64()); + let (x1, y1) = (r.get("x1").as_f64(), r.get("y1").as_f64()); + + let mut game: BTreeMap<(u64, u64), u8> = BTreeMap::new(); + for e in case.get("cliffs").as_array() { + if e.get("name").as_str() != "cliff-vulcanus" { + continue; + } + let (x, y) = (e.get("x").as_f64(), e.get("y").as_f64()); + if x < x0 || x >= x1 || y < y0 || y >= y1 { + continue; + } + let want = e.get("orientation").as_str(); + if let Some(id) = CLIFF_ORIENTATION_NAMES.iter().position(|n| *n == want) { + game.insert((x.to_bits(), y.to_bits()), id as u8); + } + } + + // `generateCliffs`' queue over a 64-tile HALO: crossings and the repair + // pass, no rejection of any kind, which is what `applyCliffs` is handed. + let raw = CliffPlacement::new(&fields, bands).placed_cells( + x0 - 64.0, + y0 - 64.0, + x1 + 64.0, + y1 + 64.0, + ); + + let scored = |halo: Option<&dyn ApplyCollision>| -> OrientationScore { + let kill = OracleKill { + game: &game, + region: (x0, y0, x1, y1), + halo, + }; + let port: BTreeMap<(u64, u64), u8> = apply_cliff_connections( + &raw, + &CliffConnectionOptions { + collides: Some(&kill), + ..Default::default() + }, + ) + .iter() + .filter(|c| c.x >= x0 && c.x < x1 && c.y >= y0 && c.y < y1) + .map(|c| ((c.x.to_bits(), c.y.to_bits()), c.orientation)) + .collect(); + + let mut s = OrientationScore::default(); + for (k, id) in &port { + match game.get(k) { + None => s.surplus += 1, + Some(want) if want == id => s.matched += 1, + Some(_) => s.wrong += 1, + } + } + s.missing = game.keys().filter(|k| !port.contains_key(k)).count(); + s + }; + + for (i, s) in [scored(None), scored(Some(&apply))].iter().enumerate() { + totals[i].matched += s.matched; + totals[i].wrong += s.wrong; + totals[i].surplus += s.surplus; + totals[i].missing += s.missing; + } + } + + assert_eq!( + totals[0], + OrientationScore { + matched: 1531, + wrong: 0, + surplus: 0, + missing: 0, + }, + "the game's own destruction set, nothing running in the halo" + ); + assert_eq!( + totals[1], totals[0], + "the halo does not decide it: our own lava + ore predicate out there \ + gives the identical answer" + ); +} + // --------------------------------------------------------------------------- // Phase 5, part 3 (#225) - the Vulcanus ROCK and RESOURCE overlays. // From 95748e4e02f25bbbf58ba0552ccf29117e19c9cd Mon Sep 17 00:00:00 2001 From: Eric J Date: Sat, 29 Aug 2026 11:47:31 -0700 Subject: [PATCH 2/2] Match the sibling line and deref the key explicitly No behaviour change - the original compiled, verified on 55e386a. But L4252 already writes the same comparison as *k, so match the file rather than lean on the deref coercion. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018PuJPe8q6EKwAxgVUXCGPh --- crates/fmw-noise/src/fixtures.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fmw-noise/src/fixtures.rs b/crates/fmw-noise/src/fixtures.rs index e4f03934..4fcee4c5 100644 --- a/crates/fmw-noise/src/fixtures.rs +++ b/crates/fmw-noise/src/fixtures.rs @@ -4420,7 +4420,7 @@ fn the_games_own_destruction_set_reproduces_the_game_exactly() { Some(_) => s.wrong += 1, } } - s.missing = game.keys().filter(|k| !port.contains_key(k)).count(); + s.missing = game.keys().filter(|k| !port.contains_key(*k)).count(); s };