diff --git a/SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldReanchor.cpp b/SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldReanchor.cpp index 670cf0a2e9..d20f2e2844 100644 --- a/SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldReanchor.cpp +++ b/SerialPrograms/Source/VideoGames/PokemonFRLG/Overworld/PokemonFRLG_OverworldReanchor.cpp @@ -6,6 +6,7 @@ #include #include +#include "Pokemon/Navigation/Pokemon_WallRecovery.h" #include "PokemonFRLG_OverworldReanchor.h" namespace PokemonAutomation{ @@ -126,15 +127,6 @@ struct Hypothesis{ bool operator==(const Hypothesis& other) const = default; }; -bool converged(const std::vector& positions){ - for (const Hypothesis& position : positions){ - if (!(position.at == positions[0].at)){ - return false; - } - } - return true; -} - // Whether a person stands, or may wander, on a tile `wall` passes after // `from`. The step rules don't have people, but one there stops the player // short of the wall. @@ -183,41 +175,33 @@ std::optional, RouteStep>> hold_all( return std::make_pair(std::move(ends), hold); } -int total_tiles(const std::vector& legs){ - int total = 0; - for (const RouteStep& leg : legs){ - total += leg.tiles; - } - return total; -} +using Found = Pokemon::WallAnchor; -struct Found{ - std::vector holds; - MapPosition at; +// Runtime world alternatives and movement mode, separate from the policy type. +struct ReanchorContext{ + const std::vector>& worlds; + bool surfing = false; }; -// Every way of exactly `depth` holds that brings all of `positions` to one -// tile, in a fixed order. -void search( - const std::vector>& worlds, const std::vector& positions, bool surfing, - size_t depth, std::vector& holds, std::vector& found -){ - for (Direction direction : Pokemon::ALL_DIRECTIONS){ - auto next = hold_all(worlds, positions, surfing, direction); - if (!next || next->first == positions || next->second.tiles == 0){ - continue; - } - holds.push_back(next->second); - if (converged(next->first)){ - if (depth == 1){ - found.push_back(Found{holds, next->first[0].at}); - } - }else if (depth > 1){ - search(worlds, next->first, surfing, depth - 1, holds, found); +class ReanchorPolicy{ +public: + using Hypothesis = PokemonFRLG::Hypothesis; + using Position = MapPosition; + using Hold = RouteStep; + + static Position position(const Hypothesis& hypothesis){ return hypothesis.at; } + static int tiles(const Hold& hold){ return hold.tiles; } + static std::optional> hold( + const ReanchorContext& context, const std::vector& positions, Direction direction + ){ + auto next = hold_all(context.worlds, positions, context.surfing, direction); + if (!next){ + return std::nullopt; } - holds.pop_back(); + return Pokemon::WallRecoveryStep{std::move(next->first), std::move(next->second)}; } -} + +}; // Whether `route`, planned from `at` on other maps, walks the same on // `world`: each leg to a wall stops at its end, each open leg gets there. @@ -257,18 +241,9 @@ bool walks_same_everywhere( std::vector find_player( const std::vector>& worlds, const std::vector& positions, bool surfing ){ - std::vector found; - if (converged(positions)){ - found.push_back(Found{{}, positions[0].at}); - } - for (size_t depth = 1; found.empty() && depth <= MAX_HOLDS; depth++){ - std::vector holds; - search(worlds, positions, surfing, depth, holds, found); - std::stable_sort(found.begin(), found.end(), [](const Found& a, const Found& b){ - return total_tiles(a.holds) < total_tiles(b.holds); - }); - } - return found; + return Pokemon::find_wall_anchors( + positions, ReanchorContext{.worlds = worlds, .surfing = surfing}, {.max_holds = MAX_HOLDS} + ); } }