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.
This commit is contained in:
acamilo 2026-09-22 17:19:25 +00:00
parent 8ef5dc321d
commit c42255e199
2 changed files with 48 additions and 3 deletions

View file

@ -1298,9 +1298,23 @@ fn exit_tiers(state: &mut dyn MacroState, way: Way) -> Vec<Exit> {
let known_visited = match exit.destination(here) { let known_visited = match exit.destination(here) {
Some(map) => state.map_visited(map), 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 // 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 // this run has stood on by construction.
// candidate. None if exit.way == Way::Exit => true,
None => exit.way == Way::Exit, // **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 { if !known_visited {
fresh.push(*exit); fresh.push(*exit);

View file

@ -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)); 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<ExitId> = 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<ExitId> = 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] #[test]
fn an_errand_does_not_settle_on_the_doormat_it_is_standing_on() { 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 // Row 54 of `infra/docs/macros-traps.md`, and section 12.2's rule: "a macro that completes