implement downloading games and parsing deck

This commit is contained in:
Maximilian Keßler 2023-08-05 00:34:31 +02:00
parent 362d121930
commit 262d909f3d
Signed by: max
GPG key ID: BCC5A619923C0BA5
3 changed files with 130 additions and 44 deletions

76
download.h Normal file
View file

@ -0,0 +1,76 @@
#ifndef DYNAMIC_PROGRAM_DOWNLOAD_H
#define DYNAMIC_PROGRAM_DOWNLOAD_H
#include <boost/json.hpp>
#include <boost/json/src.hpp>
#include <cpr/cpr.h>
#include <iostream>
#include "game_state.h"
// This helper function deduces the type and assigns the value with the matching key
template<class T>
void extract( boost::json::object const& obj, T& t, std::string_view key )
{
t = value_to<T>( obj.at( key ) );
}
namespace Hanabi {
Card tag_invoke(boost::json::value_to_tag<Card>,
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<Hanabi::Card> parse_deck(const boost::json::value& deck_json) {
auto deck = boost::json::value_to<std::vector<Hanabi::Card>>(deck_json);
std::array<std::array<Hanabi::rank_t, 5>, 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

View file

@ -17,6 +17,8 @@
#include <ostream> #include <ostream>
namespace Hanabi {
using rank_t = std::uint8_t; using rank_t = std::uint8_t;
using suit_t = std::uint8_t; using suit_t = std::uint8_t;
using clue_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; using state_t = std::uint32_t;
/** /**
* We will generally assume that stacks are played from n to 0 * We will generally assume that stacks are played from n to 0
* Playing a 0 will yield a clue * Playing a 0 will yield a clue
@ -46,6 +47,7 @@ struct Card {
suit_t suit; suit_t suit;
rank_t rank; rank_t rank;
uint8_t copy; uint8_t copy;
uint8_t index; // index of card in the deck
Card &operator++(); Card &operator++();
Card successor() const; Card successor() const;
@ -78,8 +80,7 @@ constexpr Card y4 = {1, 4, 0};
* - Number of clues * - Number of clues
*/ */
template<std::size_t num_suits> template <std::size_t num_suits> using Stacks = std::array<rank_t, num_suits>;
using Stacks = std::array<rank_t, num_suits>;
template <std::size_t num_suits> template <std::size_t num_suits>
std::ostream &operator<<(std::ostream &os, const Stacks<num_suits> &stacks); std::ostream &operator<<(std::ostream &os, const Stacks<num_suits> &stacks);
@ -91,8 +92,7 @@ struct CardMultiplicity {
auto operator<=>(const CardMultiplicity &) const = default; auto operator<=>(const CardMultiplicity &) const = default;
}; };
template<std::size_t num_suits> template <std::size_t num_suits> struct CardPositions {
struct CardPositions {
const player_t &operator[](const Card &card) const; const player_t &operator[](const Card &card) const;
@ -101,14 +101,13 @@ struct CardPositions {
auto operator<=>(const CardPositions &) const = default; auto operator<=>(const CardPositions &) const = default;
private: private:
std::array<std::array<std::array<player_t, max_card_duplicity>, starting_card_rank>, num_suits> _card_positions; std::array<
std::array<std::array<player_t, max_card_duplicity>, starting_card_rank>,
num_suits>
_card_positions;
}; };
enum class ActionType { enum class ActionType { discard, clue, play };
discard,
clue,
play
};
struct Action { struct Action {
ActionType type{}; ActionType type{};
@ -116,11 +115,10 @@ struct Action {
std::uint8_t index{}; std::uint8_t index{};
}; };
template <std::size_t num_suits, std::size_t num_players, std::size_t hand_size,
template <std::size_t num_suits, std::size_t num_players, std::size_t hand_size, std::uint8_t max_draw_pile_size> std::uint8_t max_draw_pile_size>
class HanabiState { class HanabiState {
public: public:
Action clue(); Action clue();
/** /**
* Plays a card from current hand, drawing top card of draw pile and rotating draw pile * Plays a card from current hand, drawing top card of draw pile and rotating draw pile
@ -132,7 +130,6 @@ public:
void revert(const Action &action); void revert(const Action &action);
void draw(std::uint8_t index); void draw(std::uint8_t index);
void revert_draw(std::uint8_t index, Card card); void revert_draw(std::uint8_t index, Card card);
void incr_turn(); void incr_turn();
@ -142,7 +139,8 @@ public:
clue_t _num_clues{}; clue_t _num_clues{};
std::uint8_t _draw_pile_size{}; std::uint8_t _draw_pile_size{};
Stacks<num_suits> _stacks{}; Stacks<num_suits> _stacks{};
std::array<boost::container::static_vector<Card, hand_size>, num_players> _hands {}; std::array<boost::container::static_vector<Card, hand_size>, num_players>
_hands{};
CardPositions<num_suits> _card_positions{}; CardPositions<num_suits> _card_positions{};
std::list<CardMultiplicity> _draw_pile{}; std::list<CardMultiplicity> _draw_pile{};
@ -152,11 +150,17 @@ public:
auto operator<=>(const HanabiState &) const = default; auto operator<=>(const HanabiState &) const = default;
}; };
template <std::size_t num_suits, std::size_t num_players, std::size_t hand_size, std::uint8_t max_draw_pile_size> template <std::size_t num_suits, std::size_t num_players, std::size_t hand_size,
std::ostream& operator<<(std::ostream& os, HanabiState<num_suits, num_players, hand_size, max_draw_pile_size> hanabi_state); std::uint8_t max_draw_pile_size>
std::ostream &
operator<<(std::ostream &os,
HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>
hanabi_state);
#include "game_state.hpp" #include "game_state.hpp"
template class HanabiState<5, 3, 4, 20>; template class HanabiState<5, 3, 4, 20>;
}
#endif // DYNAMIC_PROGRAM_GAME_STATE_H #endif // DYNAMIC_PROGRAM_GAME_STATE_H

View file

@ -9,7 +9,9 @@
#include <vector> #include <vector>
#include "game_state.h" #include "game_state.h"
#include "download.h"
namespace Hanabi {
void test_game() { void test_game() {
HanabiState<2, 2, 5, 10> state; HanabiState<2, 2, 5, 10> state;
@ -36,20 +38,24 @@ void test_game() {
assert(state == state2); assert(state == state2);
} }
void print_sizes() { void download() { download_game(1000000); }
std::cout << "size of card -> hand map: " << sizeof(HanabiState<5,3,4, 5>) << std::endl;
CardSetSpecification<5> test; void print_sizes() {
std::cout << sizeof(CardSetSpecification<8>::AdditionalCardsFlags) << std::endl; std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4, 5>)
<< std::endl;
unsigned exp = 32; unsigned exp = 32;
std::cout << "Pair size: " << sizeof(std::pair<std::uint32_t, float>) << std::endl; std::cout << "Pair size: " << sizeof(std::pair<std::uint32_t, float>)
<< std::endl;
std::cout << sizeof(boost::rational<int>) << std::endl; std::cout << sizeof(boost::rational<int>) << std::endl;
std::cout << (1ul << exp) << std::endl; std::cout << (1ul << exp) << std::endl;
} }
}
int main() { int main() {
test_game(); // Hanabi::test_game();
Hanabi::download();
return 0; return 0;
} }