add method to list reasonable moves
This commit is contained in:
parent
907fb3ae47
commit
57ebc3d478
2 changed files with 93 additions and 2 deletions
11
game_state.h
11
game_state.h
|
@ -143,6 +143,10 @@ enum class ActionType {
|
|||
vote_terminate = 10,
|
||||
};
|
||||
|
||||
class Action {
|
||||
ActionType type {};
|
||||
Card card {};
|
||||
};
|
||||
|
||||
/** Would like to have 2 versions:
|
||||
* All:
|
||||
|
@ -185,8 +189,6 @@ public:
|
|||
HanabiState() = default;
|
||||
explicit HanabiState(const std::vector<Card>& deck);
|
||||
|
||||
probability_t evaluate_state() final;
|
||||
|
||||
void clue() final;
|
||||
void discard(hand_index_t index) final;
|
||||
void play(hand_index_t index) final;
|
||||
|
@ -203,6 +205,11 @@ public:
|
|||
[[nodiscard]] const std::unordered_map<unsigned long, probability_t>& position_tablebase() const final;
|
||||
|
||||
void init_backtracking_information() final;
|
||||
probability_t evaluate_state() final;
|
||||
|
||||
std::optional<probability_t> lookup() const;
|
||||
|
||||
std::vector<std::pair<Action, std::optional<probability_t>>> get_reasonable_actions();
|
||||
|
||||
auto operator<=>(const HanabiState &) const = default;
|
||||
|
||||
|
|
|
@ -451,6 +451,90 @@ namespace Hanabi {
|
|||
}
|
||||
}
|
||||
|
||||
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||
std::vector<std::pair<Action, std::optional<probability_t>>> HanabiState<num_suits, num_players, hand_size>::get_reasonable_actions() {
|
||||
std::vector<std::pair<Action, std::optional<probability_t>>> reasonable_actions {};
|
||||
|
||||
if(_score == 5 * num_suits or _pace < 0 or _endgame_turns_left == 0) {
|
||||
return reasonable_actions;
|
||||
}
|
||||
|
||||
const std::array<Card, hand_size>& hand = _hands[_turn];
|
||||
// First, check for playable cards
|
||||
for(std::uint8_t index = 0; index < hand_size; index++) {
|
||||
if(is_playable(hand[index])) {
|
||||
const Action action = {ActionType::play, hand[index]};
|
||||
bool known = true;
|
||||
probability_t sum_of_probabilities = 0;
|
||||
|
||||
do_for_each_potential_draw<true>(index, [this, &sum_of_probabilities, &known](const unsigned long multiplicity){
|
||||
const std::optional<probability_t> prob = lookup();
|
||||
if (prob.has_value()) {
|
||||
sum_of_probabilities += prob.value() * multiplicity;
|
||||
} else {
|
||||
known = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (known) {
|
||||
const unsigned long total_weight = std::max(static_cast<unsigned long>(_weighted_draw_pile_size), 1ul);
|
||||
const probability_t probability_play = sum_of_probabilities / total_weight;
|
||||
reasonable_actions.emplace_back(action, probability_play);
|
||||
} else {
|
||||
reasonable_actions.emplace_back(action, std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_pace > 0 and _num_clues < max_num_clues) {
|
||||
for(std::uint8_t index = 0; index < hand_size; index++) {
|
||||
if (is_trash(hand[index])) {
|
||||
const Action action = {ActionType::discard, hand[index]};
|
||||
bool known = true;
|
||||
probability_t sum_of_probabilities = 0;
|
||||
|
||||
do_for_each_potential_draw<false>(index, [this, &sum_of_probabilities, &known](const unsigned long multiplicity){
|
||||
const std::optional<probability_t> prob = lookup();
|
||||
if (prob.has_value()) {
|
||||
sum_of_probabilities += prob.value() * multiplicity;
|
||||
} else {
|
||||
known = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (known) {
|
||||
const unsigned long total_weight = std::max(static_cast<unsigned long>(_weighted_draw_pile_size), 1ul);
|
||||
const probability_t probability_discard = sum_of_probabilities / total_weight;
|
||||
reasonable_actions.emplace_back(action, probability_discard);
|
||||
} else {
|
||||
reasonable_actions.emplace_back(action, std::nullopt);
|
||||
}
|
||||
|
||||
// All discards are equivalent, do not continue searching for different trash
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_num_clues > 0) {
|
||||
clue();
|
||||
const std::optional<probability_t> prob = lookup();
|
||||
const Action action = {ActionType::clue, unknown_card};
|
||||
reasonable_actions.emplace_back(action, prob);
|
||||
const probability_t probability_stall = evaluate_state();
|
||||
revert_clue();
|
||||
}
|
||||
}
|
||||
|
||||
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||
std::optional<probability_t> HanabiState<num_suits, num_players, hand_size>::lookup() const {
|
||||
const auto id = unique_id();
|
||||
if(_position_tablebase.contains(id)) {
|
||||
return _position_tablebase[id];
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||
probability_t HanabiState<num_suits, num_players, hand_size>::evaluate_state() {
|
||||
|
|
Loading…
Reference in a new issue