Endgame-Analyzer/src/parse_game.cpp

108 lines
3.4 KiB
C++
Raw Normal View History

#include "parse_game.h"
2023-11-15 23:07:39 +01:00
#include "myassert.h"
namespace Parsing {
// 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();
Parsing::extract(obj, card.rank, "rank");
Parsing::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}};
}
}
namespace Parsing {
HanabLiveAction tag_invoke(boost::json::value_to_tag<HanabLiveAction>, boost::json::value const &jv) {
HanabLiveAction action{};
uint8_t type;
boost::json::object const &obj = jv.as_object();
extract(obj, action.target, "target");
extract(obj, type, "type");
action.type = static_cast<Hanabi::ActionType>(type);
switch (action.type) {
case Hanabi::ActionType::color_clue:
case Hanabi::ActionType::rank_clue:
action.type = Hanabi::ActionType::clue;
break;
case Hanabi::ActionType::end_game:
case Hanabi::ActionType::vote_terminate_players:
case Hanabi::ActionType::vote_terminate:
action.type = Hanabi::ActionType::end_game;
break;
case Hanabi::ActionType::play:
case Hanabi::ActionType::discard:
break;
default:
throw std::runtime_error(
"Invalid game format, could not parse action type " + std::to_string(type));
}
return action;
}
std::pair<std::vector<Hanabi::Card>, Hanabi::suit_t> parse_deck(const boost::json::value &deck_json) {
auto deck = boost::json::value_to<std::vector<Hanabi::Card>>(deck_json);
for (auto &card: deck) {
ASSERT(card.rank < 5);
ASSERT(card.rank >= 0);
ASSERT(card.suit < 6);
ASSERT(card.suit >= 0);
}
Hanabi::suit_t num_suits = 0;
for(const auto& card: deck) {
num_suits = std::max(num_suits, card.suit);
}
return {deck, num_suits + 1};
}
std::vector<HanabLiveAction> parse_actions(const boost::json::value &action_json)
{
return boost::json::value_to<std::vector<HanabLiveAction>>(action_json);
}
std::vector<Hanabi::Action> convert_actions(std::vector<HanabLiveAction> const & hanab_live_actions, std::vector<Hanabi::Card> const & deck)
{
std::vector<Hanabi::Action> actions;
std::transform(
hanab_live_actions.begin(),
hanab_live_actions.end(),
std::back_inserter(actions),
[&deck](HanabLiveAction const & action){
return Hanabi::Action {action.type, deck[action.target]};
}
);
return actions;
}
GameInfo parse_game(boost::json::object const & game_json)
{
auto const [deck, num_suits] = parse_deck(game_json.at("deck"));
const std::vector<Parsing::HanabLiveAction> hanab_live_actions = parse_actions(game_json.at("actions"));
Hanabi::player_t num_players = game_json.at("players").as_array().size();
std::vector<Hanabi::Action> actions = convert_actions(hanab_live_actions, deck);
return {deck, actions, num_suits, num_players};
}
}