Introduce option for HanabiState to save memory

This commit is contained in:
Maximilian Keßler 2024-02-08 21:54:39 +01:00
parent 27922de8e8
commit bfc731ae36
Signed by: max
GPG Key ID: BCC5A619923C0BA5
2 changed files with 29 additions and 9 deletions

View File

@ -62,6 +62,20 @@ namespace Hanabi
std::array<inner_array_t, num_suits> _array{};
};
struct HanabiStateConfig
{
/** What score to consider as a win. If left empty, automatically replaced by max score on construction. */
std::optional<uint8_t> 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<Card> & deck, uint8_t score_goal = 5 * num_suits, clue_t num_clues_gained_on_discard_or_stack_finished = 1);
explicit HanabiState(const std::vector<Card> & 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<unsigned long, probability_t> _position_tablebase;
std::uint64_t _enumerated_states{};
};
template<std::size_t num_suits, player_t num_players, std::size_t hand_size>

View File

@ -75,11 +75,11 @@ namespace Hanabi
}
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
HanabiState<num_suits, num_players, hand_size>::HanabiState(const std::vector<Card> & 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<num_suits, num_players, hand_size>::HanabiState(const std::vector<Card> & 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<suit_t num_suits, player_t num_players, hand_index_t hand_size>
bool HanabiState<num_suits, num_players, hand_size>::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<suit_t num_suits, player_t num_players, hand_index_t hand_size>