From 28bd980e653560194e88c2c4148a08bbfddbb168 Mon Sep 17 00:00:00 2001 From: acamilo Date: Wed, 23 Sep 2026 10:34:33 +0000 Subject: [PATCH] survey: the route probe prints the room whole, its people, and the rung at the end The catch dump prints a small map whole with its people drawn and off the screen, each person's ledger entries and whether a route reaches them; outcomes are keyed by the map they finished on, the trace line carries the seam's bytes (wCurOpponent included), and the drive ends with the rank. How row 58's mechanism was read. --- .../crates/flysim/examples/scene_probe.rs | 70 +++++++++++++++---- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/services/flysim/crates/flysim/examples/scene_probe.rs b/services/flysim/crates/flysim/examples/scene_probe.rs index 717001a..28a3d33 100644 --- a/services/flysim/crates/flysim/examples/scene_probe.rs +++ b/services/flysim/crates/flysim/examples/scene_probe.rs @@ -1355,9 +1355,9 @@ fn dialog_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64 /// [`PokemonPalette`]: flybrain_gb::pokemon_red::macros::PokemonPalette fn route_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64) { use flybrain_gb::MacroPalette; - use flybrain_gb::pokemon_red::macros::cartridge::{MacroState, TargetKey}; + use flybrain_gb::pokemon_red::macros::cartridge::{FACINGS, MacroState, TalkTarget, TargetKey}; use flybrain_gb::pokemon_red::macros::path::Way; - use flybrain_gb::pokemon_red::macros::{PokemonPalette, palette, path}; + use flybrain_gb::pokemon_red::macros::{PokemonPalette, Tile, palette, path}; let budget = env_usize("FLY_PROBE_FRAMES", 240_000); let mut rng = env_usize("FLY_PROBE_RNG", 20_260_923) as u32 | 1; @@ -1484,7 +1484,12 @@ fn route_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64) } } if let Some((name, outcome)) = macros.take_finished() { - *outcomes.entry(format!("{name} {outcome:?}")).or_default() += 1; + *outcomes + .entry(format!( + "{name} {outcome:?} on {:?}", + state::player(gb).map(|p| p.map) + )) + .or_default() += 1; if !matches!(outcome, flybrain_gb::Outcome::Done) { println!( "f{frame:<6} {:?} {name} {outcome:?}", @@ -1495,11 +1500,12 @@ fn route_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64) since_decision += 1; if frame < trace_frames { println!( - " t{frame:<5} {:?} mask {mask:#04x} running {:?} marks {:?} stood {}", + " t{frame:<5} {:?} mask {mask:#04x} running {:?} marks {:?} stood {} | {}", state::player(gb).map(|p| (p.map, p.x, p.y, p.facing)), macros.running(), macros.fences().1, - macros.stood() + macros.stood(), + scene::why_unknown(gb) ); } gb.set_buttons(mask); @@ -1531,6 +1537,11 @@ fn route_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64) } } println!("```\n"); + let progress = adapter.progress(); + println!( + "- at the end: rank {} ({}), badges {}, unique tiles {}", + progress.rank, progress.rank_label, progress.counter, progress.unique_locations + ); println!("- refusals: {refusals:?}"); println!("- outcomes: {outcomes:?}"); let Some(frame) = caught_at else { @@ -1557,11 +1568,13 @@ fn route_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64) println!("- objective: {:?}", state.objective()); println!("- `objective_goals`: {:?}", palette::objective_goals(state)); println!("- `objective_targets`: {:?}", palette::objective_targets(state)); - for (tile, target) in path::person_targets(state) { + let drawn = path::person_targets(state); + for (tile, target) in drawn.iter().copied().chain(path::offscreen_person_targets(state)) { println!( - " - person {target:?} at ({:2},{:2}): talked {}, blocked {}, reached {}", + " - person {target:?} at ({:2},{:2}) {}: talked {}, blocked {}, reached {}", tile.x, tile.y, + if drawn.contains(&(tile, target)) { "drawn" } else { "off the screen" }, state.talked(target), state.blocked(TargetKey::Thing(target)), state.reached(TargetKey::Thing(target)) @@ -1591,16 +1604,44 @@ fn route_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64) reach ); } - println!("\n### The fly's own neighbourhood (pushed = `P`, player = `@`)\n\n```"); - for y in player.y.saturating_sub(3)..=player.y.saturating_add(3) { - let row: String = (player.x.saturating_sub(6)..=player.x.saturating_add(6)) + // A room small enough to print whole is printed whole, with its people on it (row 58: + // the gym's leader is twelve rows from the door). + let size = state.map_size().expect("a loaded map"); + let whole = size.width <= 24 && size.height <= 24; + let people: Vec<(Tile, TalkTarget)> = path::person_targets(state) + .into_iter() + .chain(path::offscreen_person_targets(state)) + .collect(); + let (rows, columns) = if whole { + (0..=size.height - 1, 0..=size.width - 1) + } else { + ( + player.y.saturating_sub(3)..=player.y.saturating_add(3), + player.x.saturating_sub(6)..=player.x.saturating_add(6), + ) + }; + let grid = state.map_grid(); + println!( + "\n### The fly's {} (pushed = `P`, player = `@`, a person = `N`; grid {})\n\n```", + if whole { "whole map" } else { "own neighbourhood" }, + grid.is_some() + ); + for y in rows { + let row: String = columns + .clone() .map(|x| { + let walk = match grid.as_deref() { + Some(grid) => grid.walkable(x, y), + None => state.walkable(x, y), + }; if x == player.x && y == player.y { '@' + } else if people.iter().any(|(tile, _)| *tile == Tile::new(x, y)) { + 'N' } else if state.pushed_tile(x, y) { 'P' } else { - match state.walkable(x, y) { + match walk { flybrain_gb::pokemon_red::macros::state::Walkable::Yes => '.', flybrain_gb::pokemon_red::macros::state::Walkable::No => '#', flybrain_gb::pokemon_red::macros::state::Walkable::Unknown => '?', @@ -1608,9 +1649,14 @@ fn route_survey(gb: &mut Emulator, adapter: &mut PokemonRedReward, ms: &mut f64) } }) .collect(); - println!("y{y:2} x{:2}.. {row}", player.x.saturating_sub(6)); + println!("y{y:2} x{:2}.. {row}", if whole { 0 } else { player.x.saturating_sub(6) }); } println!("```"); + for (tile, target) in &people { + let aims: Vec = FACINGS.iter().filter_map(|facing| tile.step(*facing)).collect(); + let reach = path::route(state, &aims).map(|route| route.goal); + println!("- a route to {target:?} at ({:2},{:2}): {reach:?}", tile.x, tile.y); + } }); }