add cli command to dump id parts

This commit is contained in:
Maximilian Keßler 2023-08-12 18:48:01 +02:00
parent 012b73879f
commit b1c1f41c6e
Signed by: max
GPG Key ID: BCC5A619923C0BA5
3 changed files with 85 additions and 17 deletions

View File

@ -220,6 +220,8 @@ public:
[[nodiscard]] virtual std::optional<probability_t> lookup() const = 0;
[[nodiscard]] virtual std::uint64_t unique_id() const = 0;
[[nodiscard]] virtual std::pair<std::vector<std::uint64_t>, std::vector<Card>> dump_unique_id_parts() const = 0;
virtual std::vector<std::pair<Action, std::optional<probability_t>>> get_reasonable_actions() = 0;
virtual std::vector<std::pair<CardMultiplicity, std::optional<probability_t>>> possible_next_states(hand_index_t index, bool play) = 0;
@ -264,8 +266,9 @@ public:
void init_backtracking_information() final;
probability_t evaluate_state() final;
std::optional<probability_t> lookup() const;
std::uint64_t unique_id() const final;
[[nodiscard]] std::optional<probability_t> lookup() const final;
[[nodiscard]] std::uint64_t unique_id() const final;
[[nodiscard]] std::pair<std::vector<std::uint64_t>, std::vector<Card>> dump_unique_id_parts() const final;
std::vector<std::pair<Action, std::optional<probability_t>>> get_reasonable_actions() final;
std::vector<std::pair<CardMultiplicity, std::optional<probability_t>>> possible_next_states(hand_index_t index, bool play) final;

View File

@ -816,6 +816,55 @@ namespace Hanabi {
return id;
}
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
std::pair<std::vector<std::uint64_t>, std::vector<Card>> HanabiState<num_suits, num_players, hand_size>::dump_unique_id_parts() const {
std::vector<std::uint64_t> ret;
std::vector<Card> cards;
// encode all positions of cards that started in draw pile
ASSERT(_relative_representation.card_positions_draw.size() == _relative_representation.good_cards_draw.size());
for(size_t i = 0; i < _relative_representation.card_positions_draw.size(); i++) {
for(player_t player : _relative_representation.card_positions_draw[i]) {
// We normalize here: If a card is already played, then the positions of its other copies
// do not matter, so we can just pretend that they are all in the trash already.
// The resulting states will be equivalent.
if (!is_trash(_relative_representation.good_cards_draw[i])) {
ret.push_back(player);
} else {
ret.push_back(trash_or_play_stack);
}
cards.push_back(_relative_representation.good_cards_draw[i]);
}
}
// encode number of clues
ret.push_back(_num_clues);
// we can encode draw pile size and extra turn in one metric, since we only have extra turns if draw pile is empty
const std::uint8_t draw_pile_size_and_extra_turns = [this]() -> uint8_t {
if(_endgame_turns_left == no_endgame) {
return _weighted_draw_pile_size + num_players;
}
else {
return _endgame_turns_left;
}
}();
ret.push_back(draw_pile_size_and_extra_turns);
// encode positions of cards that started in hands
ret.push_back(_relative_representation.card_positions_hands.to_ulong());
ret.push_back(_turn);
// The id is unique now, since for all relevant cards, we know their position (including if they are played),
// the number of clues, the draw pile size and whose turn it is.
// This already uniquely determines the current players position, assuming that we never discard good cards
// (and only play them)
return {ret, cards};
}
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
const std::unordered_map<unsigned long, probability_t>& HanabiState<num_suits, num_players, hand_size>::position_tablebase() const {
return _position_tablebase;

View File

@ -29,19 +29,20 @@ namespace Hanabi {
return ret;
}
constexpr static std::array<std::string, 12> cli_commands = {
constexpr static std::array<std::string, 13> cli_commands = {
"play",
"clue",
"discard",
"id",
"opt",
"state",
"id",
"revert",
"actions",
"evaluate",
"help",
"quit",
"initials",
"opt",
"set-initials",
"dump-id-parts",
};
char * cli_commands_generator(const char *text, int state) {
@ -152,16 +153,31 @@ namespace Hanabi {
add_history(prompt.c_str());
if (prompt.starts_with("help")) {
std::cout << "state: print information on current game state." << std::endl;
std::cout << "clue: give a clue." << std::endl;
std::cout << "play <card>: play specified card." << std::endl;
std::cout << "discard: discard trash from hand." << std::endl;
std::cout << "opt: take optimal action. In case of ties, prefers plays and discards in that order." << std::endl;
std::cout << "revert <turns>: revert specified number of turns (default 1)." << std::endl;
std::cout << "actions: display list of reasonable actions to take and their winning chances." << std::endl;
std::cout << "evaluate: evaluate current game state recursively. Potentially runtime-expensive." << std::endl;
std::cout << "id: display id of state. Has no inherent meaning, useful for debugging." << std::endl;
std::cout << "quit: Quit this interactive shell." << std::endl;
std::cout << "state: print information on current game state." << std::endl;
std::cout << "clue: give a clue." << std::endl;
std::cout << "play <card>: play specified card." << std::endl;
std::cout << "discard: discard trash from hand." << std::endl;
std::cout << "opt: take optimal action. In case of ties, prefers plays and discards in that order." << std::endl;
std::cout << "revert <turns>: revert specified number of turns (default 1)." << std::endl;
std::cout << "actions: display list of reasonable actions to take and their winning chances." << std::endl;
std::cout << "evaluate: evaluate current game state recursively. Potentially runtime-expensive." << std::endl;
std::cout << "set-initials <chars>: Set initials for the suits." << std::endl;
std::cout << "quit: Quit this interactive shell." << std::endl;
std::cout << "id: display id of state. Has no inherent meaning, useful for debugging." << std::endl;
std::cout << "dump-id-parts: Dump parts used to calculate the id of the state as well as the cards associated to them." << std::endl;
std::cout << "help: Display this help message." << std::endl;
continue;
}
if (prompt.starts_with("dump-id-parts")) {
for (const auto val: game->dump_unique_id_parts().first) {
std::cout << val << ", ";
}
std::cout << std::endl;
for (const auto card: game->dump_unique_id_parts().second) {
std::cout << card << " ";
}
std::cout << std::endl;
continue;
}
@ -171,7 +187,7 @@ namespace Hanabi {
break;
}
if (prompt.starts_with("initials")) {
if (prompt.starts_with("set-initials")) {
if (prompt.length() < 12) {
std::cout << "At least 3 initials need to be specified" << std::endl;
continue;