diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f10524..70bdf75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,8 @@ add_executable(endgame-analyzer src/main.cpp src/state_explorer.cpp src/download include/game_interface.h src/hanabi_types.cpp src/game_interface.cpp + include/make_state.h + src/make_state.cpp ) target_link_libraries(endgame-analyzer cpr) diff --git a/include/make_state.h b/include/make_state.h new file mode 100644 index 0000000..5ef80e0 --- /dev/null +++ b/include/make_state.h @@ -0,0 +1,33 @@ +#ifndef DYNAMIC_PROGRAM_MAKE_STATE_H +#define DYNAMIC_PROGRAM_MAKE_STATE_H + +#include + +#include "game_interface.h" + +namespace Hanabi +{ + /** + * @brief Produces a game state from specified parms. + * @param num_suits: Has to be in [3,6] + * @param num_players Has to be in [2,6] + * @param deck A list of cards with at most as many suits as num_suits + * @param score_goal What is considered as an optimal score for this game state. + * If null, the maximum score is inserted + * @return Pointer to created game state, wrapped into abstract interface + * + * @note Since the implementation of the actual game state (the concrete class derived from HanabiStateIF), + * is heavily templated, this function has its own header + source file to reduce compilation time + * for all components using this, since there is now only one place where the templated implementation + * is actually compiled and has not be recompiled upon other program parts changing. + */ + std::unique_ptr make_game_state( + std::size_t num_suits, + Hanabi::player_t num_players, + std::vector const &deck, + std::optional score_goal = std::nullopt + ); +} + + +#endif //DYNAMIC_PROGRAM_MAKE_STATE_H diff --git a/src/download.cpp b/src/download.cpp index c273ec3..8838a2a 100644 --- a/src/download.cpp +++ b/src/download.cpp @@ -2,7 +2,7 @@ #include #include "parse_game.h" -#include "game_state.h" +#include "make_state.h" #include "download.h" @@ -27,82 +27,6 @@ namespace Download { return boost::json::parse(game_json).as_object(); } - std::unique_ptr get_base_state( - std::size_t num_suits, - Hanabi::player_t num_players, - std::vector const & deck, - std::optional score_goal) { - uint8_t actual_score_goal = score_goal.value_or(5 * num_suits); - switch(num_players) { - case 2: - switch(num_suits) { - case 3: - return std::unique_ptr(new Hanabi::HanabiState<3,2,5>(deck, actual_score_goal)); - case 4: - return std::unique_ptr(new Hanabi::HanabiState<4,2,5>(deck, actual_score_goal)); - case 5: - return std::unique_ptr(new Hanabi::HanabiState<5,2,5>(deck, actual_score_goal)); - case 6: - return std::unique_ptr(new Hanabi::HanabiState<6,2,5>(deck, actual_score_goal)); - default: - throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); - } - case 3: - switch(num_suits) { - case 3: - return std::unique_ptr(new Hanabi::HanabiState<3,3,5>(deck, actual_score_goal)); - case 4: - return std::unique_ptr(new Hanabi::HanabiState<4,3,5>(deck, actual_score_goal)); - case 5: - return std::unique_ptr(new Hanabi::HanabiState<5,3,5>(deck, actual_score_goal)); - case 6: - return std::unique_ptr(new Hanabi::HanabiState<6,3,5>(deck, actual_score_goal)); - default: - throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); - } - case 4: - switch(num_suits) { - case 3: - return std::unique_ptr(new Hanabi::HanabiState<3,4,4>(deck, actual_score_goal)); - case 4: - return std::unique_ptr(new Hanabi::HanabiState<4,4,4>(deck, actual_score_goal)); - case 5: - return std::unique_ptr(new Hanabi::HanabiState<5,4,4>(deck, actual_score_goal)); - case 6: - return std::unique_ptr(new Hanabi::HanabiState<6,4,4>(deck, actual_score_goal)); - default: - throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); - } - case 5: - switch(num_suits) { - case 3: - return std::unique_ptr(new Hanabi::HanabiState<3,5,4>(deck, actual_score_goal)); - case 4: - return std::unique_ptr(new Hanabi::HanabiState<4,5,4>(deck, actual_score_goal)); - case 5: - return std::unique_ptr(new Hanabi::HanabiState<5,5,4>(deck, actual_score_goal)); - case 6: - return std::unique_ptr(new Hanabi::HanabiState<6,5,4>(deck, actual_score_goal)); - default: - throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); - } - case 6: - switch(num_suits) { - case 3: - return std::unique_ptr(new Hanabi::HanabiState<3,6,3>(deck, actual_score_goal)); - case 4: - return std::unique_ptr(new Hanabi::HanabiState<4,6,3>(deck, actual_score_goal)); - case 5: - return std::unique_ptr(new Hanabi::HanabiState<5,6,3>(deck, actual_score_goal)); - case 6: - return std::unique_ptr(new Hanabi::HanabiState<6,6,3>(deck, actual_score_goal)); - default: - throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); - } - default: - throw std::runtime_error("Invalid number of players: " + std::to_string(num_players)); - } - } Hanabi::Game get_game(std::variant game_spec, std::optional score_goal){ const std::optional game_json_opt = [&game_spec]() { @@ -118,7 +42,7 @@ namespace Download { } Hanabi::GameInfo game_info = Parsing::parse_game(game_json_opt.value()); - return {get_base_state(game_info.num_suits, game_info.num_players, game_info.deck, score_goal), game_info}; + return {make_game_state(game_info.num_suits, game_info.num_players, game_info.deck, score_goal), game_info}; } } // namespace Download diff --git a/src/make_state.cpp b/src/make_state.cpp new file mode 100644 index 0000000..8ef5824 --- /dev/null +++ b/src/make_state.cpp @@ -0,0 +1,83 @@ +#include "game_state.h" +#include "game_interface.h" + +namespace Hanabi { + std::unique_ptr make_game_state( + std::size_t num_suits, + Hanabi::player_t num_players, + std::vector const &deck, + std::optional score_goal) + { + uint8_t actual_score_goal = score_goal.value_or(5 * num_suits); + switch(num_players) { + case 2: + switch(num_suits) { + case 3: + return std::unique_ptr(new Hanabi::HanabiState<3,2,5>(deck, actual_score_goal)); + case 4: + return std::unique_ptr(new Hanabi::HanabiState<4,2,5>(deck, actual_score_goal)); + case 5: + return std::unique_ptr(new Hanabi::HanabiState<5,2,5>(deck, actual_score_goal)); + case 6: + return std::unique_ptr(new Hanabi::HanabiState<6,2,5>(deck, actual_score_goal)); + default: + throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); + } + case 3: + switch(num_suits) { + case 3: + return std::unique_ptr(new Hanabi::HanabiState<3,3,5>(deck, actual_score_goal)); + case 4: + return std::unique_ptr(new Hanabi::HanabiState<4,3,5>(deck, actual_score_goal)); + case 5: + return std::unique_ptr(new Hanabi::HanabiState<5,3,5>(deck, actual_score_goal)); + case 6: + return std::unique_ptr(new Hanabi::HanabiState<6,3,5>(deck, actual_score_goal)); + default: + throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); + } + case 4: + switch(num_suits) { + case 3: + return std::unique_ptr(new Hanabi::HanabiState<3,4,4>(deck, actual_score_goal)); + case 4: + return std::unique_ptr(new Hanabi::HanabiState<4,4,4>(deck, actual_score_goal)); + case 5: + return std::unique_ptr(new Hanabi::HanabiState<5,4,4>(deck, actual_score_goal)); + case 6: + return std::unique_ptr(new Hanabi::HanabiState<6,4,4>(deck, actual_score_goal)); + default: + throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); + } + case 5: + switch(num_suits) { + case 3: + return std::unique_ptr(new Hanabi::HanabiState<3,5,4>(deck, actual_score_goal)); + case 4: + return std::unique_ptr(new Hanabi::HanabiState<4,5,4>(deck, actual_score_goal)); + case 5: + return std::unique_ptr(new Hanabi::HanabiState<5,5,4>(deck, actual_score_goal)); + case 6: + return std::unique_ptr(new Hanabi::HanabiState<6,5,4>(deck, actual_score_goal)); + default: + throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); + } + case 6: + switch(num_suits) { + case 3: + return std::unique_ptr(new Hanabi::HanabiState<3,6,3>(deck, actual_score_goal)); + case 4: + return std::unique_ptr(new Hanabi::HanabiState<4,6,3>(deck, actual_score_goal)); + case 5: + return std::unique_ptr(new Hanabi::HanabiState<5,6,3>(deck, actual_score_goal)); + case 6: + return std::unique_ptr(new Hanabi::HanabiState<6,6,3>(deck, actual_score_goal)); + default: + throw std::runtime_error("Invalid number of suits: " + std::to_string(num_suits)); + } + default: + throw std::runtime_error("Invalid number of players: " + std::to_string(num_players)); + } + } +} +