#ifndef DYNAMIC_PROGRAM_GAME_INTERFACE_H #define DYNAMIC_PROGRAM_GAME_INTERFACE_H #include #include #include #include #include "hanabi_types.hpp" namespace Hanabi { /** * A card together with an associated multiplicity */ struct CardMultiplicity { Card card; unsigned multiplicity; bool operator==(const CardMultiplicity &) const; bool operator!=(const CardMultiplicity &) const; }; 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}; }; class HanabiStateIF { public: virtual void give_clue() = 0; virtual void discard(hand_index_t index) = 0; virtual void play(hand_index_t index) = 0; virtual void rotate_next_draw(const Card & card) = 0; [[nodiscard]] virtual ActionType last_action_type() const = 0; virtual void revert() = 0; virtual void modify_clues(clue_t change) = 0; virtual void set_clues(clue_t clues) = 0; [[nodiscard]] virtual player_t turn() const = 0; [[nodiscard]] virtual clue_t num_clues() const = 0; [[nodiscard]] virtual unsigned num_strikes() const = 0; [[nodiscard]] virtual unsigned score() const = 0; [[nodiscard]] virtual std::vector> hands() const = 0; [[nodiscard]] virtual std::vector cur_hand() const = 0; [[nodiscard]] virtual size_t draw_pile_size() const = 0; [[nodiscard]] virtual bool is_trash(const Card & card) const = 0; /** Returns whether the card is critical, assuming it is not trash already */ [[nodiscard]] virtual bool is_critical(const Card & card) const = 0; [[nodiscard]] virtual bool is_playable(const Card & card) const = 0; [[nodiscard]] virtual bool is_relative_state_initialized() const = 0; [[nodiscard]] virtual hand_index_t find_card_in_hand(const Card & card) const = 0; [[nodiscard]] virtual std::uint64_t enumerated_states() const = 0; [[nodiscard]] virtual const map_type & position_tablebase() const = 0; virtual void init_backtracking_information() = 0; virtual probability_t evaluate_state() = 0; [[nodiscard]] virtual std::optional lookup() const = 0; [[nodiscard]] virtual std::uint64_t unique_id() const = 0; [[nodiscard]] virtual std::pair, std::vector> dump_unique_id_parts() const = 0; virtual std::vector>> get_reasonable_actions(bool evaluate_all = false, bool reasonable = true) = 0; virtual std::vector>> possible_next_states(hand_index_t index, bool play) = 0; virtual ~HanabiStateIF() = default; protected: virtual void print(std::ostream & os) const = 0; friend std::ostream & operator<<(std::ostream &, HanabiStateIF const &); }; std::ostream & operator<<(std::ostream & os, HanabiStateIF const & hanabi_state); struct GameInfo { std::vector deck; std::vector actions; Hanabi::suit_t num_suits; Hanabi::player_t num_players; clue_t num_clues_gained_per_discard_or_stack_finished; }; struct Game : private GameInfo { public: Game(std::unique_ptr state, GameInfo game_info); [[nodiscard]] unsigned cur_turn() const; [[nodiscard]] unsigned num_turns() const; void make_turn(); void revert_turn(); bool goto_draw_pile_size(size_t draw_pile_break); bool goto_turn(size_t turn); [[nodiscard]] bool holds_state() const; std::unique_ptr state; unsigned next_action; }; } #endif //DYNAMIC_PROGRAM_GAME_INTERFACE_H