diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b8ebc1..e0e2b45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.16) project(endgame-analyzer CXX) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wpedantic -Werror") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DGAME_STATE_NO_TABLEBASE_LOOKUP") diff --git a/include/game_interface.h b/include/game_interface.h index ab831f5..44ce794 100644 --- a/include/game_interface.h +++ b/include/game_interface.h @@ -21,7 +21,8 @@ namespace Hanabi Card card; unsigned multiplicity; - bool operator==(const CardMultiplicity &) const = default; + bool operator==(const CardMultiplicity &) const; + bool operator!=(const CardMultiplicity &) const; }; class HanabiStateIF diff --git a/include/game_state.h b/include/game_state.h index b3e11f7..4d55682 100644 --- a/include/game_state.h +++ b/include/game_state.h @@ -56,7 +56,7 @@ namespace Hanabi value_type & operator[](const Card & card); - auto operator<=>(const CardArray &) const = default; + //auto operator<=>(const CardArray &) const = default; private: using inner_array_t = typename InnerCardArray::template array_t; @@ -132,7 +132,7 @@ namespace Hanabi std::vector>> possible_next_states(hand_index_t index, bool play) final; - auto operator<=>(const HanabiState &) const = default; + //auto operator<=>(const HanabiState &) const = default; protected: void print(std::ostream & os) const final; diff --git a/include/game_state.hpp b/include/game_state.hpp index ffd2574..53187c7 100644 --- a/include/game_state.hpp +++ b/include/game_state.hpp @@ -82,7 +82,7 @@ namespace Hanabi , _actions_log(), _relative_representation(), _position_tablebase() , _enumerated_states(0) { - std::ranges::fill(_stacks, starting_card_rank); + std::fill(_stacks.begin(), _stacks.end(), starting_card_rank); for (const Card & card: deck) { _draw_pile.push_back({card, 1}); @@ -347,8 +347,11 @@ namespace Hanabi } else { - auto replaced_card_it = std::ranges::find(_relative_representation.card_positions_draw[discarded.local_index] - , _turn); + auto replaced_card_it = std::find( + _relative_representation.card_positions_draw[discarded.local_index].begin(), + _relative_representation.card_positions_draw[discarded.local_index].end(), + _turn + ); ASSERT(replaced_card_it != _relative_representation.card_positions_draw[discarded.local_index].end()); if (played) { @@ -358,7 +361,10 @@ namespace Hanabi { *replaced_card_it = RelativeRepresentationData::discard_pile; } - std::ranges::sort(_relative_representation.card_positions_draw[discarded.local_index]); + std::sort( + _relative_representation.card_positions_draw[discarded.local_index].begin(), + _relative_representation.card_positions_draw[discarded.local_index].end() + ); } } } @@ -392,11 +398,17 @@ namespace Hanabi if (!draw.card.initial_trash) { ASSERT(draw.card.in_starting_hand == false); - auto new_card_it = std::ranges::find(_relative_representation.card_positions_draw[draw.card.local_index] - , RelativeRepresentationData::draw_pile); + auto new_card_it = std::find( + _relative_representation.card_positions_draw[draw.card.local_index].begin(), + _relative_representation.card_positions_draw[draw.card.local_index].end(), + RelativeRepresentationData::draw_pile + ); ASSERT(new_card_it != _relative_representation.card_positions_draw[draw.card.local_index].end()); *new_card_it = _turn; - std::ranges::sort(_relative_representation.card_positions_draw[draw.card.local_index]); + std::sort( + _relative_representation.card_positions_draw[draw.card.local_index].begin(), + _relative_representation.card_positions_draw[draw.card.local_index].end() + ); } } @@ -460,10 +472,17 @@ namespace Hanabi if (_relative_representation.initialized && !drawn.initial_trash) { ASSERT(drawn.in_starting_hand == false); - auto drawn_card_it = std::ranges::find(_relative_representation.card_positions_draw[drawn.local_index], _turn); + auto drawn_card_it = std::find( + _relative_representation.card_positions_draw[drawn.local_index].begin(), + _relative_representation.card_positions_draw[drawn.local_index].end(), + _turn + ); ASSERT(drawn_card_it != _relative_representation.card_positions_draw[drawn.local_index].end()); *drawn_card_it = RelativeRepresentationData::draw_pile; - std::ranges::sort(_relative_representation.card_positions_draw[drawn.local_index]); + std::sort( + _relative_representation.card_positions_draw[drawn.local_index].begin(), + _relative_representation.card_positions_draw[drawn.local_index].end() + ); } _weighted_draw_pile_size++; @@ -494,11 +513,17 @@ namespace Hanabi return RelativeRepresentationData::discard_pile; } }(); - auto hand_card_it = std::ranges::find(_relative_representation.card_positions_draw[discarded_card.local_index] - , old_position); + auto hand_card_it = std::find( + _relative_representation.card_positions_draw[discarded_card.local_index].begin(), + _relative_representation.card_positions_draw[discarded_card.local_index].end(), + old_position + ); ASSERT(hand_card_it != _relative_representation.card_positions_draw[discarded_card.local_index].end()); *hand_card_it = _turn; - std::ranges::sort(_relative_representation.card_positions_draw[discarded_card.local_index]); + std::sort( + _relative_representation.card_positions_draw[discarded_card.local_index].begin(), + _relative_representation.card_positions_draw[discarded_card.local_index].end() + ); } } @@ -917,7 +942,7 @@ namespace Hanabi return 0; } const auto id = unique_id(); - if (_position_tablebase.contains(id)) + if (_position_tablebase.count(id) == 1) { return _position_tablebase.at(id); } @@ -969,7 +994,7 @@ namespace Hanabi return 0; } #ifndef GAME_STATE_NO_TABLEBASE_LOOKUP - if (_position_tablebase.contains(id_of_state)) { + if (_position_tablebase.count(id_of_state) == 1) { return _position_tablebase[id_of_state]; } #endif @@ -1334,7 +1359,7 @@ namespace Hanabi std::cout << "\n" << std::endl; } #endif - if (_position_tablebase.contains(id)) + if (_position_tablebase.count(id) == 1) { ASSERT(_position_tablebase[id] == probability); } diff --git a/include/hanabi_types.hpp b/include/hanabi_types.hpp index f1d55e0..522a513 100644 --- a/include/hanabi_types.hpp +++ b/include/hanabi_types.hpp @@ -51,7 +51,7 @@ namespace Hanabi constexpr rank_t starting_card_rank = 5; constexpr suit_t max_suit_index = 5; constexpr size_t max_card_duplicity = 3; - constexpr clue_t max_num_clues = 8; + const clue_t max_num_clues = 8; constexpr hand_index_t invalid_hand_idx = std::numeric_limits::max(); // We might want to change these at runtime to adapt to other variants. @@ -75,6 +75,7 @@ namespace Hanabi * This is inlined as this is a runtime critical function when backtracking. */ inline bool operator==(const Card & other) const; + inline bool operator!=(const Card & other) const; }; enum class ActionType : std::uint8_t @@ -154,6 +155,11 @@ namespace Hanabi return suit == other.suit and rank == other.rank; } + bool Card::operator!=(const Card & other) const + { + return not (*this == other); + } + template std::ostream & print_probability(std::ostream & os, const std::optional & prob) { diff --git a/src/game_interface.cpp b/src/game_interface.cpp index dcda23f..b2120f2 100644 --- a/src/game_interface.cpp +++ b/src/game_interface.cpp @@ -5,6 +5,16 @@ namespace Hanabi { + bool CardMultiplicity::operator==(Hanabi::CardMultiplicity const & other) const + { + return card == other.card && multiplicity == other.multiplicity; + } + + bool CardMultiplicity::operator!=(Hanabi::CardMultiplicity const & other) const + { + return not (*this == other); + } + std::ostream & operator<<(std::ostream & os, HanabiStateIF const & hanabi_state) { hanabi_state.print(os); diff --git a/src/parse_game.cpp b/src/parse_game.cpp index 2ab33b7..7341328 100644 --- a/src/parse_game.cpp +++ b/src/parse_game.cpp @@ -8,7 +8,7 @@ namespace Parsing template void extract(boost::json::object const & obj, T & t, std::string_view key) { - t = value_to(obj.at(key)); + t = boost::json::value_to(obj.at(key)); } } diff --git a/src/state_explorer.cpp b/src/state_explorer.cpp index b21e5a4..6130410 100644 --- a/src/state_explorer.cpp +++ b/src/state_explorer.cpp @@ -41,7 +41,7 @@ namespace Hanabi std::string text_str(text); for (auto & command: cli_commands) { - if (command.starts_with(text_str) && state-- <= 0) + if (command.find(text_str) == 0 && state-- <= 0) { return strdup(command.c_str()); } @@ -135,7 +135,7 @@ namespace Hanabi states_to_show.pop_back(); } - std::ranges::sort(states_to_show, [](const auto & left, const auto & right) { + std::sort(states_to_show.begin(), states_to_show.end(), [](const auto & left, const auto & right) { return left.second > right.second; }); @@ -199,7 +199,7 @@ namespace Hanabi const std::string prompt = read_line_memory_safe("> "); add_history(prompt.c_str()); - if (prompt.starts_with("help")) + if (prompt.find("help") == 0) { std::cout << "state: print information on current game state." << std::endl; std::cout << "clue: give a clue." << std::endl; @@ -224,7 +224,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("dump-id-parts")) + if (prompt.find("dump-id-parts") == 0) { for (const auto val: game.state->dump_unique_id_parts().first) { @@ -239,7 +239,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("quit") or prompt == "q") + if (prompt.find("quit") == 0 or prompt == "q") { std::cout << "Quitting." << std::endl; clear_history(); @@ -247,7 +247,7 @@ namespace Hanabi break; } - if (prompt.starts_with("set-initials")) + if (prompt.find("set-initials") == 0) { if (prompt.length() < 16) { @@ -268,7 +268,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("state")) + if (prompt.find("state") == 0) { std::cout << *game.state << std::endl; const std::optional prob = game.state->lookup(); @@ -277,7 +277,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("evaluate")) + if (prompt.find("evaluate") == 0) { std::cout << "Evaluating current game state, this might take a while." << std::endl; game.state->evaluate_state(); @@ -285,7 +285,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("revert")) + if (prompt.find("revert") == 0) { if (depth == 0) { @@ -319,13 +319,13 @@ namespace Hanabi continue; } - if (prompt.starts_with("id")) + if (prompt.find("id") == 0) { std::cout << game.state->unique_id() << std::endl; continue; } - if (prompt.starts_with("play")) + if (prompt.find("play") == 0) { const Card card = parse_card(prompt.substr(5, 2)); if (prompt.length() < 7) @@ -353,7 +353,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("discard")) + if (prompt.find("discard") == 0) { const auto hand = game.state->cur_hand(); hand_index_t trash_index = invalid_hand_idx; @@ -384,7 +384,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("clue")) + if (prompt.find("clue") == 0) { if (game.state->num_clues() == clue_t(0)) { @@ -396,7 +396,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("actions")) + if (prompt.find("actions") == 0) { auto reasonable_actions = game.state->get_reasonable_actions(); int max_rational_digit_len = std::accumulate( @@ -422,7 +422,7 @@ namespace Hanabi continue; } - if (prompt.starts_with("opt")) + if (prompt.find("opt") == 0) { const auto reasonable_actions = game.state->get_reasonable_actions(); if (reasonable_actions.empty())