#include "myassert.h" #include "game_interface.h" namespace Hanabi { bool CardMultiplicity::operator==(Hanabi::CardMultiplicity const & other) const { return card == other.card && multiplicity == other.multiplicity; } bool CardMultiplicity::operator!=(Hanabi::CardMultiplicity const & other) const { return not (*this == other); } std::ostream & operator<<(std::ostream & os, HanabiStateIF const & hanabi_state) { hanabi_state.print(os); return os; } Game::Game(std::unique_ptr state, Hanabi::GameInfo game_info) : GameInfo(std::move(game_info)), state(std::move(state)), 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:; } } } unsigned Game::cur_turn() const { return next_action + 1; } unsigned Game::num_turns() const { return actions.size(); } void Game::make_turn() { ASSERT(next_action < actions.size()); size_t draw_pile_size = state->draw_pile_size(); if (draw_pile_size > 0) { Card const next_draw = deck.at(deck.size() - draw_pile_size); state->rotate_next_draw(next_draw); } Action const & action = actions[next_action]; std::uint8_t index; switch (action.type) { case Hanabi::ActionType::color_clue: case Hanabi::ActionType::rank_clue: state->give_clue(); break; case Hanabi::ActionType::discard: index = state->find_card_in_hand(action.card); ASSERT(index != std::uint8_t(-1)); state->discard(index); break; case Hanabi::ActionType::play: index = state->find_card_in_hand(action.card); ASSERT(index != std::uint8_t(-1)); state->play(index); break; case Hanabi::ActionType::vote_terminate_players: case Hanabi::ActionType::vote_terminate: case Hanabi::ActionType::end_game:; } ++next_action; } void Game::revert_turn() { state->revert(); --next_action; } bool Game::goto_turn(size_t turn) { 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::holds_state() const { return state != nullptr; } 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 (next_action > 0 and (state->draw_pile_size() < draw_pile_break or (state->draw_pile_size() == draw_pile_break and state->last_action_type() == ActionType::clue))) { revert_turn(); } return state->draw_pile_size() == draw_pile_break; } }