implement criticality of cards

This commit is contained in:
Maximilian Keßler 2024-01-12 14:27:16 +01:00
parent 8b42819704
commit 4ba61b0450
Signed by: max
GPG key ID: BCC5A619923C0BA5
3 changed files with 40 additions and 0 deletions

View file

@ -57,6 +57,9 @@ namespace Hanabi
[[nodiscard]] virtual bool is_trash(const Card & card) const = 0; [[nodiscard]] virtual bool is_trash(const Card & card) const = 0;
/** Returns whether the card is critical, assuming it is not trash already */
[[nodiscard]] virtual bool is_critical(const Card & card) const = 0;
[[nodiscard]] virtual bool is_playable(const Card & card) const = 0; [[nodiscard]] virtual bool is_playable(const Card & card) const = 0;
[[nodiscard]] virtual bool is_relative_state_initialized() const = 0; [[nodiscard]] virtual bool is_relative_state_initialized() const = 0;

View file

@ -106,6 +106,9 @@ namespace Hanabi
[[nodiscard]] bool is_trash(const Card & card) const final; [[nodiscard]] bool is_trash(const Card & card) const final;
/** Returns whether the card is critical, assuming that it is non-trash */
[[nodiscard]] bool is_critical(const Card & card) const final;
[[nodiscard]] bool is_playable(const Card & card) const final; [[nodiscard]] bool is_playable(const Card & card) const final;
[[nodiscard]] bool is_relative_state_initialized() const final; [[nodiscard]] bool is_relative_state_initialized() const final;
@ -230,6 +233,11 @@ namespace Hanabi
std::list<CardMultiplicity> _draw_pile{}; std::list<CardMultiplicity> _draw_pile{};
std::uint8_t _endgame_turns_left{}; std::uint8_t _endgame_turns_left{};
// This will actually not always be updated exactly, but only for those cards that are not
// trash yet, since for trash, this is simply not interesting.
// Thus, we only need to update this on discards or misplays.
CardArray<num_suits, int8_t> _num_copies_left {0};
// further values of game state that are technically determined, but we update them anyway // further values of game state that are technically determined, but we update them anyway
int8_t _pace{}; int8_t _pace{};
uint8_t _score{}; uint8_t _score{};

View file

@ -86,6 +86,17 @@ namespace Hanabi
incr_turn(); incr_turn();
} }
ASSERT(_turn == 0); ASSERT(_turn == 0);
// Prepare card counting
CardArray<num_suits, unsigned> card_multiplicities (0);
for (auto const hand: _hands) {
for (Card const card: hand) {
_num_copies_left[card] += 1;
}
}
for (CardMultiplicity const card_mult : _draw_pile) {
_num_copies_left[card_mult.card] += card_mult.multiplicity;
}
} }
template<suit_t num_suits, player_t num_players, hand_index_t hand_size> template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
@ -147,6 +158,12 @@ namespace Hanabi
return card.rank == _stacks[card.suit] - 1; return card.rank == _stacks[card.suit] - 1;
} }
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
bool HanabiState<num_suits, num_players, hand_size>::is_critical(Card const & card) const
{
return _num_copies_left[card] == 1;
}
template<suit_t num_suits, player_t num_players, hand_index_t hand_size> template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
std::uint64_t HanabiState<num_suits, num_players, hand_size>::enumerated_states() const std::uint64_t HanabiState<num_suits, num_players, hand_size>::enumerated_states() const
{ {
@ -186,6 +203,8 @@ namespace Hanabi
// update clues if we played the last played_card of a stack // update clues if we played the last played_card of a stack
_num_clues += _clues_gained_on_discard_or_stack_finished; _num_clues += _clues_gained_on_discard_or_stack_finished;
} }
} else {
_num_copies_left[played_card]--;
} }
const unsigned long multiplicity = draw(index, cycle, !strike); const unsigned long multiplicity = draw(index, cycle, !strike);
@ -213,6 +232,8 @@ namespace Hanabi
_num_clues += _clues_gained_on_discard_or_stack_finished; _num_clues += _clues_gained_on_discard_or_stack_finished;
_pace--; _pace--;
_num_copies_left[discarded_card]--;
unsigned long multiplicity = draw(index, cycle, false); unsigned long multiplicity = draw(index, cycle, false);
_actions_log.emplace(ActionType::discard, discarded_card, index); _actions_log.emplace(ActionType::discard, discarded_card, index);
@ -274,6 +295,9 @@ namespace Hanabi
for (hand_index_t index = 0; index < hand.size(); index++) for (hand_index_t index = 0; index < hand.size(); index++)
{ {
os << hand[index]; os << hand[index];
if (is_critical(hand[index])) {
os << "!";
}
if (index < hand.size() - 1) if (index < hand.size() - 1)
{ {
os << " "; os << " ";
@ -577,6 +601,9 @@ namespace Hanabi
{ {
_stacks[last_action.discarded.suit]++; _stacks[last_action.discarded.suit]++;
_score--; _score--;
} else {
// If we misplayed, then we lost the card and have to regain it now
_num_copies_left[last_action.discarded]++;
} }
check_draw_pile_integrity(); check_draw_pile_integrity();
} }
@ -597,6 +624,8 @@ namespace Hanabi
_pace++; _pace++;
_num_copies_left[last_action.discarded]++;
revert_draw(last_action.index, last_action.discarded, cycle, false); revert_draw(last_action.index, last_action.discarded, cycle, false);
check_draw_pile_integrity(); check_draw_pile_integrity();
} }