From 262d909f3d5b0424a7625fd3426e817385062dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Ke=C3=9Fler?= Date: Sat, 5 Aug 2023 00:34:31 +0200 Subject: [PATCH] implement downloading games and parsing deck --- download.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ game_state.h | 78 +++++++++++++++++++++++++++------------------------- main.cpp | 20 +++++++++----- 3 files changed, 130 insertions(+), 44 deletions(-) create mode 100644 download.h diff --git a/download.h b/download.h new file mode 100644 index 0000000..ce27b4a --- /dev/null +++ b/download.h @@ -0,0 +1,76 @@ +#ifndef DYNAMIC_PROGRAM_DOWNLOAD_H +#define DYNAMIC_PROGRAM_DOWNLOAD_H + +#include +#include +#include +#include + +#include "game_state.h" + + +// This helper function deduces the type and assigns the value with the matching key +template +void extract( boost::json::object const& obj, T& t, std::string_view key ) +{ + t = value_to( obj.at( key ) ); +} + +namespace Hanabi { + Card tag_invoke(boost::json::value_to_tag, + boost::json::value const &jv) { + Hanabi::Card card{}; + boost::json::object const &obj = jv.as_object(); + extract(obj, card.rank, "rank"); + extract(obj, card.suit, "suitIndex"); + card.rank = 5 - card.rank; + return card; + } + + void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, Hanabi::Card const &card) { + jv = {{"suitIndex", card.suit}, {"rank", card.rank}}; + } +} + + +std::vector parse_deck(const boost::json::value& deck_json) { + auto deck = boost::json::value_to>(deck_json); + std::array, 6> next_copy_indices {}; + for(size_t i = 0; i < deck.size(); i++) { + auto &card = deck[i]; + assert(card.rank < 5); + assert(card.rank >= 0); + assert(card.suit < 6); + assert(card.suit >= 0); + card.index = i; + card.copy = next_copy_indices[card.suit][card.rank]; + next_copy_indices[card.suit][card.rank]++; + } + return deck; +} + +boost::json::object download_game_json(int game_id) { + std::string request_str = "https://hanab.live/export/" + std::to_string(game_id); + cpr::Response r = cpr::Get(cpr::Url(request_str)); + if (r.header["content-type"] != "application/json; charset=utf-8") { + return {}; + } + 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; + } + std::cout << num_players; +} + + + + +#endif // DYNAMIC_PROGRAM_DOWNLOAD_H diff --git a/game_state.h b/game_state.h index 586a1e0..d97746d 100644 --- a/game_state.h +++ b/game_state.h @@ -17,6 +17,8 @@ #include +namespace Hanabi { + using rank_t = std::uint8_t; using suit_t = std::uint8_t; using clue_t = std::uint8_t; @@ -24,7 +26,6 @@ using player_t = std::int8_t; using state_t = std::uint32_t; - /** * We will generally assume that stacks are played from n to 0 * Playing a 0 will yield a clue @@ -40,21 +41,22 @@ 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"}; struct Card { suit_t suit; rank_t rank; uint8_t copy; + uint8_t index; // index of card in the deck - Card& operator++(); + Card &operator++(); Card successor() const; const Card operator++(int); - auto operator<=>(const Card&) const = default; + auto operator<=>(const Card &) const = default; }; -std::ostream& operator<<(std::ostream& os, const Card& card) { +std::ostream &operator<<(std::ostream &os, const Card &card) { os << suit_initials[card.suit] << +card.rank; return os; } @@ -78,49 +80,45 @@ constexpr Card y4 = {1, 4, 0}; * - Number of clues */ -template -using Stacks = std::array; +template using Stacks = std::array; -template -std::ostream& operator<<(std::ostream& os, const Stacks& stacks); +template +std::ostream &operator<<(std::ostream &os, const Stacks &stacks); struct CardMultiplicity { Card card; std::uint8_t multiplicity; - auto operator<=>(const CardMultiplicity&) const = default; + auto operator<=>(const CardMultiplicity &) const = default; }; -template -struct CardPositions { +template struct CardPositions { - const player_t & operator[](const Card& card) const; + const player_t &operator[](const Card &card) const; - player_t & operator[](const Card& card); + player_t &operator[](const Card &card); - auto operator<=>(const CardPositions&) const = default; + auto operator<=>(const CardPositions &) const = default; private: - std::array, starting_card_rank>, num_suits> _card_positions; + std::array< + std::array, starting_card_rank>, + num_suits> + _card_positions; }; -enum class ActionType { - discard, - clue, - play -}; +enum class ActionType { discard, clue, play }; struct Action { - ActionType type {}; - Card discarded {}; - std::uint8_t index {}; + ActionType type{}; + Card discarded{}; + std::uint8_t index{}; }; - -template +template class HanabiState { public: - Action clue(); /** * Plays a card from current hand, drawing top card of draw pile and rotating draw pile @@ -130,8 +128,7 @@ public: Action discard(std::uint8_t index); - void revert(const Action& action); - + void revert(const Action &action); void draw(std::uint8_t index); void revert_draw(std::uint8_t index, Card card); @@ -141,22 +138,29 @@ public: player_t _turn{}; clue_t _num_clues{}; std::uint8_t _draw_pile_size{}; - Stacks _stacks {}; - std::array, num_players> _hands {}; - CardPositions _card_positions {}; - std::list _draw_pile {}; + Stacks _stacks{}; + std::array, num_players> + _hands{}; + CardPositions _card_positions{}; + std::list _draw_pile{}; // further statistics that we might want to keep track of uint8_t _pace{}; - auto operator<=>(const HanabiState&) const = default; + auto operator<=>(const HanabiState &) const = default; }; -template -std::ostream& operator<<(std::ostream& os, HanabiState hanabi_state); +template +std::ostream & +operator<<(std::ostream &os, + HanabiState + hanabi_state); #include "game_state.hpp" template class HanabiState<5, 3, 4, 20>; -#endif // DYNAMIC_PROGRAM_GAME_STATE_H +} + +#endif // DYNAMIC_PROGRAM_GAME_STATE_H \ No newline at end of file diff --git a/main.cpp b/main.cpp index e31ebee..4825e28 100644 --- a/main.cpp +++ b/main.cpp @@ -9,13 +9,15 @@ #include #include "game_state.h" +#include "download.h" +namespace Hanabi { void test_game() { HanabiState<2, 2, 5, 10> state; state._stacks[0] = 2; state._stacks[1] = 3; - Card r41 = {0,4,1}; + Card r41 = {0, 4, 1}; state._draw_pile.push_back({r41, 1}); state._hands[0] = {y0, y1, y2, r0, r1}; state._hands[1] = {r1, r1, y1, r3, r2}; @@ -36,20 +38,24 @@ void test_game() { assert(state == state2); } -void print_sizes() { - std::cout << "size of card -> hand map: " << sizeof(HanabiState<5,3,4, 5>) << std::endl; +void download() { download_game(1000000); } - CardSetSpecification<5> test; - std::cout << sizeof(CardSetSpecification<8>::AdditionalCardsFlags) << std::endl; +void print_sizes() { + std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4, 5>) + << std::endl; unsigned exp = 32; - std::cout << "Pair size: " << sizeof(std::pair) << std::endl; + std::cout << "Pair size: " << sizeof(std::pair) + << std::endl; std::cout << sizeof(boost::rational) << std::endl; std::cout << (1ul << exp) << std::endl; } +} + int main() { - test_game(); +// Hanabi::test_game(); + Hanabi::download(); return 0; } \ No newline at end of file