Rework probability printing
Outputting of probabilities is now done in unified way. This ensures that we can handle both rational and floating-point probabilities in all program parts properly. The compile-time macro NUSE_RATIONAL_PROBABILITIES can now be defined to use floating-point probabilities instead of real rational ones. Using floating-point results in roughly 10% speedup.
This commit is contained in:
parent
0cc069485d
commit
b69cb6d974
4 changed files with 57 additions and 15 deletions
|
@ -23,7 +23,28 @@ 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 probability_base_type = unsigned long;
|
||||
using rational_probability = boost::rational<probability_base_type>;
|
||||
|
||||
/**
|
||||
* Define macro
|
||||
* NUSE_RATIONAL_PROBABILITIES
|
||||
* to use floating-point arithematic for the stored probabilities
|
||||
* instead of rational representations
|
||||
*/
|
||||
|
||||
#ifndef NUSE_RATIONAL_PROBABILITIES
|
||||
using probability_t = boost::rational<probability_base_type>;
|
||||
#else
|
||||
using probability_t = double;
|
||||
#endif
|
||||
|
||||
inline std::ostream& print_probability(std::ostream& os, double prob);
|
||||
inline std::ostream& print_probability(std::ostream& os, const rational_probability& prob);
|
||||
|
||||
template<typename T>
|
||||
std::ostream& print_probability(std::ostream& os, const std::optional<T>& prob);
|
||||
|
||||
/**
|
||||
* We will generally assume that stacks are played from n to 0
|
||||
|
|
|
@ -5,6 +5,26 @@
|
|||
|
||||
namespace Hanabi {
|
||||
|
||||
template<typename T>
|
||||
std::ostream& print_probability(std::ostream& os, const std::optional<T>& prob) {
|
||||
if (prob.has_value()) {
|
||||
return print_probability(os, prob.value());
|
||||
} else {
|
||||
os << "unknown";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& print_probability(std::ostream& os, const rational_probability & prob) {
|
||||
os << prob << " ~ " << std::setprecision(5) << boost::rational_cast<double>(prob) * 100 << "%";
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& print_probability(std::ostream& os, double prob) {
|
||||
os << std::setprecision(5) << prob;
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, HanabiStateIF const &hanabi_state) {
|
||||
hanabi_state.print(os);
|
||||
return os;
|
||||
|
|
|
@ -11,17 +11,10 @@
|
|||
#include <memory>
|
||||
#include <cmath>
|
||||
#include "game_state.h"
|
||||
#include <myassert.h>
|
||||
|
||||
namespace Hanabi {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::optional<probability_t>& prob) {
|
||||
if (prob.has_value()) {
|
||||
os << prob.value() << " ~ " << std::setprecision(5) << boost::rational_cast<double>(prob.value()) * 100 << "%";
|
||||
} else {
|
||||
os << "unknown";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
std::string read_line_memory_safe(const char *prompt) {
|
||||
char *line = readline(prompt);
|
||||
|
@ -89,11 +82,15 @@ namespace Hanabi {
|
|||
}
|
||||
}
|
||||
|
||||
int representation_length(probability_t probability) {
|
||||
int representation_length(const rational_probability& probability) {
|
||||
return 1 + static_cast<int>(std::ceil(std::log10(probability.denominator()))) + \
|
||||
static_cast<int>(std::ceil(std::log10(probability.numerator())));
|
||||
}
|
||||
|
||||
int representation_length(const double probability) {
|
||||
return static_cast<int>(std::ceil(std::log10(probability)));
|
||||
}
|
||||
|
||||
bool ask_for_card_and_rotate_draw(const std::shared_ptr<HanabiStateIF>& game, hand_index_t index, bool play) {
|
||||
const auto next_states = game->possible_next_states(index, play);
|
||||
|
||||
|
@ -132,7 +129,8 @@ namespace Hanabi {
|
|||
|
||||
for (const auto &[card_multiplicity, probability]: states_to_show) {
|
||||
std::cout << card_multiplicity.card << " (" << card_multiplicity.multiplicity;
|
||||
std::cout << " copie(s) in draw) " << std::setw(max_rational_digit_len) << probability << std::endl;
|
||||
std::cout << " copie(s) in draw) " << std::setw(max_rational_digit_len);
|
||||
print_probability(std::cout, probability) << std::endl;
|
||||
}
|
||||
|
||||
std::stringstream prompt;
|
||||
|
@ -235,7 +233,8 @@ namespace Hanabi {
|
|||
if (prompt.starts_with("state")) {
|
||||
std::cout << *game << std::endl;
|
||||
const std::optional<probability_t> prob = game->lookup();
|
||||
std::cout << "Winning chance: " << prob << std::endl;
|
||||
std::cout << "Winning chance: ";
|
||||
print_probability(std::cout, prob) << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -349,7 +348,8 @@ namespace Hanabi {
|
|||
std::cout.setf(std::ios_base::left, std::ios_base::adjustfield);
|
||||
std::cout << std::setw(7) << action << ": ";
|
||||
std::cout.setf(std::ios_base::right, std::ios_base::adjustfield);
|
||||
std::cout << std::setw(max_rational_digit_len) << probability << std::endl;
|
||||
std::cout << std::setw(max_rational_digit_len);
|
||||
print_probability(std::cout, probability) << std::endl;
|
||||
}
|
||||
if(reasonable_actions.empty()) {
|
||||
std::cout << "Game is over, no actions to take." << std::endl;
|
||||
|
|
|
@ -27,7 +27,8 @@ namespace Hanabi {
|
|||
|
||||
std::cout.precision(10);
|
||||
std::cout << std::endl;
|
||||
std::cout << "Probability with optimal play: " << res << " ~ " << std::setprecision(5) << boost::rational_cast<double>(res) * 100 << "%" << std::endl;
|
||||
std::cout << "Probability with optimal play: ";
|
||||
print_probability(std::cout, res) << std::endl;
|
||||
std::cout << "Took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start) << "." << std::endl;
|
||||
std::cout << "Visited " << game->enumerated_states() << " states." << std::endl;
|
||||
std::cout << "Enumerated " << game->position_tablebase().size() << " unique game states. " << std::endl;
|
||||
|
|
Loading…
Reference in a new issue