#include "parse_game.h" #include "myassert.h" namespace Parsing { // 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(); 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, 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(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, Hanabi::suit_t> parse_deck(const boost::json::value &deck_json) { auto deck = boost::json::value_to>(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 parse_actions(const boost::json::value &action_json) { return boost::json::value_to>(action_json); } std::vector convert_actions(std::vector const & hanab_live_actions, std::vector const & deck) { std::vector 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 hanab_live_actions = parse_actions(game_json.at("actions")); Hanabi::player_t num_players = game_json.at("players").as_array().size(); std::vector actions = convert_actions(hanab_live_actions, deck); return {deck, actions, num_suits, num_players}; } }