From c42255e199f98e87fdcb6d95a2b79561c0af74e6 Mon Sep 17 00:00:00 2001 From: acamilo Date: Tue, 22 Sep 2026 17:19:25 +0000 Subject: [PATCH] macros: an edge the map graph cannot name stops being somewhere new once it is stood on The rung-11 reading of row 54. Route 3's connections read north and west off the cartridge (`wCurMapConnections`, and it has no warps at all) while the geography table carries west and east, so the seven walkable tiles of its north edge had an unnameable destination -- and an unnameable destination counted as unvisited, which made them first-tier for `GO ROUTE` on every hold for ever, with `GO OBJECTIVE` off the pad beside them because nothing on that map leads to the objective. A warp's destination is a byte the cartridge publishes, so `None` there is the `LAST_MAP` case already handled. An edge's comes only from `geography::connected`, so `None` there means the table cannot name the map on the other side and never will, and the only record left is the adapter's own boundary ledger. It narrows: a genuinely new edge is still first-tier until the fly reaches it. Which map is north of Route 3 is not guessed at here. That is a survey -- walk the fly off the edge with real presses and read the map id back -- and it is recorded as a residual instead. --- .../src/pokemon_red/macros/palette.rs | 20 ++++++++++-- .../src/pokemon_red/macros/tests.rs | 31 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/palette.rs b/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/palette.rs index 1c641ad..6778b70 100644 --- a/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/palette.rs +++ b/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/palette.rs @@ -1298,9 +1298,23 @@ fn exit_tiers(state: &mut dyn MacroState, way: Way) -> Vec { let known_visited = match exit.destination(here) { Some(map) => state.map_visited(map), // A front door nobody can name opens on the map the fly came in from, which is a map - // this run has stood on by construction. Every other unnameable destination stays a - // candidate. - None => exit.way == Way::Exit, + // this run has stood on by construction. + None if exit.way == Way::Exit => true, + // **An edge the geography table has no row for** (2026-09-22, the rung-11 reading of + // row 54). A warp's destination is a byte the cartridge publishes, so `None` there is + // the `LAST_MAP` case above; an edge's destination comes only from + // [`geography::connected`], so `None` here means the table cannot name the map on the + // other side and never will. Route 3 is the measured one: the cartridge reports its + // connections as **north and west** while the table carries west and *east*, so its + // seven walkable north-edge tiles answered "leads somewhere this run has not stood + // on" on every hold for ever, and `GO ROUTE` aimed at them once per hold. + // + // The only record left is the adapter's own boundary ledger, which is what section + // 9.2 replaced as the *general* test and which is still the honest answer for an exit + // nothing else can say anything about: an edge the run has already stood on is not + // somewhere new. It narrows, so a genuinely new edge is still first-tier until the + // fly reaches it. + None => state.exit_visited(exit.id), }; if !known_visited { fresh.push(*exit); diff --git a/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/tests.rs b/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/tests.rs index 9101e05..53e9359 100644 --- a/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/tests.rs +++ b/services/flysim/crates/flybrain-gb/src/pokemon_red/macros/tests.rs @@ -3970,6 +3970,37 @@ fn go_shop_and_go_heal_are_on_the_pad_while_their_errand_stands() { assert!(!on_the_pad(&mut pallet, MacroKind::GoHeal)); } +#[test] +fn an_edge_the_table_cannot_name_stops_being_somewhere_new_once_it_is_stood_on() { + // The rung-11 reading of row 54 (`infra/docs/macros-traps.md`). The cartridge reports Route + // 3's connections as north and west; `geography`'s row carries west and east, so the north + // edge's destination is unnameable -- and an unnameable destination counted as *unvisited*, + // which made those tiles first-tier for `GO ROUTE` on every hold for ever, with + // `GO OBJECTIVE` off the pad beside them because nothing on this map leads to the objective. + let mut world = World::room(); + world.map = maps::ROUTE_3; + world.size = MapSize { width: 8, height: 8 }; + world.player = Tile::new(4, 4); + world.connections = Connections { north: true, south: false, east: false, west: true }; + // West is Pewter City, which the table does name and the run has stood on. + world.seen_maps.insert(maps::PEWTER_CITY); + + let north: Vec = ways(&mut world, Way::Route).iter().map(|exit| exit.id).collect(); + assert!( + north.iter().all(|id| *id == ExitId::Edge(Edge::North)), + "the unnameable north edge is the only fresh way out: {north:?}" + ); + + // Stood on, and it is no longer somewhere new -- so the walk falls to the tier that leads + // toward the objective instead of aiming at the same edge once per hold for ever. + world.visited.insert(ExitId::Edge(Edge::North)); + let left: Vec = ways(&mut world, Way::Route).iter().map(|exit| exit.id).collect(); + assert!( + !left.contains(&ExitId::Edge(Edge::North)), + "an edge nothing can name, already crossed, is not first-tier: {left:?}" + ); +} + #[test] fn an_errand_does_not_settle_on_the_doormat_it_is_standing_on() { // Row 54 of `infra/docs/macros-traps.md`, and section 12.2's rule: "a macro that completes