implement downloading games and parsing deck
This commit is contained in:
parent
362d121930
commit
262d909f3d
3 changed files with 130 additions and 44 deletions
76
download.h
Normal file
76
download.h
Normal 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
|
76
game_state.h
76
game_state.h
|
@ -17,6 +17,8 @@
|
|||
#include <ostream>
|
||||
|
||||
|
||||
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<std::string, 5> suit_initials {"r", "y", "g", "b", "p"};
|
||||
constexpr std::array<std::string, 5> 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<std::size_t num_suits>
|
||||
using Stacks = std::array<rank_t, num_suits>;
|
||||
template <std::size_t num_suits> using Stacks = std::array<rank_t, num_suits>;
|
||||
|
||||
template<std::size_t num_suits>
|
||||
std::ostream& operator<<(std::ostream& os, const Stacks<num_suits>& stacks);
|
||||
template <std::size_t num_suits>
|
||||
std::ostream &operator<<(std::ostream &os, const Stacks<num_suits> &stacks);
|
||||
|
||||
struct CardMultiplicity {
|
||||
Card card;
|
||||
std::uint8_t multiplicity;
|
||||
|
||||
auto operator<=>(const CardMultiplicity&) const = default;
|
||||
auto operator<=>(const CardMultiplicity &) const = default;
|
||||
};
|
||||
|
||||
template<std::size_t num_suits>
|
||||
struct CardPositions {
|
||||
template <std::size_t num_suits> 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<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 {
|
||||
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 <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::uint8_t max_draw_pile_size>
|
||||
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<num_suits> _stacks {};
|
||||
std::array<boost::container::static_vector<Card, hand_size>, num_players> _hands {};
|
||||
CardPositions<num_suits> _card_positions {};
|
||||
std::list<CardMultiplicity> _draw_pile {};
|
||||
Stacks<num_suits> _stacks{};
|
||||
std::array<boost::container::static_vector<Card, hand_size>, num_players>
|
||||
_hands{};
|
||||
CardPositions<num_suits> _card_positions{};
|
||||
std::list<CardMultiplicity> _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::size_t num_suits, std::size_t num_players, std::size_t hand_size, 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);
|
||||
template <std::size_t num_suits, std::size_t num_players, std::size_t hand_size,
|
||||
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"
|
||||
|
||||
template class HanabiState<5, 3, 4, 20>;
|
||||
|
||||
}
|
||||
|
||||
#endif // DYNAMIC_PROGRAM_GAME_STATE_H
|
20
main.cpp
20
main.cpp
|
@ -9,13 +9,15 @@
|
|||
#include <vector>
|
||||
|
||||
#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::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 << (1ul << exp) << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_game();
|
||||
// Hanabi::test_game();
|
||||
Hanabi::download();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue