Skip to content

Pokemon navigation: the shared core for AutoStory - #114

Open
dayfine wants to merge 22 commits into
autostory/r3-shared-statsfrom
nav/shared
Open

dayfine wants to merge 22 commits into
autostory/r3-shared-statsfrom
nav/shared

Conversation

@dayfine

@dayfine dayfine commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Depends on #45 (on #44 and #43; #43 and #44 are upstream as PokemonAutomation#1828).

BDSP and FRLG AutoStory each had their own grid, planner, walker and map format, so none of it could be shared or tested once. This adds the game-agnostic core: Pokemon/Navigation has the grid types, the leg planner, the leg walker with its stop hooks, the route log lines both walkers write, and Pokemon::MapData, the one JSON map schema both games' maps are written in (tiles in shared glyphs, elevation, warps that say how they are entered, objects, named points and flag sets); Pokemon/AutoStory has checkpoints as events, segments and the tile pose, with ScreenMachine/StepTrace in CommonTools. Navigation includes nothing from AutoStory or any game. Tested with the LegPlanner, LegWalker, MapData, RouteLog, StoryEvents and StorySegments suites in fork CI on Mac, Windows Clang and Ubuntu.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E

dayfine and others added 4 commits October 31, 2026 21:59
std::function is copyable, so copying one silently forks a stateful
lambda's state, and it can't hold move-only captures.
std::move_only_function fixes both, but Apple Clang's libc++ doesn't have
it yet. MoveOnlyFunction is an alias of std::move_only_function where the
library defines it (GCC, MSVC) and a small fallback elsewhere (macOS),
with copying deleted. Tested with four unit tests on fork CI (Mac runs
the fallback; Ubuntu and Windows clang run the std branch).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
FRLG and BDSP each built a grid planner for AutoStory, and the two copies
share the same ideas but can't serve each other, because each planner is
tied to its own map type. This adds the part both games plan on: the grid
types (tile positions and directions) and a leg planner that asks the
game's step model what one press does and prefers legs that end at a
wall, tested on a small made-up game. The leg walker, ScreenMachine and
TileGrid/MapSet live with their users in other PRs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
BDSP's new-game intro runs as a closed loop over the screens it knows:
read the screen, take the one step that screen calls for, read again,
and treat an unexpected screen or a state that keeps coming back as the
sign of a dropped or wrong input. This adds that loop as its own module:
ScreenMachine runs it and StepTrace logs every recognized screen change
with a numbered screenshot and every input, so a failure reports the
screens that led up to it. Nothing here depends on navigation; there are
no tests yet, CI checks that it builds on its own.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
AutoStory checkpoints are long C++ functions of walks, presses and
waits, and a checkpoint only notices drift or a missed talk when a later
step fails. This adds the game-neutral runner from the event-model
design: a checkpoint is a list of events with skip_if, require, an
action, expects, a learned pose and named recoveries (wait, then
re-anchor, then stop), plus per-checkpoint interrupts. run_checkpoint()
skips events whose effect already shows, so a reload resumes by
re-checking, and it logs one "[Event] ..." line per event for the lab
watcher. Observation and actuation are MoveOnlyFunctions, so the
Pokemon::StoryEvents unit tests run it against a scripted world; no
game uses it yet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
@dayfine
dayfine marked this pull request as ready for review November 1, 2026 06:19
@dayfine

dayfine commented Nov 1, 2026

Copy link
Copy Markdown
Owner Author

LGTM

Scarlet/Violet will run story checkpoints on map points and fly points, so
the engine's Pose can no longer be tiles and a facing. The engine now keeps
only the map, the certainty and an opaque Position the game supplies and the
engine only prints; the tile pose moves to Pokemon_TilePose.h for the 2D
games, and InterruptPose::INEXACT becomes WITHIN_SET. No behavior change:
the log text for a tile pose is the same as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
Upstream merged MoveOnlyFunction as PokemonAutomation#1810,
so this branch's copy is redundant: MoveOnlyFunction_Tests.cpp takes
upstream's version, the header and test list were already identical.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine and others added 2 commits November 1, 2026 00:12
A story segment is now a Segment: rows of CheckpointSpec, each with an id,
a title, whether the segment saves after it, and a factory that builds the
checkpoint fresh for every attempt. run_segment() runs a range of rows in
order through SegmentHooks (save, reload, log); a failed checkpoint is
reloaded, rebuilt and run again up to SegmentPolicy's attempts, then the
report names the checkpoint, the event and the reason. Actions no longer
write the run's pose: a succeeded Outcome carries the pose and the runner
writes it before the expects. describe() dumps a checkpoint or a segment as
text for review, covered by a golden-string test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
BDSP and FRLG each read their own map files with their own parser. This
adds a game-neutral MapData and parse_map() in Pokemon/Navigation, with one
schema: a name, the decompilation source (file, revision, date), tiles as
rows of glyphs, named points, warps to a point of another map, objects
(npc, item, sign, with a facing and a wander box), connections to the
neighbouring maps, and patches of tiles measured on the console applied
on top. The reader generalises FRLG's read_map(): errors name the source
and the JSON path, and anything placed outside the tiles is an error.
Grid<Cell> moves into Pokemon_Grid.h for it. No game reads these yet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
GCC's -Wdangling-reference flagged the source object bound from as_object()
with a temporary path string. Naming the path first silences it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
A step can be marked wild (the walk may be interrupted there, e.g. by a
wild battle in tall grass). The planner tracks per step whether the leg in
progress has a wild step, marks such legs wild, and adds
LegCosts::per_open_wild_stop when one of them ends in the open: after an
interruption a leg to a wall is simply walked again, while how far an open
one got is a guess. The weight defaults to 0, so games that don't set it
plan as before.

Moved here from frlg/walk-interrupt-recount (b4d1976), which added it
for FRLG's Route 1. Tests on the planner's toy grid: a leg through grass is
wild, an open stop after grass is weighed, the weight needs a wild step,
and a new leg starts out not wild.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
# Conflicts:
#	SerialPrograms/Source/ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_Navigation_Tests.h
#	SerialPrograms/cmake/SourceFiles.cmake
dayfine added a commit that referenced this pull request Nov 1, 2026
Brings in nav/shared (#114) through #117.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
…count

Brings in nav/shared (#114) through #117 and #118, including the planner's wild-step weighting (7008f8c), which moved there from this branch's b4d1976.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
…-mvp

#119 now has nav/shared (#114) through #117 and #118, so this PR's diff shows only its own files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
LegPlanner's wild-step weighting moved from #119 to #114 (7008f8c) and merged down #117 → #118 → #119 → #120; #120's diff is PokemonFRLG only. Adds #119, #120, #121 to the tree and a file-ownership table.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
The shared engine replaces this branch's copies of the grid types, leg
planner and story events. LegWalker goes: nothing in BDSP uses it, and
FRLG brings its own on nav/shared. SandgemCenterEvents moves to the
shared Pose (a Position) and returns learned poses in its Outcome.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E

# Conflicts:
#	Common/Cpp/MoveOnlyFunction_Tests.cpp
#	SerialPrograms/Source/ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_Grid.cpp
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_Grid.h
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_LegPlanner.h
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_LegPlanner_Tests.cpp
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_Navigation_Tests.h
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_StoryEvents.cpp
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_StoryEvents.h
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_StoryEvents_Tests.cpp
#	SerialPrograms/cmake/SourceFiles.cmake
dayfine added a commit that referenced this pull request Nov 1, 2026
…p/maps-rederive

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
A leg's wild flag was worked out from the tiles on its start map only, so
"north 22" from Pallet Town, through Route 1's grass beyond the map's
edge, was walked without watching for battles (console B, 2026-11-01).
It now comes from the planner's per-step wild flag (#114), set on tall
grass and water. The wild-steps route test checks that leg.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
The leg walker and its tests, moved here from the FRLG PRs (#117 added
it, #119 dropped the tile-at-a-time walk and added the stop hooks), so
that the shared navigation code lives in one PR. Unchanged from #119's
version: it walks one leg with a game's mover, clears interrupts on the
way, and stops an open leg at an interrupt or a leg to a wall that is
interrupted again at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
…mes from #114

# Conflicts:
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_LegWalker.cpp
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_LegWalker.h
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_LegWalker_Tests.cpp
dayfine added a commit that referenced this pull request Nov 1, 2026
…s PR

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
@dayfine
dayfine changed the base branch from base/upstream-main to autostory/r3-shared-stats November 1, 2026 20:30
…base test) into nav/shared

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
Navigation is moving the player (grids, maps, legs, the walker, the route
log); AutoStory is the story. StoryEvents, StorySegments and TilePose (the
story's pose on a tile map) move unchanged to Pokemon/AutoStory, next to
the select database and stats, with their tests registered from a new
Pokemon_AutoStory_Tests.h. Navigation includes nothing from AutoStory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
…y) into nav/story-steps

# Conflicts:
#	SerialPrograms/Source/Pokemon/Navigation/Pokemon_Navigation_Tests.h
#	SerialPrograms/cmake/SourceFiles.cmake
dayfine added a commit that referenced this pull request Nov 1, 2026
StorySteps and its tests move unchanged to Pokemon/AutoStory, next to the
events and segments they build on (#114), and register from
Pokemon_AutoStory_Tests.h. The story run options include them from there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
Grid is a plain value whose methods only read: a cell is changed through
the free function cell_at(). The leg walker's mover is a callable
(LegMover = std::function) instead of a one-method interface. Position
keeps its virtual describe(), now with a default, since games extend it
with their own data and read it back by type (TilePose).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
The shared LegMover is now a callable (#114): the D-pad hold is a plain
function. Reading the player's facing at the start of a route moves into
read_facing(), keeping walk_overworld_route() under the function size
limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
…s logged

The [Segment], [Checkpoint] and [Event] lines went only to the program's
log, and an event whose game step threw left the runner with no "failed"
line. SegmentHooks gains an optional status sink that gets every line
again without its tag ("00.03/2 below_oaks_trigger: start"), for the
video overlay and, once run records land (#132), for the run's events.
An exception out of an event is logged as "[Event] ... failed: <what>"
and "[Checkpoint] ... failed at <n> <event>: <what>", then rethrown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine added a commit that referenced this pull request Nov 1, 2026
…/story-steps

# Conflicts:
#	SerialPrograms/Source/Pokemon/AutoStory/Pokemon_StorySegments.cpp
#	SerialPrograms/Source/Pokemon/AutoStory/Pokemon_StorySegments.h
@dayfine dayfine added autostory AutoStory programs game:shared Shared or game-neutral code navigation Maps, planner, walker labels Nov 1, 2026
All optional in the JSON, so today's maps parse unchanged:
- world: a map's place on a world grid shared with other maps.
- regions: named, ordered tile lists (replacing numbered points).
- tiles: ' ' off the game's map; '8' '2' '4' '6' one-sided walls.
- elevation: rows of hex digits, the size of the tiles.
- warps: how they are entered (walk_into, step_on, cave_entrance,
  walk_<direction> for mats), and a destination that may be left out
  for a map not loaded; warp_at() finds the warp on a tile.
- objects: trainer sight and the ways a trainer looks; hide_flag.
- triggers: coord-event boxes, with the story state they fire in.
- flag_sets: flags set together, by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E
dayfine and others added 2 commits November 2, 2026 07:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKYzhrMnPK61XHWEch4a6E

# Conflicts:
#	SerialPrograms/Source/ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autostory AutoStory programs game:shared Shared or game-neutral code navigation Maps, planner, walker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant