diff --git a/include/game_state.h b/include/game_state.h index e1476eb..43d8c3e 100644 --- a/include/game_state.h +++ b/include/game_state.h @@ -62,6 +62,20 @@ namespace Hanabi std::array _array{}; }; + struct HanabiStateConfig + { + /** What score to consider as a win. If left empty, automatically replaced by max score on construction. */ + std::optional score_goal; + /** The number of clues gained when a stack is finished or a card is discarded. Usually 1, 1/2 in clue starved. */ + clue_t num_clues_gained_on_discard_or_stack_finished {1}; + /** + * If set to true, only roughly half of the game states will be stored in the internal lookup table. + * This results in roughly halving memory consumption at the cost of roughly a factor 3-5 in execution speed + * (the slowdown is theoretically bounded to visiting at most 9 times the number of states if this option is activated). + * You should typically never need this, unless you are very specifically short on memory and. + * */ + bool save_memory {false}; + }; // A game mimics a game state together with a list of actions and allows to traverse the game // history by making and reverting the stored actions. @@ -71,7 +85,7 @@ namespace Hanabi public: HanabiState() = default; - explicit HanabiState(const std::vector & deck, uint8_t score_goal = 5 * num_suits, clue_t num_clues_gained_on_discard_or_stack_finished = 1); + explicit HanabiState(const std::vector & deck, HanabiStateConfig config = HanabiStateConfig()); void give_clue() final; @@ -263,10 +277,10 @@ namespace Hanabi RelativeRepresentationData _relative_representation; // Lookup table for states. Uses the ids calculated using the relative representation + bool const _save_memory; map_type _position_tablebase; std::uint64_t _enumerated_states{}; - }; template diff --git a/include/game_state.hpp b/include/game_state.hpp index 7d68268..c414d77 100644 --- a/include/game_state.hpp +++ b/include/game_state.hpp @@ -75,11 +75,11 @@ namespace Hanabi } template - HanabiState::HanabiState(const std::vector & deck, uint8_t score_goal, clue_t num_clues_gained_on_discard_or_stack_finished): - _clues_gained_on_discard_or_stack_finished(num_clues_gained_on_discard_or_stack_finished) - , _score_goal(score_goal), _turn(0), _num_clues(max_num_clues), _num_strikes(0), _weighted_draw_pile_size(deck.size()), _stacks(), _hands(), _draw_pile() - , _endgame_turns_left(no_endgame), _pace(deck.size() - score_goal - num_players * (hand_size - 1)), _score(0) - , _actions_log(), _relative_representation(), _position_tablebase() + HanabiState::HanabiState(const std::vector & deck, HanabiStateConfig config): + _clues_gained_on_discard_or_stack_finished(config.num_clues_gained_on_discard_or_stack_finished) + , _score_goal(config.score_goal.value_or(num_suits * 5)), _turn(0), _num_clues(max_num_clues), _num_strikes(0), _weighted_draw_pile_size(deck.size()), _stacks(), _hands(), _draw_pile() + , _endgame_turns_left(no_endgame), _pace(deck.size() - _score_goal - num_players * (hand_size - 1)), _score(0) + , _actions_log(), _relative_representation(), _save_memory(config.save_memory), _position_tablebase() , _enumerated_states(0) { std::fill(_stacks.begin(), _stacks.end(), starting_card_rank); @@ -985,8 +985,14 @@ namespace Hanabi template bool HanabiState::save_state_to_map() { - return true; - return _draw_pile.size() != 2; + if (_save_memory) + { + return _weighted_draw_pile_size % 2 == 0; + } + else + { + return true; + } } template