implement reading from file. cleanup
This commit is contained in:
parent
262d909f3d
commit
3b993030ea
4 changed files with 197 additions and 181 deletions
30
download.h
30
download.h
|
@ -5,6 +5,8 @@
|
||||||
#include <boost/json/src.hpp>
|
#include <boost/json/src.hpp>
|
||||||
#include <cpr/cpr.h>
|
#include <cpr/cpr.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include "game_state.h"
|
#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();
|
return boost::json::parse(r.text).as_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
void download_game(int game_id) {
|
boost::json::object open_game_json(const char* filename) {
|
||||||
boost::json::object game = download_game_json(game_id);
|
std::ifstream file(filename);
|
||||||
std::cout << game << std::endl;
|
if (!file.is_open()) {
|
||||||
const auto deck = parse_deck(game.at("deck"));
|
std::cout << "Failed to open " << filename << "." << std::endl;
|
||||||
const unsigned num_players = game.at("players").as_array().size();
|
return {};
|
||||||
|
|
||||||
for(const auto& card : deck) {
|
|
||||||
std::cout << card << std::endl;
|
|
||||||
}
|
}
|
||||||
|
std::string game_json ((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||||
|
return boost::json::parse(game_json).as_object();
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_game(std::variant<int, const char*> game_spec) {
|
||||||
|
const boost::json::object game = [&game_spec](){
|
||||||
|
if (game_spec.index() == 0) {
|
||||||
|
return download_game_json(std::get<int>(game_spec));
|
||||||
|
} else {
|
||||||
|
return open_game_json(std::get<const char*>(game_spec));
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
const std::vector<Hanabi::Card> 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;
|
std::cout << num_players;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// Created by maximilian on 7/13/23.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DYNAMIC_PROGRAM_GAME_STATE_H
|
#ifndef DYNAMIC_PROGRAM_GAME_STATE_H
|
||||||
#define 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 player_t trash_or_play_stack = -2;
|
||||||
constexpr clue_t max_num_clues = 8;
|
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, 6> suit_initials{"r", "y", "g", "b", "p", "t"};
|
||||||
|
|
||||||
struct Card {
|
struct Card {
|
||||||
suit_t suit;
|
suit_t suit;
|
||||||
|
@ -157,10 +153,11 @@ operator<<(std::ostream &os,
|
||||||
HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>
|
HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>
|
||||||
hanabi_state);
|
hanabi_state);
|
||||||
|
|
||||||
#include "game_state.hpp"
|
|
||||||
|
|
||||||
template class HanabiState<5, 3, 4, 20>;
|
template class HanabiState<5, 3, 4, 20>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "game_state.hpp"
|
||||||
|
|
||||||
#endif // DYNAMIC_PROGRAM_GAME_STATE_H
|
#endif // DYNAMIC_PROGRAM_GAME_STATE_H
|
337
game_state.hpp
337
game_state.hpp
|
@ -2,176 +2,181 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace Hanabi {
|
||||||
|
|
||||||
Card& Card::operator++() {
|
Card &Card::operator++() {
|
||||||
rank++;
|
rank++;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
|
||||||
|
|
||||||
Card Card::successor() const {
|
|
||||||
return {suit, static_cast<rank_t>(rank + 1)};
|
|
||||||
}
|
|
||||||
|
|
||||||
const Card Card::operator++(int) {
|
|
||||||
Card ret = *this;
|
|
||||||
rank++;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t num_suits>
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Stacks<num_suits>& stacks) {
|
|
||||||
for (size_t i = 0; i < stacks.size() - 1; i++) {
|
|
||||||
os << +stacks[i] << ", ";
|
|
||||||
}
|
|
||||||
os << +stacks.back();
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t num_suits>
|
|
||||||
const player_t & CardPositions<num_suits>::operator[](const Card& card) const {
|
|
||||||
return _card_positions[card.suit][card.rank][card.copy];
|
|
||||||
};
|
|
||||||
|
|
||||||
template<std::size_t num_suits>
|
|
||||||
player_t & CardPositions<num_suits>::operator[](const Card& card) {
|
|
||||||
return _card_positions[card.suit][card.rank][card.copy];
|
|
||||||
};
|
|
||||||
|
|
||||||
template <size_t num_suits, size_t num_players, size_t hand_size, uint8_t max_draw_pile_size>
|
|
||||||
Action HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::clue() {
|
|
||||||
assert(_num_clues > 0);
|
|
||||||
--_num_clues;
|
|
||||||
|
|
||||||
incr_turn();
|
|
||||||
|
|
||||||
return Action {ActionType::clue, {}, {}};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t num_suits, size_t num_players, size_t hand_size, uint8_t max_draw_pile_size>
|
|
||||||
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::incr_turn() {
|
|
||||||
_turn = (_turn + 1) % num_players;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t num_suits, size_t num_players, size_t hand_size, uint8_t max_draw_pile_size>
|
|
||||||
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::decr_turn() {
|
|
||||||
_turn = (_turn + num_players - 1) % num_players;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
|
||||||
Action HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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 <std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
|
||||||
Action HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
|
||||||
std::ostream& operator<<(std::ostream& os, const HanabiState<num_suits, num_players, hand_size, max_draw_pile_size> 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 <std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
|
||||||
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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 <std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
Card Card::successor() const { return {suit, static_cast<rank_t>(rank + 1)}; }
|
||||||
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::revert_draw(std::uint8_t index, Card card) {
|
|
||||||
assert(index < _hands[_turn].size());
|
|
||||||
|
|
||||||
_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
|
template<std::size_t num_suits>
|
||||||
if (_draw_pile.back().card == _hands[_turn][index]) {
|
std::ostream &operator<<(std::ostream &os, const Stacks<num_suits> &stacks) {
|
||||||
_draw_pile.back().multiplicity++;
|
for (size_t i = 0; i < stacks.size() - 1; i++) {
|
||||||
} else {
|
os << +stacks[i] << ", ";
|
||||||
_draw_pile.push_back({_hands[_turn][index], 1});
|
}
|
||||||
}
|
os << +stacks.back();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
_hands[_turn][index] = card;
|
template<std::size_t num_suits>
|
||||||
_card_positions[card] = _turn;
|
const player_t &CardPositions<num_suits>::operator[](const Card &card) const {
|
||||||
_draw_pile_size++;
|
return _card_positions[card.suit][card.rank][card.copy];
|
||||||
}
|
};
|
||||||
|
|
||||||
template <std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
template<std::size_t num_suits>
|
||||||
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::revert(const Action &action) {
|
player_t &CardPositions<num_suits>::operator[](const Card &card) {
|
||||||
decr_turn();
|
return _card_positions[card.suit][card.rank][card.copy];
|
||||||
switch (action.type) {
|
};
|
||||||
case ActionType::clue:
|
|
||||||
assert(_num_clues < max_num_clues);
|
template<size_t num_suits, size_t num_players, size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
_num_clues++;
|
Action HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::clue() {
|
||||||
break;
|
assert(_num_clues > 0);
|
||||||
case ActionType::discard:
|
--_num_clues;
|
||||||
assert(_num_clues > 0);
|
|
||||||
_num_clues--;
|
incr_turn();
|
||||||
revert_draw(action.index, action.discarded);
|
|
||||||
break;
|
return Action{ActionType::clue, {}, {}};
|
||||||
case ActionType::play:
|
}
|
||||||
if (action.discarded.rank == 0) {
|
|
||||||
_num_clues--;
|
template<size_t num_suits, size_t num_players, size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
}
|
void HanabiState<num_suits, num_players, hand_size,
|
||||||
revert_draw(action.index, action.discarded);
|
max_draw_pile_size>::incr_turn() {
|
||||||
_stacks[action.discarded.suit]++;
|
_turn = (_turn + 1) % num_players;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
template<size_t num_suits, size_t num_players, size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
|
void HanabiState<num_suits, num_players, hand_size,
|
||||||
|
max_draw_pile_size>::decr_turn() {
|
||||||
|
_turn = (_turn + num_players - 1) % num_players;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
|
Action HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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<std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
|
Action HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
|
std::ostream &operator<<(std::ostream &os, const HanabiState<num_suits, num_players, hand_size, max_draw_pile_size> 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<std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
|
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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<std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
|
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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<std::size_t num_suits, std::size_t num_players, std::size_t hand_size, uint8_t max_draw_pile_size>
|
||||||
|
void HanabiState<num_suits, num_players, hand_size, max_draw_pile_size>::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
|
2
main.cpp
2
main.cpp
|
@ -38,7 +38,7 @@ void test_game() {
|
||||||
assert(state == state2);
|
assert(state == state2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void download() { download_game(1000000); }
|
void download() { get_game("314159.json"); }
|
||||||
|
|
||||||
void print_sizes() {
|
void print_sizes() {
|
||||||
std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4, 5>)
|
std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4, 5>)
|
||||||
|
|
Loading…
Reference in a new issue