diff --git a/game_state.h b/game_state.h index 7a73e2b..43ba301 100644 --- a/game_state.h +++ b/game_state.h @@ -180,7 +180,7 @@ public: std::uint8_t _weighted_draw_pile_size{}; Stacks _stacks{}; std::array, num_players> _hands{}; - CardArray _card_positions{}; +// CardArray _card_positions{}; std::list _draw_pile{}; std::uint8_t endgame_turns_left; @@ -193,6 +193,17 @@ public: auto operator<=>(const HanabiState &) const = default; }; +template +bool same_up_to_discard_permutation(HanabiState state1, HanabiState state2) { + auto comp = [](CardMultiplicity &m1, CardMultiplicity &m2) -> bool { + return m1.card.suit < m2.card.suit || (m1.card.suit == m2.card.suit and m1.card.rank < m2.card.rank) || + (m1.card.suit == m2.card.suit and m1.card.rank == m2.card.rank and m1.multiplicity < m2.multiplicity); + }; + state1._draw_pile.sort(comp); + state2._draw_pile.sort(comp); + return state1 == state2; +} + template std::ostream & operator<<(std::ostream &os, HanabiState hanabi_state); diff --git a/game_state.hpp b/game_state.hpp index 957524f..d9a4ef7 100644 --- a/game_state.hpp +++ b/game_state.hpp @@ -64,7 +64,7 @@ namespace Hanabi { _weighted_draw_pile_size(deck.size()), _stacks(), _hands(), - _card_positions(draw_pile), +// _card_positions(draw_pile), _draw_pile(), _pace(deck.size() - 5 * num_suits - num_players * (hand_size - 1)), _score(0) { @@ -199,7 +199,7 @@ namespace Hanabi { const Card& discarded = _hands[_turn][index]; if (_stacks[discarded.suit] > discarded.rank) { - _card_positions[_hands[_turn][index]] = trash_or_play_stack; +// _card_positions[_hands[_turn][index]] = trash_or_play_stack; } // draw a new card if the draw pile is not empty @@ -220,7 +220,7 @@ namespace Hanabi { card_in_hand.copy = draw.multiplicity - 1; if (_stacks[draw.card.suit] > draw.card.rank) { - _card_positions[card_in_hand] = _turn; +// _card_positions[card_in_hand] = _turn; } if(_draw_pile.empty()) { @@ -238,7 +238,7 @@ namespace Hanabi { assert(index < _hands[_turn].size()); const Card &drawn = _hands[_turn][index]; if (_stacks[drawn.suit] > drawn.rank) { - _card_positions[drawn] = draw_pile; +// _card_positions[drawn] = draw_pile; } // put discarded_card back into draw pile (at the back) @@ -253,7 +253,7 @@ namespace Hanabi { endgame_turns_left = no_endgame; _hands[_turn][index] = discarded_card; if (_stacks[discarded_card.suit] > discarded_card.rank) { - _card_positions[discarded_card] = _turn; +// _card_positions[discarded_card] = _turn; } } @@ -286,7 +286,7 @@ namespace Hanabi { _draw_pile.push_back({card, nums_in_draw_pile[card]}); for (std::uint8_t copy = 0; copy < nums_in_draw_pile[card]; copy++) { card.copy = copy; - _card_positions[card] = draw_pile; +// _card_positions[card] = draw_pile; } } } @@ -357,18 +357,22 @@ namespace Hanabi { if(is_playable(hand[index])) { std::cout << std::string("---------------------", depth) << "playing " << hand[index] << std::endl; if (_draw_pile.empty()) { + auto copy = *this; BacktrackAction action = play(index); const double probability_for_this_play = backtrack(depth + 1); revert(action); + assert(same_up_to_discard_permutation(*this, copy)); UPDATE_PROBABILITY(probability_for_this_play); } else { double sum_of_probabilities = 0; uint8_t sum_of_mults = 0; for (size_t i = 0; i < _draw_pile.size(); i++) { + auto copy = *this; BacktrackAction action = play(index); sum_of_probabilities += backtrack(depth + 1) * action.multiplicity; sum_of_mults += action.multiplicity; revert(action); + assert(same_up_to_discard_permutation(*this, copy)); assert(sum_of_mults <= _weighted_draw_pile_size); } assert(sum_of_mults == _weighted_draw_pile_size); @@ -385,17 +389,21 @@ namespace Hanabi { std::cout << std::string("---------------------------", depth) << "discarding " << hand[index] << std::endl; double sum_of_probabilities = 0; if (_draw_pile.empty()) { + auto copy = *this; BacktrackAction action = discard(index); const double probability_for_this_discard = backtrack(depth + 1); revert(action); + assert(same_up_to_discard_permutation(*this, copy)); UPDATE_PROBABILITY(probability_for_this_discard); } else { uint8_t sum_of_mults = 0; for (size_t i = 0; i < _draw_pile.size(); i++) { + auto copy = *this; BacktrackAction action = discard(index); sum_of_probabilities += backtrack(depth + 1) * action.multiplicity; sum_of_mults += action.multiplicity; revert(action); + assert(same_up_to_discard_permutation(*this, copy)); } assert(sum_of_mults == _weighted_draw_pile_size); const double probability_discard = sum_of_probabilities / _weighted_draw_pile_size; @@ -411,9 +419,11 @@ namespace Hanabi { // Last option is to stall if(_num_clues > 0) { std::cout << std::string("--------------------", depth) << "stalling " << std::endl; + auto copy = *this; BacktrackAction action = clue(); const double probability_stall = backtrack(depth + 1); revert(action); + assert(same_up_to_discard_permutation(*this, copy)); UPDATE_PROBABILITY(probability_stall); } diff --git a/main.cpp b/main.cpp index 838dac3..6b5c2bc 100644 --- a/main.cpp +++ b/main.cpp @@ -21,7 +21,7 @@ void test_game() { state._draw_pile.push_back({r41, 1}); state._hands[0] = {y0, y1, y2, r0, r1}; state._hands[1] = {r1, r1, y1, r3, r2}; - state._card_positions[r1] = 0; +// state._card_positions[r1] = 0; state._weighted_draw_pile_size = 1; auto state2 = state; @@ -34,7 +34,7 @@ void test_game() { std::cout << state2 << std::endl; assert(state._hands == state2._hands); assert(state._draw_pile == state2._draw_pile); - assert(state._card_positions == state2._card_positions); +// assert(state._card_positions == state2._card_positions); assert(state == state2); }