2023-08-12 19:15:05 +02:00
|
|
|
#include <boost/json/src.hpp>
|
2023-08-12 19:43:22 +02:00
|
|
|
#include <cpr/cpr.h>
|
|
|
|
|
2023-11-15 21:47:50 +01:00
|
|
|
#include "parse_game.h"
|
2023-11-15 23:07:39 +01:00
|
|
|
#include "game_state.h"
|
2023-08-12 19:15:05 +02:00
|
|
|
|
2023-11-15 21:47:50 +01:00
|
|
|
#include "download.h"
|
2023-08-12 19:15:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
namespace Download {
|
|
|
|
|
|
|
|
std::optional<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 std::nullopt;
|
|
|
|
}
|
|
|
|
return boost::json::parse(r.text).as_object();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<boost::json::object> open_game_json(const char *filename) {
|
|
|
|
std::ifstream file(filename);
|
|
|
|
if (!file.is_open()) {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
std::string game_json((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
|
|
|
return boost::json::parse(game_json).as_object();
|
|
|
|
}
|
|
|
|
|
2023-11-10 20:35:05 +01:00
|
|
|
std::unique_ptr<Hanabi::HanabiStateIF> get_base_state(
|
|
|
|
std::size_t num_suits,
|
|
|
|
Hanabi::player_t num_players,
|
|
|
|
std::vector<Hanabi::Card> const & deck,
|
|
|
|
std::optional<uint8_t> score_goal) {
|
2023-11-04 13:02:16 +01:00
|
|
|
uint8_t actual_score_goal = score_goal.value_or(5 * num_suits);
|
2023-08-12 19:15:05 +02:00
|
|
|
switch(num_players) {
|
|
|
|
case 2:
|
|
|
|
switch(num_suits) {
|
|
|
|
case 3:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<3,2,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 4:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<4,2,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 5:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<5,2,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 6:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<6,2,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
default:
|
|
|
|
throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits));
|
|
|
|
}
|
|
|
|
case 3:
|
|
|
|
switch(num_suits) {
|
|
|
|
case 3:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<3,3,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 4:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<4,3,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 5:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<5,3,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 6:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<6,3,5>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
default:
|
|
|
|
throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits));
|
|
|
|
}
|
|
|
|
case 4:
|
|
|
|
switch(num_suits) {
|
|
|
|
case 3:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<3,4,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 4:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<4,4,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 5:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<5,4,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 6:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<6,4,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
default:
|
|
|
|
throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits));
|
|
|
|
}
|
|
|
|
case 5:
|
|
|
|
switch(num_suits) {
|
|
|
|
case 3:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<3,5,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 4:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<4,5,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 5:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<5,5,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 6:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<6,5,4>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
default:
|
|
|
|
throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits));
|
|
|
|
}
|
|
|
|
case 6:
|
|
|
|
switch(num_suits) {
|
|
|
|
case 3:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<3,6,3>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 4:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<4,6,3>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 5:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<5,6,3>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
case 6:
|
2023-11-10 20:35:05 +01:00
|
|
|
return std::unique_ptr<Hanabi::HanabiStateIF>(new Hanabi::HanabiState<6,6,3>(deck, actual_score_goal));
|
2023-08-12 19:15:05 +02:00
|
|
|
default:
|
|
|
|
throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits));
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
throw std::runtime_error("Invalid number of players: " + std::to_string(num_players));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-12 17:30:44 +01:00
|
|
|
Hanabi::Game get_game(std::variant<int, std::string> game_spec, std::optional<uint8_t> score_goal){
|
2023-11-10 20:35:05 +01:00
|
|
|
const std::optional<boost::json::object> game_json_opt = [&game_spec]() {
|
|
|
|
if (game_spec.index() == 0) {
|
|
|
|
return download_game_json(std::get<int>(game_spec));
|
|
|
|
} else {
|
2023-11-12 17:30:44 +01:00
|
|
|
return open_game_json(std::get<std::string>(game_spec).c_str());
|
2023-11-10 20:35:05 +01:00
|
|
|
}
|
|
|
|
}();
|
|
|
|
|
|
|
|
if (!game_json_opt.has_value() or game_json_opt.value().empty()) {
|
2023-11-15 21:47:50 +01:00
|
|
|
return {nullptr, {}, {}};
|
2023-11-10 20:35:05 +01:00
|
|
|
}
|
|
|
|
|
2023-11-15 21:47:50 +01:00
|
|
|
Parsing::GameInfo game_info = Parsing::parse_game(game_json_opt.value());
|
|
|
|
return {get_base_state(game_info.num_suits, game_info.num_players, game_info.deck, score_goal), game_info.actions, game_info.deck};
|
2023-11-10 20:35:05 +01:00
|
|
|
}
|
|
|
|
|
2023-08-12 19:15:05 +02:00
|
|
|
} // namespace Download
|