diff --git a/.gitignore b/.gitignore index 9192c68..5261d75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ build/ ideas/ +*.json +*.exe +.vscode/ +*.log +.DS_Store +.github/ diff --git a/src/cell_tree_agent.hpp b/src/cell_tree_agent.hpp index d55f395..00f9068 100644 --- a/src/cell_tree_agent.hpp +++ b/src/cell_tree_agent.hpp @@ -73,7 +73,6 @@ Dir move_to_parent(Grid const& cell_parents, Coord a) { throw "move_to_parent"; } - Unreachables cell_tree_unreachables(GameBase const& game, Grid const& dists) { auto cell_parents = cell_tree_parents(game.dimensions(), game.snake); auto can_move = [&](Coord from, Coord to, Dir dir) { @@ -82,6 +81,38 @@ Unreachables cell_tree_unreachables(GameBase const& game, Grid const& dist return unreachables(can_move, game, dists); } +bool should_use_cached_path_for_move_tail(const Unreachables& unreachable, Lookahead lookahead, const std::vector& cached_path) { + if (lookahead == Lookahead::many_move_tail) { + if ((unreachable.any) && (unreachable.dist_to_farthest >= INT_MAX) && !cached_path.empty()) { + return true; + } + } + return false; +} + +Unreachables get_unreachables( + const GameBase& game, + const std::vector& path, + Lookahead lookahead, + const Grid& dists) { + if (lookahead == Lookahead::many_move_tail) { + auto after = after_moves(game, path, Lookahead::many_move_tail); + auto unreachable = cell_tree_unreachables(after, dists); + + if (!unreachable.any) { + return unreachable; + } else { + auto after = after_moves(game, path, Lookahead::many_keep_tail); + auto unreachable = cell_tree_unreachables(after, dists); + return unreachable; + } + } else { + auto after = after_moves(game, path, lookahead); + auto unreachable = cell_tree_unreachables(after, dists); + return unreachable; + } +} + enum class DetourStrategy { none, any, @@ -156,9 +187,14 @@ struct CellTreeAgent : Agent { } // Heuristic 3: prevent making parts of the grid unreachable - if (detour != DetourStrategy::none) { - auto after = after_moves(game, path, lookahead); - auto unreachable = cell_tree_unreachables(after, dists); + if (detour != DetourStrategy::none) { + const Unreachables unreachable = get_unreachables(game, path, lookahead, dists); + if (should_use_cached_path_for_move_tail(unreachable, lookahead, cached_path)) { + pos2 = cached_path.back(); + cached_path.pop_back(); + return pos2 - pos; + } + if (unreachable.any) { if (log) { Grid unreachable_grid(game.dimensions()); diff --git a/src/game_util.hpp b/src/game_util.hpp index 5a38ffc..f9e0aab 100644 --- a/src/game_util.hpp +++ b/src/game_util.hpp @@ -43,7 +43,9 @@ GameBase after_moves(GameBase const& game, std::vector const& path, Looka struct Unreachables { bool any = false; Coord nearest = {-1,-1}; + Coord farthest = {-1,-1}; int dist_to_nearest = INT_MAX; + int dist_to_farthest = 0; Grid reachable; Unreachables(Grid const& reachable) @@ -68,6 +70,10 @@ Unreachables unreachables(CanMove can_move, GameLike const& game, Grid con out.nearest = a; out.dist_to_nearest = dists[a].dist; } + if (dists[a].dist > out.dist_to_farthest) { // track the farthest unreachable coordinate + out.farthest = a; + out.dist_to_farthest = dists[a].dist; + } } } return out; @@ -171,7 +177,7 @@ Grid random_spanning_tree(CoordRange dims, RNG& rng) { } } while (!queue.empty()) { - int i = rng.random(queue.size()); + int i = rng.random(static_cast(queue.size())); Coord parent = queue[i].first; Coord node = queue[i].second; queue[i] = queue.back(); diff --git a/src/snake.cpp b/src/snake.cpp index e510ed1..575ec92 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -449,7 +449,7 @@ Stats play_multiple_threaded(AgentGen make_agent, Config& config) { t.join(); } // done - if (!config.quiet) std::cout << "\033[K\r"; + if (!config.quiet) std::cout << std::endl; return stats; } @@ -467,7 +467,7 @@ Stats play_multiple(AgentGen make_agent, Config& config) { std::cout << (i+1) << "/" << config.num_rounds << " " << stats << "\033[K\r" << std::flush; } } - if (!config.quiet) std::cout << "\033[K\r"; + if (!config.quiet) std::cout << std::endl; return stats; }