implement discarding dupes and sacrifice discards
This commit is contained in:
parent
43477b1023
commit
8398173939
1 changed files with 68 additions and 18 deletions
|
@ -194,7 +194,7 @@ namespace Hanabi
|
||||||
|
|
||||||
_actions_log.emplace(ActionType::play, played_card, index, _num_clues == 8, strike);
|
_actions_log.emplace(ActionType::play, played_card, index, _num_clues == 8, strike);
|
||||||
|
|
||||||
if (is_playable(played_card))
|
if (!strike)
|
||||||
{
|
{
|
||||||
--_stacks[played_card.suit];
|
--_stacks[played_card.suit];
|
||||||
_score++;
|
_score++;
|
||||||
|
@ -951,31 +951,81 @@ namespace Hanabi
|
||||||
// Check for discards now
|
// Check for discards now
|
||||||
if (_pace > 0 and _num_clues < max_num_clues)
|
if (_pace > 0 and _num_clues < max_num_clues)
|
||||||
{
|
{
|
||||||
for (std::uint8_t index = 0; index < hand_size; index++)
|
// This will hold the index of trash to discard
|
||||||
|
std::uint8_t const invalid_index = std::numeric_limits<std::uint8_t>::max();
|
||||||
|
std::uint8_t discard_index = invalid_index;
|
||||||
|
|
||||||
|
for (hand_index_t index = 0; index < hand_size; index++)
|
||||||
{
|
{
|
||||||
if (is_trash(hand[index]))
|
if (is_trash(hand[index]))
|
||||||
{
|
{
|
||||||
probability_t sum_of_probabilities = 0;
|
discard_index = index;
|
||||||
|
|
||||||
do_for_each_potential_draw(index, false, [this, &sum_of_probabilities](const unsigned long multiplicity) {
|
|
||||||
sum_of_probabilities += evaluate_state() * multiplicity;
|
|
||||||
});
|
|
||||||
|
|
||||||
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;
|
|
||||||
best_probability = std::max(best_probability, probability_discard);
|
|
||||||
|
|
||||||
best_probability = std::max(best_probability, probability_discard);
|
|
||||||
if (best_probability == 1)
|
|
||||||
{
|
|
||||||
update_tablebase(id_of_state, best_probability);
|
|
||||||
return best_probability;
|
|
||||||
};
|
|
||||||
|
|
||||||
// All discards are equivalent, do not continue searching for different trash
|
// All discards are equivalent, do not continue searching for different trash
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no trivial trash found, check for duplicates next
|
||||||
|
if (discard_index == invalid_index) {
|
||||||
|
for (std::uint8_t index = 0; index < hand_size; index++) {
|
||||||
|
Card const card = _hands[_turn][index];
|
||||||
|
auto it = std::find_if(_hands[_turn].begin() + index + 1, _hands[_turn].end(), [&card, this](Card const & card_in_hand) {
|
||||||
|
return card_in_hand == card;
|
||||||
|
});
|
||||||
|
if (it != _hands[_turn].end()) {
|
||||||
|
// found a duplicate to discard
|
||||||
|
discard_index = index;
|
||||||
|
// Since we are discarding essentially trash, we do not have to consider further actions
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discard if we found trash now
|
||||||
|
if (discard_index != invalid_index) {
|
||||||
|
probability_t sum_of_probabilities = 0;
|
||||||
|
|
||||||
|
do_for_each_potential_draw(discard_index, false, [this, &sum_of_probabilities](const unsigned long multiplicity) {
|
||||||
|
sum_of_probabilities += evaluate_state() * multiplicity;
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
best_probability = std::max(best_probability, probability_discard);
|
||||||
|
|
||||||
|
best_probability = std::max(best_probability, probability_discard);
|
||||||
|
if (best_probability == 1)
|
||||||
|
{
|
||||||
|
update_tablebase(id_of_state, best_probability);
|
||||||
|
return best_probability;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// If we reach this state, then there are no dupes in hand, so we need to check if we want to
|
||||||
|
// sacrifice cards in hand
|
||||||
|
for(hand_index_t index = 0; index < hand_size; ++index) {
|
||||||
|
if(!is_critical(hand[index])) {
|
||||||
|
std::cout << "Considered sacrificing card " << hand[index] << "in the following state:\n" << *this << std::endl;
|
||||||
|
// consider discarding this
|
||||||
|
probability_t sum_of_probabilities = 0;
|
||||||
|
|
||||||
|
do_for_each_potential_draw(index, false, [this, &sum_of_probabilities](const unsigned long multiplicity) {
|
||||||
|
sum_of_probabilities += evaluate_state() * multiplicity;
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
best_probability = std::max(best_probability, probability_discard);
|
||||||
|
|
||||||
|
best_probability = std::max(best_probability, probability_discard);
|
||||||
|
if (best_probability == 1)
|
||||||
|
{
|
||||||
|
update_tablebase(id_of_state, best_probability);
|
||||||
|
return best_probability;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last option is to stall
|
// Last option is to stall
|
||||||
|
|
Loading…
Reference in a new issue