bugfix: card cycling on reverting only used internally

This ensures that when doing a regular revert,
we revert to exactly the same state (i.e. also identical
ordering of draw pile by default)
and only rotate the draw pile in case we ensure internally
that we iterate over all possible draws so that the ordering
is restored in the end.
This commit is contained in:
Maximilian Keßler 2023-11-11 12:15:54 +01:00
parent b6a2dfb855
commit 5b0834bc22
Signed by: max
GPG key ID: BCC5A619923C0BA5
2 changed files with 29 additions and 16 deletions

View file

@ -368,10 +368,10 @@ private:
unsigned draw(hand_index_t index); unsigned draw(hand_index_t index);
void revert_draw(hand_index_t index, Card discarded_card); void revert_draw(hand_index_t index, Card discarded_card, bool cycle = false);
void revert_clue(); void revert_clue();
void revert_discard(); void revert_discard(bool cycle = false);
void revert_play(); void revert_play(bool cycle = false);
void update_tablebase(unsigned long id, probability_t probability); void update_tablebase(unsigned long id, probability_t probability);

View file

@ -362,18 +362,29 @@ namespace Hanabi {
} }
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>
void HanabiState<num_suits, num_players, hand_size>::revert_draw(std::uint8_t index, Card discarded_card) { void HanabiState<num_suits, num_players, hand_size>::revert_draw(std::uint8_t index, Card discarded_card, bool cycle) {
if (_endgame_turns_left == num_players + 1 || _endgame_turns_left == no_endgame) { if (_endgame_turns_left == num_players + 1 || _endgame_turns_left == no_endgame) {
// Put the card that is currently in hand back into the draw pile // Put the card that is currently in hand back into the draw pile
ASSERT(index < _hands[_turn].size()); ASSERT(index < _hands[_turn].size());
const Card &drawn = _hands[_turn][index]; const Card &drawn = _hands[_turn][index];
// put discarded_card back into draw pile (at the back) if (cycle)
if (!_draw_pile.empty() and _draw_pile.back().card.suit == drawn.suit and {
_draw_pile.back().card.rank == drawn.rank) { // put discarded_card back into draw pile (at the back)
_draw_pile.back().multiplicity++; if (!_draw_pile.empty() and _draw_pile.back().card.suit == drawn.suit and
} else { _draw_pile.back().card.rank == drawn.rank) {
_draw_pile.push_back({drawn, 1}); _draw_pile.back().multiplicity++;
} else {
_draw_pile.push_back({drawn, 1});
}
} else
{
if (!_draw_pile.empty() and _draw_pile.front().card.suit == drawn.suit and
_draw_pile.front().card.rank == drawn.rank) {
_draw_pile.front().multiplicity++;
} else {
_draw_pile.push_front({drawn, 1});
}
} }
if (_relative_representation.initialized && !drawn.initial_trash) { if (_relative_representation.initialized && !drawn.initial_trash) {
@ -473,7 +484,7 @@ namespace Hanabi {
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>
void void
HanabiState<num_suits, num_players, hand_size>::revert_play() { HanabiState<num_suits, num_players, hand_size>::revert_play(bool cycle) {
check_draw_pile_integrity(); check_draw_pile_integrity();
const BacktrackAction last_action = _actions_log.top(); const BacktrackAction last_action = _actions_log.top();
_actions_log.pop(); _actions_log.pop();
@ -484,7 +495,7 @@ namespace Hanabi {
if (last_action.discarded.rank == 0 and not last_action.was_on_8_clues) { if (last_action.discarded.rank == 0 and not last_action.was_on_8_clues) {
_num_clues--; _num_clues--;
} }
revert_draw(last_action.index, last_action.discarded); revert_draw(last_action.index, last_action.discarded, cycle);
if(_stacks[last_action.discarded.suit] == last_action.discarded.rank) { if(_stacks[last_action.discarded.suit] == last_action.discarded.rank) {
_stacks[last_action.discarded.suit]++; _stacks[last_action.discarded.suit]++;
} }
@ -493,7 +504,7 @@ namespace Hanabi {
} }
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>
void HanabiState<num_suits, num_players, hand_size>::revert_discard() { void HanabiState<num_suits, num_players, hand_size>::revert_discard(bool cycle) {
check_draw_pile_integrity(); check_draw_pile_integrity();
const BacktrackAction last_action = _actions_log.top(); const BacktrackAction last_action = _actions_log.top();
_actions_log.pop(); _actions_log.pop();
@ -506,7 +517,7 @@ namespace Hanabi {
_num_clues--; _num_clues--;
_pace++; _pace++;
revert_draw(last_action.index, last_action.discarded); revert_draw(last_action.index, last_action.discarded, cycle);
check_draw_pile_integrity(); check_draw_pile_integrity();
} }
@ -800,6 +811,7 @@ namespace Hanabi {
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>
template<class Function> template<class Function>
void HanabiState<num_suits, num_players, hand_size>::do_for_each_potential_draw(hand_index_t index, bool play, Function f) { void HanabiState<num_suits, num_players, hand_size>::do_for_each_potential_draw(hand_index_t index, bool play, Function f) {
auto copy = _draw_pile;
auto do_action = [this, index, play](){ auto do_action = [this, index, play](){
if (play) { if (play) {
return play_and_potentially_update(index); return play_and_potentially_update(index);
@ -810,9 +822,9 @@ namespace Hanabi {
auto revert_action = [this, play](){ auto revert_action = [this, play](){
if (play) { if (play) {
revert_play(); revert_play(true);
} else { } else {
revert_discard(); revert_discard(true);
} }
}; };
@ -831,6 +843,7 @@ namespace Hanabi {
} }
ASSERT(sum_of_multiplicities == _weighted_draw_pile_size); ASSERT(sum_of_multiplicities == _weighted_draw_pile_size);
} }
ASSERT(_draw_pile == copy);
} }
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>