#ifndef DYNAMIC_PROGRAM_DOWNLOAD_H #define DYNAMIC_PROGRAM_DOWNLOAD_H #include #include #include #include #include #include #include "game_state.h" // 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(); extract(obj, card.rank, "rank"); extract(obj, card.suit, "suitIndex"); card.rank = 5 - card.rank; return card; } Action tag_invoke(boost::json::value_to_tag, boost::json::value const &jv) { Hanabi::Action 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 ActionType::color_clue: case ActionType::rank_clue: action.type = ActionType::clue; break; case ActionType::end_game: case ActionType::vote_terminate: action.type = ActionType::end_game; break; case ActionType::play: case ActionType::discard: break; default: throw std::runtime_error("Invalid game format, could not parse action type " + std::to_string(type)); } return action; } 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 parse_deck(const boost::json::value& deck_json) { auto deck = boost::json::value_to>(deck_json); 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); } return deck; } std::vector parse_actions(const boost::json::value& action_json) { return boost::json::value_to>(action_json); } 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(); } boost::json::object open_game_json(const char* filename) { std::ifstream file(filename); if (!file.is_open()) { std::cout << "Failed to open " << filename << "." << std::endl; return {}; } std::string game_json ((std::istreambuf_iterator(file)), std::istreambuf_iterator()); return boost::json::parse(game_json).as_object(); } void get_game(std::variant game_spec) { const boost::json::object game = [&game_spec](){ if (game_spec.index() == 0) { return download_game_json(std::get(game_spec)); } else { return open_game_json(std::get(game_spec)); } }(); const std::vector deck = parse_deck(game.at("deck")); const std::vector actions = parse_actions(game.at("actions")); const unsigned num_players = game.at("players").as_array().size(); std::cout << deck.size() << std::endl; std::cout << num_players; } #endif // DYNAMIC_PROGRAM_DOWNLOAD_H