diff --git a/game_state.h b/game_state.h index 40b7e7b..fa42c28 100644 --- a/game_state.h +++ b/game_state.h @@ -19,6 +19,7 @@ using rank_t = std::uint8_t; using suit_t = std::uint8_t; using clue_t = std::uint8_t; using player_t = std::int8_t; +using hand_index_t = std::uint8_t; using state_t = std::uint32_t; @@ -49,10 +50,7 @@ struct Card { auto operator<=>(const Card &) const = default; }; -std::ostream &operator<<(std::ostream &os, const Card &card) { - os << suit_initials[card.suit] << 5 - card.rank; - return os; -} +std::ostream &operator<<(std::ostream &os, const Card &card); constexpr Card r0 = {0, 0}; constexpr Card r1 = {0, 1}; @@ -73,9 +71,10 @@ constexpr Card y4 = {1, 4}; * - Number of clues */ -template using Stacks = std::array; +template +using Stacks = std::array; -template +template std::ostream &operator<<(std::ostream &os, const Stacks &stacks); struct CardMultiplicity { @@ -85,7 +84,7 @@ struct CardMultiplicity { auto operator<=>(const CardMultiplicity &) const = default; }; -template struct CardArray { +template struct CardArray { using value_type = T; CardArray() = default; @@ -115,9 +114,9 @@ struct BacktrackAction { // The card that was discarded or played Card discarded{}; // Index of card in hand that was discarded or played - std::uint8_t index{}; + hand_index_t index{}; // Multiplicity of new draw (needed for probability calculations) - std::uint8_t multiplicity{}; + hand_index_t multiplicity{}; }; class HanabiStateIF { @@ -125,14 +124,14 @@ public: virtual double backtrack(size_t depth) = 0; virtual void clue() = 0; - virtual BacktrackAction discard(std::uint8_t index) = 0; - virtual BacktrackAction play(std::uint8_t index) = 0; + virtual BacktrackAction discard(hand_index_t index) = 0; + virtual BacktrackAction play(hand_index_t index) = 0; virtual void revert_clue() = 0; virtual void revert_play(const BacktrackAction &action, bool was_on_8_clues) = 0; virtual void revert_discard(const BacktrackAction &action) = 0; - [[nodiscard]] virtual std::uint8_t find_card_in_hand(const Card& card) const = 0; + [[nodiscard]] virtual hand_index_t find_card_in_hand(const Card& card) const = 0; [[nodiscard]] virtual bool is_trash(const Card& card) const = 0; [[nodiscard]] virtual bool is_playable(const Card& card) const = 0; @@ -148,7 +147,7 @@ protected: friend std::ostream& operator<<(std::ostream&, HanabiStateIF const&); }; -template +template class HanabiState : public HanabiStateIF { public: HanabiState() = default; @@ -157,14 +156,14 @@ public: double backtrack(size_t depth) final; void clue() final; - BacktrackAction play(std::uint8_t index) final; - BacktrackAction discard(std::uint8_t index) final; + BacktrackAction play(hand_index_t index) final; + BacktrackAction discard(hand_index_t index) final; void revert_clue() final; void revert_play(const BacktrackAction &action, bool was_on_8_clues) final; void revert_discard(const BacktrackAction &action) final; - [[nodiscard]] std::uint8_t find_card_in_hand(const Card& card) const final; + [[nodiscard]] hand_index_t find_card_in_hand(const Card& card) const final; [[nodiscard]] bool is_trash(const Card& card) const final; [[nodiscard]] bool is_playable(const Card& card) const final; @@ -178,8 +177,8 @@ protected: void print(std::ostream& os) const final; private: - uint8_t draw(uint8_t index); - void revert_draw(std::uint8_t index, Card discarded_card); + hand_index_t draw(hand_index_t index); + void revert_draw(hand_index_t index, Card discarded_card); void incr_turn(); void decr_turn(); diff --git a/game_state.hpp b/game_state.hpp index 936c54a..8375a76 100644 --- a/game_state.hpp +++ b/game_state.hpp @@ -22,7 +22,12 @@ namespace Hanabi { return ret; } - template + std::ostream &operator<<(std::ostream &os, const Card &card) { + os << suit_initials[card.suit] << 5 - card.rank; + return os; + } + + template std::ostream &operator<<(std::ostream &os, const Stacks &stacks) { for (size_t i = 0; i < stacks.size() - 1; i++) { os << starting_card_rank - stacks[i] << ", "; @@ -31,7 +36,7 @@ namespace Hanabi { return os; } - template + template CardArray::CardArray(T default_val) { for(size_t suit = 0; suit < num_suits; suit++) { for (rank_t rank = 0; rank < starting_card_rank; rank++) { @@ -40,17 +45,17 @@ namespace Hanabi { } } - template + template const T& CardArray::operator[](const Card &card) const { return _array[card.suit][card.rank]; }; - template + template T& CardArray::operator[](const Card &card) { return _array[card.suit][card.rank]; }; - template + template HanabiState::HanabiState(const std::vector &deck): _turn(0), _num_clues(max_num_clues), @@ -74,7 +79,7 @@ namespace Hanabi { ASSERT(_turn == 0); } - template + template void HanabiState::clue() { ASSERT(_num_clues > 0); --_num_clues; @@ -82,7 +87,7 @@ namespace Hanabi { incr_turn(); } - template + template void HanabiState::incr_turn() { _turn = (_turn + 1) % num_players; if(_endgame_turns_left != no_endgame) { @@ -90,7 +95,7 @@ namespace Hanabi { } } - template + template void HanabiState::decr_turn() { _turn = (_turn + num_players - 1) % num_players; if (_endgame_turns_left != no_endgame) { @@ -98,22 +103,22 @@ namespace Hanabi { } } - template + template bool HanabiState::is_playable(const Hanabi::Card &card) const { return card.rank == _stacks[card.suit] - 1; } - template + template std::uint64_t HanabiState::enumerated_states() const { return _enumerated_states; } - template + template bool HanabiState::is_trash(const Hanabi::Card &card) const { return card.rank >= _stacks[card.suit]; } - template + template BacktrackAction HanabiState::play( std::uint8_t index) { ASSERT(index < _hands[_turn].size()); @@ -134,7 +139,7 @@ namespace Hanabi { return ret; } - template + template BacktrackAction HanabiState::discard(std::uint8_t index) { ASSERT(index < _hands[_turn].size()); ASSERT(_num_clues != max_num_clues); @@ -149,7 +154,7 @@ namespace Hanabi { return ret; } - template + template std::uint8_t HanabiState::find_card_in_hand( const Hanabi::Card &card) const { for(std::uint8_t i = 0; i < hand_size; i++) { @@ -160,9 +165,9 @@ namespace Hanabi { return -1; } - template + template void HanabiState::print(std::ostream &os) const { - os << "Stacks: " << _stacks << " (score " << +_score << ")"; +// os << "Stacks: " << _stacks << " (score " << +_score << ")"; os << ", clues: " << +_num_clues << ", turn: " << +_turn << std::endl; os << "Draw pile: "; for (const auto &[card, mul]: _draw_pile) { @@ -182,7 +187,7 @@ namespace Hanabi { } } - template + template std::uint8_t HanabiState::draw(uint8_t index) { ASSERT(index < _hands[_turn].size()); @@ -210,7 +215,7 @@ namespace Hanabi { return 0; } - template + template void HanabiState::revert_draw(std::uint8_t index, Card discarded_card) { if (_endgame_turns_left == num_players + 1 || _endgame_turns_left == no_endgame) { // Put the card that is currently in hand back into the draw pile @@ -230,7 +235,7 @@ namespace Hanabi { _hands[_turn][index] = discarded_card; } - template + template void HanabiState::normalize_draw_and_positions() { const Card trash = [this]() -> Card { for(suit_t suit = 0; suit < num_suits; suit++) { @@ -263,7 +268,7 @@ namespace Hanabi { _draw_pile.push_back({trash, num_trash_in_draw_pile}); } - template + template void HanabiState::revert_play(const BacktrackAction& action, bool was_on_8_clues) { ASSERT(!was_on_8_clues or _num_clues == 8); decr_turn(); @@ -275,7 +280,7 @@ namespace Hanabi { _score--; } - template + template void HanabiState::revert_discard(const BacktrackAction& action) { decr_turn(); ASSERT(_num_clues > 0); @@ -284,7 +289,7 @@ namespace Hanabi { revert_draw(action.index, action.discarded); } - template + template void HanabiState::revert_clue() { decr_turn(); ASSERT(_num_clues < max_num_clues); @@ -297,7 +302,7 @@ namespace Hanabi { return best_probability; \ } - template + template double HanabiState::backtrack(size_t depth) { _enumerated_states++; if (_score == 5 * num_suits) { diff --git a/main.cpp b/main.cpp index 5fe8214..b088764 100644 --- a/main.cpp +++ b/main.cpp @@ -14,35 +14,39 @@ namespace Hanabi { + void download(int game_id, int turn) { + auto game = Download::get_game(game_id, turn); + std::cout << "Analysing state: " << *game << std::endl; + auto res = game->backtrack(1); + std::cout.precision(10); + std::cout << "Probability with optimal play: " << res << std::endl; + std::cout << "Enumerated " << game->enumerated_states() << " states" << std::endl; + } -void download(int turn) { - auto game = Download::get_game("1004116", turn); - std::cout << "Analysing state: " << *game << std::endl; - auto res = game->backtrack(1); - std::cout.precision(10); - std::cout << "Probability with optimal play: " << res << std::endl; - std::cout << "Enumerated " << game->enumerated_states() << " states" << std::endl; -} + void print_sizes() { + std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4>) + << std::endl; -void print_sizes() { - std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4>) - << std::endl; + unsigned exp = 32; + std::cout << "Pair size: " << sizeof(std::pair) + << std::endl; + std::cout << sizeof(boost::rational) << std::endl; + std::cout << (1ul << exp) << std::endl; + } - unsigned exp = 32; - std::cout << "Pair size: " << sizeof(std::pair) - << std::endl; - std::cout << sizeof(boost::rational) << std::endl; - std::cout << (1ul << exp) << std::endl; -} + void print_usage(const char* program_name) { + std::cout << "Usage: " << program_name << " GAME_ID TURN" << std::endl; + } } int main(int argc, char *argv[]) { -// Hanabi::test_game(); - if(argc == 2) { - std::string turn (argv[1]); - Hanabi::download(std::stoi(turn)); + if(argc == 3) { + std::string game (argv[1]); + std::string turn (argv[2]); + Hanabi::download(std::stoi(game), std::stoi(turn)); + } else { + Hanabi::print_usage(argv[0]); } - return 0; } \ No newline at end of file