2023-08-04 16:28:41 +02:00
|
|
|
//
|
|
|
|
// Created by maximilian on 7/13/23.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <boost/rational.hpp>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <iostream>
|
|
|
|
#include <optional>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "game_state.h"
|
2023-08-05 00:34:31 +02:00
|
|
|
#include "download.h"
|
2023-08-06 15:02:50 +02:00
|
|
|
#include "myassert.h"
|
|
|
|
|
2023-08-04 16:28:41 +02:00
|
|
|
|
2023-08-05 00:34:31 +02:00
|
|
|
namespace Hanabi {
|
2023-08-08 11:08:58 +02:00
|
|
|
void download(std::variant<int, const char*> game_id, int turn) {
|
2023-08-06 23:12:44 +02:00
|
|
|
auto game = Download::get_game(game_id, turn);
|
2023-08-08 00:29:19 +02:00
|
|
|
std::cout << "Analysing state: " << std::endl << *game << std::endl;
|
2023-08-06 23:12:44 +02:00
|
|
|
auto res = game->backtrack(1);
|
|
|
|
std::cout.precision(10);
|
2023-08-08 00:29:19 +02:00
|
|
|
std::cout << std::endl;
|
2023-08-06 23:12:44 +02:00
|
|
|
std::cout << "Probability with optimal play: " << res << std::endl;
|
|
|
|
std::cout << "Enumerated " << game->enumerated_states() << " states" << std::endl;
|
2023-08-07 12:48:25 +02:00
|
|
|
std::cout << "Visited " << game->visited_states().size() << " unique game states. " << std::endl;
|
2023-08-08 00:29:19 +02:00
|
|
|
unsigned long biggest_key = 0;
|
|
|
|
for(const auto& [key, prob] : game->visited_states()) {
|
|
|
|
biggest_key = std::max(biggest_key, key);
|
|
|
|
}
|
|
|
|
std::cout << "Biggest key generated is " << biggest_key << std::endl;
|
2023-08-06 23:12:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void print_sizes() {
|
|
|
|
std::cout << "size of card -> hand map: " << sizeof(HanabiState<5, 3, 4>)
|
|
|
|
<< std::endl;
|
|
|
|
|
|
|
|
unsigned exp = 32;
|
|
|
|
std::cout << "Pair size: " << sizeof(std::pair<std::uint32_t, float>)
|
|
|
|
<< std::endl;
|
|
|
|
std::cout << sizeof(boost::rational<int>) << std::endl;
|
|
|
|
std::cout << (1ul << exp) << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_usage(const char* program_name) {
|
|
|
|
std::cout << "Usage: " << program_name << " GAME_ID TURN" << std::endl;
|
|
|
|
}
|
2023-08-04 16:28:41 +02:00
|
|
|
|
2023-08-05 00:34:31 +02:00
|
|
|
}
|
|
|
|
|
2023-08-07 11:07:42 +02:00
|
|
|
#define CHECK(test, condition) if (!(condition)) { std::cerr << "Test " << (test) << " failed." << std::endl; } else { std::cout << "Test " << (test) << " succeeded." << std::endl; }
|
2023-08-07 01:51:24 +02:00
|
|
|
|
|
|
|
void test() {
|
|
|
|
{
|
2023-08-08 16:27:25 +02:00
|
|
|
auto game = Download::get_game("in/1005195", 43);
|
2023-08-07 01:51:24 +02:00
|
|
|
auto res = game->backtrack(1);
|
|
|
|
CHECK("1005195", res == static_cast<double>(7) / 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-08 02:04:58 +02:00
|
|
|
void check_games(unsigned num_players, unsigned max_draw_pile_size, unsigned first_game = 0, unsigned last_game = 9999) {
|
2023-08-08 00:29:19 +02:00
|
|
|
|
|
|
|
std::vector<std::vector<double>> winning_percentages(last_game + 2);
|
|
|
|
|
|
|
|
for(size_t draw_pile_size = 0; draw_pile_size <= max_draw_pile_size; draw_pile_size++) {
|
|
|
|
double total_chance = 0;
|
|
|
|
const std::string output_fname = "games_" + std::to_string(num_players) + "p_draw_size_" + std::to_string(draw_pile_size) + ".txt";
|
|
|
|
std::ofstream file (output_fname);
|
|
|
|
for(size_t game_id = first_game; game_id <= last_game; game_id++) {
|
|
|
|
const std::string input_fname = "json/" + std::to_string(num_players) + "p/" + std::to_string(game_id) + ".json";
|
|
|
|
auto game = Download::get_game(input_fname.c_str(), 50, draw_pile_size);
|
|
|
|
const double chance = game->backtrack(0);
|
|
|
|
winning_percentages[game_id].push_back(chance);
|
|
|
|
if(chance != 1) {
|
|
|
|
file << "Game " << game_id << ": " << chance << std::endl;
|
|
|
|
file << *game << std::endl << std::endl;
|
|
|
|
}
|
2023-08-08 00:44:50 +02:00
|
|
|
std::cout << "Finished game " << game_id << " with draw pile size " << draw_pile_size << ": " << chance << std::endl;
|
2023-08-08 00:29:19 +02:00
|
|
|
|
|
|
|
total_chance += chance;
|
|
|
|
}
|
|
|
|
const double total_average = total_chance / (last_game - first_game + 1);
|
|
|
|
winning_percentages.back().push_back(total_average);
|
|
|
|
file << "Total chance found over " << last_game - first_game + 1 << " many games: " << total_average << std::endl;
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
const std::string results_file_name {"results_" + std::to_string(num_players) + "p.txt"};
|
|
|
|
std::ofstream results_file (results_file_name);
|
|
|
|
results_file << "game_id, ";
|
|
|
|
for(size_t draw_pile_size = 0; draw_pile_size <= max_draw_pile_size; draw_pile_size++) {
|
|
|
|
results_file << std::to_string(draw_pile_size) << ", ";
|
|
|
|
}
|
|
|
|
results_file << "\n";
|
|
|
|
for(size_t game_id = first_game; game_id <= last_game; game_id++) {
|
|
|
|
results_file << game_id << ", ";
|
|
|
|
for(size_t draw_pile_size = 0; draw_pile_size <= max_draw_pile_size; draw_pile_size++) {
|
|
|
|
results_file << winning_percentages[game_id][draw_pile_size] << ", ";
|
|
|
|
}
|
|
|
|
results_file << std::endl;
|
|
|
|
}
|
|
|
|
results_file << "total, ";
|
|
|
|
for(size_t draw_pile_size = 0; draw_pile_size <= max_draw_pile_size; draw_pile_size++) {
|
|
|
|
results_file << winning_percentages.back()[draw_pile_size] << ", ";
|
|
|
|
}
|
|
|
|
results_file << std::endl;
|
|
|
|
results_file.close();
|
|
|
|
}
|
|
|
|
|
2023-08-06 15:02:50 +02:00
|
|
|
int main(int argc, char *argv[]) {
|
2023-08-08 00:29:19 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
test();
|
|
|
|
#endif
|
2023-08-06 23:12:44 +02:00
|
|
|
if(argc == 3) {
|
2023-08-08 11:08:58 +02:00
|
|
|
std::string game(argv[1]);
|
2023-08-06 23:12:44 +02:00
|
|
|
std::string turn (argv[2]);
|
2023-08-08 11:08:58 +02:00
|
|
|
try {
|
|
|
|
Hanabi::download(std::stoi(game), std::stoi(turn));
|
|
|
|
} catch(std::invalid_argument&) {
|
|
|
|
Hanabi::download(game.c_str(), std::stoi(turn));
|
|
|
|
}
|
2023-08-09 22:50:03 +02:00
|
|
|
} else if (argc == 2) {
|
|
|
|
int player_count = std::stoi(argv[1]);
|
|
|
|
if (player_count == 3) {
|
|
|
|
check_games(3, 10);
|
|
|
|
} else if (player_count == 4) {
|
|
|
|
check_games(4, 9);
|
|
|
|
} else if (player_count == 5) {
|
|
|
|
check_games(5, 9);
|
|
|
|
} else if (player_count == 2) {
|
|
|
|
check_games(2, 10);
|
|
|
|
}
|
2023-08-06 23:12:44 +02:00
|
|
|
} else {
|
|
|
|
Hanabi::print_usage(argv[0]);
|
2023-08-06 15:02:50 +02:00
|
|
|
}
|
2023-08-04 16:28:41 +02:00
|
|
|
return 0;
|
2023-08-08 16:27:25 +02:00
|
|
|
}
|