diff --git a/download.h b/download.h index ce27b4a..6d374cc 100644 --- a/download.h +++ b/download.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "game_state.h" @@ -58,15 +60,27 @@ boost::json::object download_game_json(int game_id) { return boost::json::parse(r.text).as_object(); } -void download_game(int game_id) { - boost::json::object game = download_game_json(game_id); - std::cout << game << std::endl; - const auto deck = parse_deck(game.at("deck")); - const unsigned num_players = game.at("players").as_array().size(); - - for(const auto& card : deck) { - std::cout << card << std::endl; +boost::json::object open_game_json(const char* filename) { + std::ifstream file(filename); + if (!file.is_open()) { + std::cout << "Failed to open " << filename << "." << std::endl; + return {}; } + std::string game_json ((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + return boost::json::parse(game_json).as_object(); +} + +void get_game(std::variant game_spec) { + const boost::json::object game = [&game_spec](){ + if (game_spec.index() == 0) { + return download_game_json(std::get(game_spec)); + } else { + return open_game_json(std::get(game_spec)); + } + }(); + const std::vector deck = parse_deck(game.at("deck")); + const unsigned num_players = game.at("players").as_array().size(); + std::cout << deck.size() << std::endl; std::cout << num_players; } diff --git a/game_state.h b/game_state.h index d97746d..388517e 100644 --- a/game_state.h +++ b/game_state.h @@ -1,7 +1,3 @@ -// -// Created by maximilian on 7/13/23. -// - #ifndef DYNAMIC_PROGRAM_GAME_STATE_H #define DYNAMIC_PROGRAM_GAME_STATE_H @@ -41,7 +37,7 @@ constexpr player_t draw_pile = -1; constexpr player_t trash_or_play_stack = -2; constexpr clue_t max_num_clues = 8; -constexpr std::array suit_initials{"r", "y", "g", "b", "p"}; +constexpr std::array suit_initials{"r", "y", "g", "b", "p", "t"}; struct Card { suit_t suit; @@ -157,10 +153,11 @@ operator<<(std::ostream &os, HanabiState hanabi_state); -#include "game_state.hpp" template class HanabiState<5, 3, 4, 20>; } +#include "game_state.hpp" + #endif // DYNAMIC_PROGRAM_GAME_STATE_H \ No newline at end of file diff --git a/game_state.hpp b/game_state.hpp index 36b3180..197ea40 100644 --- a/game_state.hpp +++ b/game_state.hpp @@ -2,176 +2,181 @@ #include #include +namespace Hanabi { -Card& Card::operator++() { - rank++; - return *this; -} - -Card Card::successor() const { - return {suit, static_cast(rank + 1)}; -} - -const Card Card::operator++(int) { - Card ret = *this; - rank++; - return ret; -} - -template -std::ostream& operator<<(std::ostream& os, const Stacks& stacks) { - for (size_t i = 0; i < stacks.size() - 1; i++) { - os << +stacks[i] << ", "; - } - os << +stacks.back(); - return os; -} - -template -const player_t & CardPositions::operator[](const Card& card) const { - return _card_positions[card.suit][card.rank][card.copy]; -}; - -template -player_t & CardPositions::operator[](const Card& card) { - return _card_positions[card.suit][card.rank][card.copy]; -}; - -template -Action HanabiState::clue() { - assert(_num_clues > 0); - --_num_clues; - - incr_turn(); - - return Action {ActionType::clue, {}, {}}; -} - -template -void HanabiState::incr_turn() { - _turn = (_turn + 1) % num_players; -} - -template -void HanabiState::decr_turn() { - _turn = (_turn + num_players - 1) % num_players; -} - -template -Action HanabiState::play(std::uint8_t index) { - assert(index < _hands[_turn].size()); - const Card card = _hands[_turn][index]; - assert(card.rank == _stacks[card.suit] - 1); - - --_stacks[card.suit]; - - Action ret {ActionType::play, _hands[_turn][index], index}; - - if (card.rank == 0) { - // update clues if we played the last card of a stack - _num_clues++; - } - - draw(index); - incr_turn(); - - return ret; -} - -template -Action HanabiState::discard(std::uint8_t index) { - assert(index < _hands[_turn].size()); - assert(_num_clues != max_num_clues); - - _num_clues++; - - Action ret {ActionType::discard, _hands[_turn][index], index}; - - draw(index); - incr_turn(); - - return ret; -} - - -template -std::ostream& operator<<(std::ostream& os, const HanabiState hanabi_state) { - os << "Stacks: " << hanabi_state._stacks << std::endl; - os << "Draw pile: "; - for (const auto &[card, mul] : hanabi_state._draw_pile) { - os << card; - if (mul > 1) { - os << " (" << +mul << ")"; - } - } - os << std::endl; - os << "Hands: "; - for (const auto& hand: hanabi_state._hands) { - for (const auto &card: hand) { - os << card << ", "; - } - os << " | "; - } - return os; -} - -template -void HanabiState::draw(std::uint8_t index) { - assert(index < _hands[_turn].size()); - - _card_positions[_hands[_turn][index]] = trash_or_play_stack; - - // draw a new card if the draw pile is not empty - if (!_draw_pile.empty()) { - --_draw_pile_size; - CardMultiplicity draw = _draw_pile.front(); - _draw_pile.pop_front(); - assert(draw.multiplicity > 0); - if (draw.multiplicity > 1) { - draw.multiplicity--; - _draw_pile.push_back(draw); + Card &Card::operator++() { + rank++; + return *this; } - _hands[_turn][index] = draw.card; - _card_positions[draw.card] = _turn; - } -} -template -void HanabiState::revert_draw(std::uint8_t index, Card card) { - assert(index < _hands[_turn].size()); + Card Card::successor() const { return {suit, static_cast(rank + 1)}; } - _card_positions[_hands[_turn][index]] = draw_pile; + const Card Card::operator++(int) { + Card ret = *this; + rank++; + return ret; + } - // draw a new card if the draw pile is not empty - if (_draw_pile.back().card == _hands[_turn][index]) { - _draw_pile.back().multiplicity++; - } else { - _draw_pile.push_back({_hands[_turn][index], 1}); - } + template + std::ostream &operator<<(std::ostream &os, const Stacks &stacks) { + for (size_t i = 0; i < stacks.size() - 1; i++) { + os << +stacks[i] << ", "; + } + os << +stacks.back(); + return os; + } - _hands[_turn][index] = card; - _card_positions[card] = _turn; - _draw_pile_size++; -} + template + const player_t &CardPositions::operator[](const Card &card) const { + return _card_positions[card.suit][card.rank][card.copy]; + }; -template -void HanabiState::revert(const Action &action) { - decr_turn(); - switch (action.type) { - case ActionType::clue: - assert(_num_clues < max_num_clues); - _num_clues++; - break; - case ActionType::discard: - assert(_num_clues > 0); - _num_clues--; - revert_draw(action.index, action.discarded); - break; - case ActionType::play: - if (action.discarded.rank == 0) { - _num_clues--; - } - revert_draw(action.index, action.discarded); - _stacks[action.discarded.suit]++; - } -} + template + player_t &CardPositions::operator[](const Card &card) { + return _card_positions[card.suit][card.rank][card.copy]; + }; + + template + Action HanabiState::clue() { + assert(_num_clues > 0); + --_num_clues; + + incr_turn(); + + return Action{ActionType::clue, {}, {}}; + } + + template + void HanabiState::incr_turn() { + _turn = (_turn + 1) % num_players; + } + + template + void HanabiState::decr_turn() { + _turn = (_turn + num_players - 1) % num_players; + } + + template + Action HanabiState::play( + std::uint8_t index) { + assert(index < _hands[_turn].size()); + const Card card = _hands[_turn][index]; + assert(card.rank == _stacks[card.suit] - 1); + + --_stacks[card.suit]; + + Action ret{ActionType::play, _hands[_turn][index], index}; + + if (card.rank == 0) { + // update clues if we played the last card of a stack + _num_clues++; + } + + draw(index); + incr_turn(); + + return ret; + } + + template + Action HanabiState::discard( + std::uint8_t index) { + assert(index < _hands[_turn].size()); + assert(_num_clues != max_num_clues); + + _num_clues++; + + Action ret{ActionType::discard, _hands[_turn][index], index}; + + draw(index); + incr_turn(); + + return ret; + } + + template + std::ostream &operator<<(std::ostream &os, const HanabiState hanabi_state) { + os << "Stacks: " << hanabi_state._stacks << std::endl; + os << "Draw pile: "; + for (const auto &[card, mul]: hanabi_state._draw_pile) { + os << card; + if (mul > 1) { + os << " (" << +mul << ")"; + } + } + os << std::endl; + os << "Hands: "; + for (const auto &hand: hanabi_state._hands) { + for (const auto &card: hand) { + os << card << ", "; + } + os << " | "; + } + return os; + } + + template + void HanabiState::draw(std::uint8_t index) { + assert(index < _hands[_turn].size()); + + _card_positions[_hands[_turn][index]] = trash_or_play_stack; + + // draw a new card if the draw pile is not empty + if (!_draw_pile.empty()) { + --_draw_pile_size; + CardMultiplicity draw = _draw_pile.front(); + _draw_pile.pop_front(); + assert(draw.multiplicity > 0); + if (draw.multiplicity > 1) { + draw.multiplicity--; + _draw_pile.push_back(draw); + } + _hands[_turn][index] = draw.card; + _card_positions[draw.card] = _turn; + } + } + + template + void HanabiState::revert_draw(std::uint8_t index, Card card) { + assert(index < _hands[_turn].size()); + + _card_positions[_hands[_turn][index]] = draw_pile; + + // draw a new card if the draw pile is not empty + if (_draw_pile.back().card == _hands[_turn][index]) { + _draw_pile.back().multiplicity++; + } else { + _draw_pile.push_back({_hands[_turn][index], 1}); + } + + _hands[_turn][index] = card; + _card_positions[card] = _turn; + _draw_pile_size++; + } + + template + void HanabiState::revert( + const Action &action) { + decr_turn(); + switch (action.type) { + case ActionType::clue: + assert(_num_clues < max_num_clues); + _num_clues++; + break; + case ActionType::discard: + assert(_num_clues > 0); + _num_clues--; + revert_draw(action.index, action.discarded); + break; + case ActionType::play: + if (action.discarded.rank == 0) { + _num_clues--; + } + revert_draw(action.index, action.discarded); + _stacks[action.discarded.suit]++; + } + } + +} // namespace Hanabi \ No newline at end of file diff --git a/main.cpp b/main.cpp index 4825e28..1d6aece 100644 --- a/main.cpp +++ b/main.cpp @@ -38,7 +38,7 @@ void test_game() { assert(state == state2); } -void download() { download_game(1000000); } +void download() { get_game("314159.json"); } void print_sizes() { std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4, 5>)