use rationals as probabilities
This commit is contained in:
parent
5f0a850c45
commit
24aa016d36
3 changed files with 22 additions and 20 deletions
12
game_state.h
12
game_state.h
|
@ -12,6 +12,7 @@
|
|||
#include <boost/container/static_vector.hpp>
|
||||
#include <list>
|
||||
#include <ostream>
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
|
||||
namespace Hanabi {
|
||||
|
@ -21,6 +22,7 @@ namespace Hanabi {
|
|||
using clue_t = std::uint8_t;
|
||||
using player_t = std::uint8_t;
|
||||
using hand_index_t = std::uint8_t;
|
||||
using probability_t = boost::rational<unsigned long>;
|
||||
|
||||
using state_t = std::uint32_t;
|
||||
|
||||
|
@ -152,7 +154,7 @@ struct BacktrackAction {
|
|||
|
||||
class HanabiStateIF {
|
||||
public:
|
||||
virtual double backtrack(size_t depth) = 0;
|
||||
virtual probability_t backtrack(size_t depth) = 0;
|
||||
|
||||
virtual void clue() = 0;
|
||||
virtual BacktrackAction discard(hand_index_t index) = 0;
|
||||
|
@ -164,7 +166,7 @@ public:
|
|||
[[nodiscard]] virtual size_t draw_pile_size() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::uint64_t enumerated_states() const = 0;
|
||||
[[nodiscard]] virtual std::unordered_map<unsigned long, double> visited_states() const = 0;
|
||||
[[nodiscard]] virtual std::unordered_map<unsigned long, probability_t> visited_states() const = 0;
|
||||
|
||||
virtual void normalize_draw_and_positions() = 0;
|
||||
|
||||
|
@ -182,7 +184,7 @@ public:
|
|||
HanabiState() = default;
|
||||
explicit HanabiState(const std::vector<Card>& deck);
|
||||
|
||||
double backtrack(size_t depth) final;
|
||||
probability_t backtrack(size_t depth) final;
|
||||
|
||||
void clue() final;
|
||||
BacktrackAction play(hand_index_t index) final;
|
||||
|
@ -198,7 +200,7 @@ public:
|
|||
[[nodiscard]] size_t draw_pile_size() const final;
|
||||
|
||||
[[nodiscard]] std::uint64_t enumerated_states() const final;
|
||||
[[nodiscard]] std::unordered_map<unsigned long, double> visited_states() const final;
|
||||
[[nodiscard]] std::unordered_map<unsigned long, probability_t> visited_states() const final;
|
||||
|
||||
void normalize_draw_and_positions() final;
|
||||
|
||||
|
@ -248,7 +250,7 @@ private:
|
|||
|
||||
std::uint64_t _enumerated_states {};
|
||||
|
||||
std::unordered_map<unsigned long, double> _position_tablebase;
|
||||
std::unordered_map<unsigned long, probability_t> _position_tablebase;
|
||||
};
|
||||
|
||||
template <std::size_t num_suits, player_t num_players, std::size_t hand_size>
|
||||
|
|
|
@ -419,7 +419,7 @@ namespace Hanabi {
|
|||
}
|
||||
|
||||
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||
double HanabiState<num_suits, num_players, hand_size>::backtrack(size_t depth) {
|
||||
probability_t HanabiState<num_suits, num_players, hand_size>::backtrack(size_t depth) {
|
||||
_enumerated_states++;
|
||||
const unsigned long id_of_state = unique_id();
|
||||
|
||||
|
@ -436,7 +436,7 @@ namespace Hanabi {
|
|||
// TODO: Have some endgame analysis here?
|
||||
|
||||
// First, check if we have any playable cards
|
||||
double best_probability = 0;
|
||||
probability_t best_probability = 0;
|
||||
const std::array<Card, hand_size> hand = _hands[_turn];
|
||||
|
||||
// First, check for playables
|
||||
|
@ -445,11 +445,11 @@ namespace Hanabi {
|
|||
if (_draw_pile.empty()) {
|
||||
bool on_8_clues = _num_clues == 8;
|
||||
BacktrackAction action = play_and_potentially_update<true>(index);
|
||||
const double probability_for_this_play = backtrack(depth + 1);
|
||||
const probability_t probability_for_this_play = backtrack(depth + 1);
|
||||
revert_play(action, on_8_clues);
|
||||
UPDATE_PROBABILITY(probability_for_this_play);
|
||||
} else {
|
||||
double sum_of_probabilities = 0;
|
||||
probability_t sum_of_probabilities = 0;
|
||||
uint8_t sum_of_mults = 0;
|
||||
for (size_t i = 0; i < _draw_pile.size(); i++) {
|
||||
bool on_8_clues = _num_clues == 8;
|
||||
|
@ -460,7 +460,7 @@ namespace Hanabi {
|
|||
ASSERT(sum_of_mults <= _weighted_draw_pile_size);
|
||||
}
|
||||
ASSERT(sum_of_mults == _weighted_draw_pile_size);
|
||||
const double probability_for_this_play = sum_of_probabilities / _weighted_draw_pile_size;
|
||||
const probability_t probability_for_this_play = sum_of_probabilities / _weighted_draw_pile_size;
|
||||
UPDATE_PROBABILITY(probability_for_this_play);
|
||||
}
|
||||
}
|
||||
|
@ -470,10 +470,10 @@ namespace Hanabi {
|
|||
if(_pace > 0 and _num_clues < max_num_clues) {
|
||||
for(std::uint8_t index = 0; index < hand_size; index++) {
|
||||
if (is_trash(hand[index])) {
|
||||
double sum_of_probabilities = 0;
|
||||
probability_t sum_of_probabilities = 0;
|
||||
if (_draw_pile.empty()) {
|
||||
BacktrackAction action = discard_and_potentially_update<true>(index);
|
||||
const double probability_for_this_discard = backtrack(depth + 1);
|
||||
const probability_t probability_for_this_discard = backtrack(depth + 1);
|
||||
revert_discard(action);
|
||||
UPDATE_PROBABILITY(probability_for_this_discard);
|
||||
} else {
|
||||
|
@ -485,7 +485,7 @@ namespace Hanabi {
|
|||
revert_discard(action);
|
||||
}
|
||||
ASSERT(sum_of_mults == _weighted_draw_pile_size);
|
||||
const double probability_discard = sum_of_probabilities / _weighted_draw_pile_size;
|
||||
const probability_t probability_discard = sum_of_probabilities / _weighted_draw_pile_size;
|
||||
UPDATE_PROBABILITY(probability_discard);
|
||||
}
|
||||
|
||||
|
@ -498,7 +498,7 @@ namespace Hanabi {
|
|||
// Last option is to stall
|
||||
if(_num_clues > 0) {
|
||||
clue();
|
||||
const double probability_stall = backtrack(depth + 1);
|
||||
const probability_t probability_stall = backtrack(depth + 1);
|
||||
revert_clue();
|
||||
UPDATE_PROBABILITY(probability_stall);
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ namespace Hanabi {
|
|||
}
|
||||
|
||||
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||
std::unordered_map<unsigned long, double> HanabiState<num_suits, num_players, hand_size>::visited_states() const {
|
||||
std::unordered_map<unsigned long, probability_t> HanabiState<num_suits, num_players, hand_size>::visited_states() const {
|
||||
return _position_tablebase;
|
||||
}
|
||||
|
||||
|
|
10
main.cpp
10
main.cpp
|
@ -53,22 +53,22 @@ void test() {
|
|||
{
|
||||
auto game = Download::get_game("in/1005195", 43);
|
||||
auto res = game->backtrack(1);
|
||||
CHECK("1005195", res == static_cast<double>(7) / 8);
|
||||
CHECK("1005195", res == Hanabi::probability_t (7,8));
|
||||
}
|
||||
}
|
||||
|
||||
void check_games(unsigned num_players, unsigned max_draw_pile_size, unsigned first_game = 0, unsigned last_game = 9999) {
|
||||
|
||||
std::vector<std::vector<double>> winning_percentages(last_game + 2);
|
||||
std::vector<std::vector<Hanabi::probability_t>> 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;
|
||||
Hanabi::probability_t 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);
|
||||
const Hanabi::probability_t chance = game->backtrack(0);
|
||||
winning_percentages[game_id].push_back(chance);
|
||||
if(chance != 1) {
|
||||
file << "Game " << game_id << ": " << chance << std::endl;
|
||||
|
@ -78,7 +78,7 @@ void check_games(unsigned num_players, unsigned max_draw_pile_size, unsigned fir
|
|||
|
||||
total_chance += chance;
|
||||
}
|
||||
const double total_average = total_chance / (last_game - first_game + 1);
|
||||
const Hanabi::probability_t 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();
|
||||
|
|
Loading…
Reference in a new issue