diff --git a/include/game_state.h b/include/game_state.h index 7fb77cd..a985e48 100644 --- a/include/game_state.h +++ b/include/game_state.h @@ -259,11 +259,12 @@ protected: // A game mimics a game state together with a list of actions and allows to traverse the game // history by making and reverting the stored actions. struct Game { + Game(std::unique_ptr state, std::vector actions, std::vector deck); void make_turn(); void revert_turn(); - void forward_until(size_t turn = 100, size_t draw_pile_break = 0); - void revert_until(size_t draw_pile_break); + bool goto_draw_pile_size(size_t draw_pile_break); + bool goto_turn(size_t turn); std::unique_ptr state; std::vector actions; diff --git a/src/download.cpp b/src/download.cpp index 7a6b568..632c0c7 100644 --- a/src/download.cpp +++ b/src/download.cpp @@ -182,7 +182,7 @@ namespace Download { }(); if (!game_json_opt.has_value() or game_json_opt.value().empty()) { - return {nullptr, {}, {}, 0}; + return Hanabi::Game(nullptr, {}, {}); } const boost::json::object& game_json = game_json_opt.value(); @@ -202,7 +202,7 @@ namespace Download { } ); - return {get_base_state(num_suits, num_players, deck, score_goal), actions, deck, 0}; + return {get_base_state(num_suits, num_players, deck, score_goal), actions, deck}; } } // namespace Download diff --git a/src/game_state.cpp b/src/game_state.cpp index c206cb2..a511a61 100644 --- a/src/game_state.cpp +++ b/src/game_state.cpp @@ -1,7 +1,26 @@ +#include +#include #include "game_state.h" namespace Hanabi { + Game::Game(std::unique_ptr state, std::vector actions, std::vector deck): + state(std::move(state)), actions(std::move(actions)), deck(std::move(deck)), next_action(0) + { + // If there is a 'Null' action that only signals the game's end, we want to get rid of it now, + // as this will mess with our moves. + if(not this->actions.empty()) { + switch(this->actions.back().type) { + case ActionType::vote_terminate: + case ActionType::vote_terminate_players: + case ActionType::end_game: + this->actions.pop_back(); + default: + ; + } + } + } + void Game::make_turn() { ASSERT(next_action < actions.size()); @@ -35,26 +54,35 @@ namespace Hanabi { void Game::revert_turn() { state->revert(); + --next_action; } - void Game::forward_until(size_t turn, size_t draw_pile_break) + bool Game::goto_turn(size_t turn) { - for (size_t i = 0; i < std::min(turn - 1, actions.size()); i++) { - if (state->draw_pile_size() == draw_pile_break) { - break; + size_t const cur_turn = next_action + 1; + if (cur_turn >= turn) { + for(size_t i = 0; i < cur_turn - turn; i++) { + revert_turn(); } + } else { + while(next_action < actions.size() and next_action + 1 < turn) { + make_turn(); + } + } + return next_action + 1 == turn; + } + + bool Game::goto_draw_pile_size(size_t draw_pile_break) + { + while (state->draw_pile_size() > draw_pile_break and next_action < actions.size()) { make_turn(); } + while(state->draw_pile_size() < draw_pile_break or (state->draw_pile_size() == draw_pile_break and state->last_action_type() == ActionType::clue)) { + revert_turn(); + } + std::cout << "Moved to turn " << next_action + 1 << " with draw pile size " << state->draw_pile_size() << ".\n"; + return state->draw_pile_size() == draw_pile_break; } - void Game::revert_until(size_t draw_pile_break) - { - while(state->draw_pile_size() < draw_pile_break) { - revert_turn(); - } - while(state->last_action_type() == ActionType::clue) - { - revert_turn(); - } - } + } diff --git a/src/main.cpp b/src/main.cpp index 5694ee7..cdcfc73 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,7 +23,7 @@ namespace Hanabi { return; } - game.forward_until(turn, draw_pile_size); + game.goto_draw_pile_size(draw_pile_size); if (draw_pile_size != 0 and game.state->draw_pile_size() != static_cast(draw_pile_size)) { std::cout << "This given draw pile size (" << draw_pile_size << ") cannot be obtained with the specified replay." << std::endl; return; @@ -57,9 +57,11 @@ namespace Hanabi { if (print_remaining_states) { size_t const max_draw_pile_size = game.state->draw_pile_size(); - game.forward_until(100, 1); for(size_t remaining_cards = 1; remaining_cards <= max_draw_pile_size; remaining_cards++) { - game.revert_until(remaining_cards); + if (!game.goto_draw_pile_size(remaining_cards)) + { + continue; + }; if (all_clues) { clue_t original_num_clues = game.state->num_clues(); for(clue_t num_clues = 0; num_clues <= 8; num_clues++) {