Merge branch 'main' into cpr-fetch-content

This commit is contained in:
Maximilian Keßler 2024-01-14 18:05:08 +01:00
commit 759386f21b
Signed by: max
GPG key ID: BCC5A619923C0BA5
8 changed files with 78 additions and 36 deletions

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(endgame-analyzer CXX) 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 "${CMAKE_CXX_FLAGS} -Wall -Wpedantic -Werror")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DGAME_STATE_NO_TABLEBASE_LOOKUP") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DGAME_STATE_NO_TABLEBASE_LOOKUP")

View file

@ -21,7 +21,8 @@ namespace Hanabi
Card card; Card card;
unsigned multiplicity; unsigned multiplicity;
bool operator==(const CardMultiplicity &) const = default; bool operator==(const CardMultiplicity &) const;
bool operator!=(const CardMultiplicity &) const;
}; };
class HanabiStateIF class HanabiStateIF

View file

@ -56,7 +56,7 @@ namespace Hanabi
value_type & operator[](const Card & card); value_type & operator[](const Card & card);
auto operator<=>(const CardArray &) const = default; //auto operator<=>(const CardArray &) const = default;
private: private:
using inner_array_t = typename InnerCardArray<T>::template array_t<starting_card_rank>; using inner_array_t = typename InnerCardArray<T>::template array_t<starting_card_rank>;
@ -132,7 +132,7 @@ namespace Hanabi
std::vector<std::pair<CardMultiplicity, std::optional<probability_t>>> std::vector<std::pair<CardMultiplicity, std::optional<probability_t>>>
possible_next_states(hand_index_t index, bool play) final; possible_next_states(hand_index_t index, bool play) final;
auto operator<=>(const HanabiState &) const = default; //auto operator<=>(const HanabiState &) const = default;
protected: protected:
void print(std::ostream & os) const final; void print(std::ostream & os) const final;

View file

@ -82,7 +82,7 @@ namespace Hanabi
, _actions_log(), _relative_representation(), _position_tablebase() , _actions_log(), _relative_representation(), _position_tablebase()
, _enumerated_states(0) , _enumerated_states(0)
{ {
std::ranges::fill(_stacks, starting_card_rank); std::fill(_stacks.begin(), _stacks.end(), starting_card_rank);
for (const Card & card: deck) for (const Card & card: deck)
{ {
_draw_pile.push_back({card, 1}); _draw_pile.push_back({card, 1});
@ -347,8 +347,11 @@ namespace Hanabi
} }
else else
{ {
auto replaced_card_it = std::ranges::find(_relative_representation.card_positions_draw[discarded.local_index] auto replaced_card_it = std::find(
, _turn); _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()); ASSERT(replaced_card_it != _relative_representation.card_positions_draw[discarded.local_index].end());
if (played) if (played)
{ {
@ -358,7 +361,10 @@ namespace Hanabi
{ {
*replaced_card_it = RelativeRepresentationData::discard_pile; *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) if (!draw.card.initial_trash)
{ {
ASSERT(draw.card.in_starting_hand == false); ASSERT(draw.card.in_starting_hand == false);
auto new_card_it = std::ranges::find(_relative_representation.card_positions_draw[draw.card.local_index] auto new_card_it = std::find(
, RelativeRepresentationData::draw_pile); _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()); ASSERT(new_card_it != _relative_representation.card_positions_draw[draw.card.local_index].end());
*new_card_it = _turn; *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) if (_relative_representation.initialized && !drawn.initial_trash)
{ {
ASSERT(drawn.in_starting_hand == false); 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()); ASSERT(drawn_card_it != _relative_representation.card_positions_draw[drawn.local_index].end());
*drawn_card_it = RelativeRepresentationData::draw_pile; *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++; _weighted_draw_pile_size++;
@ -494,11 +513,17 @@ namespace Hanabi
return RelativeRepresentationData::discard_pile; return RelativeRepresentationData::discard_pile;
} }
}(); }();
auto hand_card_it = std::ranges::find(_relative_representation.card_positions_draw[discarded_card.local_index] auto hand_card_it = std::find(
, old_position); _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()); ASSERT(hand_card_it != _relative_representation.card_positions_draw[discarded_card.local_index].end());
*hand_card_it = _turn; *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; return 0;
} }
const auto id = unique_id(); const auto id = unique_id();
if (_position_tablebase.contains(id)) if (_position_tablebase.count(id) == 1)
{ {
return _position_tablebase.at(id); return _position_tablebase.at(id);
} }
@ -969,7 +994,7 @@ namespace Hanabi
return 0; return 0;
} }
#ifndef GAME_STATE_NO_TABLEBASE_LOOKUP #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]; return _position_tablebase[id_of_state];
} }
#endif #endif
@ -1334,7 +1359,7 @@ namespace Hanabi
std::cout << "\n" << std::endl; std::cout << "\n" << std::endl;
} }
#endif #endif
if (_position_tablebase.contains(id)) if (_position_tablebase.count(id) == 1)
{ {
ASSERT(_position_tablebase[id] == probability); ASSERT(_position_tablebase[id] == probability);
} }

View file

@ -51,7 +51,7 @@ namespace Hanabi
constexpr rank_t starting_card_rank = 5; constexpr rank_t starting_card_rank = 5;
constexpr suit_t max_suit_index = 5; constexpr suit_t max_suit_index = 5;
constexpr size_t max_card_duplicity = 3; 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<hand_index_t>::max(); constexpr hand_index_t invalid_hand_idx = std::numeric_limits<hand_index_t>::max();
// We might want to change these at runtime to adapt to other variants. // 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. * 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;
inline bool operator!=(const Card & other) const;
}; };
enum class ActionType : std::uint8_t enum class ActionType : std::uint8_t
@ -154,6 +155,11 @@ namespace Hanabi
return suit == other.suit and rank == other.rank; return suit == other.suit and rank == other.rank;
} }
bool Card::operator!=(const Card & other) const
{
return not (*this == other);
}
template<typename T> template<typename T>
std::ostream & print_probability(std::ostream & os, const std::optional<T> & prob) std::ostream & print_probability(std::ostream & os, const std::optional<T> & prob)
{ {

View file

@ -5,6 +5,16 @@
namespace Hanabi 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) std::ostream & operator<<(std::ostream & os, HanabiStateIF const & hanabi_state)
{ {
hanabi_state.print(os); hanabi_state.print(os);

View file

@ -8,7 +8,7 @@ namespace Parsing
template<class T> template<class T>
void extract(boost::json::object const & obj, T & t, std::string_view key) void extract(boost::json::object const & obj, T & t, std::string_view key)
{ {
t = value_to<T>(obj.at(key)); t = boost::json::value_to<T>(obj.at(key));
} }
} }

View file

@ -41,7 +41,7 @@ namespace Hanabi
std::string text_str(text); std::string text_str(text);
for (auto & command: cli_commands) 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()); return strdup(command.c_str());
} }
@ -135,7 +135,7 @@ namespace Hanabi
states_to_show.pop_back(); 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; return left.second > right.second;
}); });
@ -199,7 +199,7 @@ namespace Hanabi
const std::string prompt = read_line_memory_safe("> "); const std::string prompt = read_line_memory_safe("> ");
add_history(prompt.c_str()); 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 << "state: print information on current game state." << std::endl;
std::cout << "clue: give a clue." << std::endl; std::cout << "clue: give a clue." << std::endl;
@ -224,7 +224,7 @@ namespace Hanabi
continue; 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) for (const auto val: game.state->dump_unique_id_parts().first)
{ {
@ -239,7 +239,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("quit") or prompt == "q") if (prompt.find("quit") == 0 or prompt == "q")
{ {
std::cout << "Quitting." << std::endl; std::cout << "Quitting." << std::endl;
clear_history(); clear_history();
@ -247,7 +247,7 @@ namespace Hanabi
break; break;
} }
if (prompt.starts_with("set-initials")) if (prompt.find("set-initials") == 0)
{ {
if (prompt.length() < 16) if (prompt.length() < 16)
{ {
@ -268,7 +268,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("state")) if (prompt.find("state") == 0)
{ {
std::cout << *game.state << std::endl; std::cout << *game.state << std::endl;
const std::optional<probability_t> prob = game.state->lookup(); const std::optional<probability_t> prob = game.state->lookup();
@ -277,7 +277,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("evaluate")) if (prompt.find("evaluate") == 0)
{ {
std::cout << "Evaluating current game state, this might take a while." << std::endl; std::cout << "Evaluating current game state, this might take a while." << std::endl;
game.state->evaluate_state(); game.state->evaluate_state();
@ -285,7 +285,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("revert")) if (prompt.find("revert") == 0)
{ {
if (depth == 0) if (depth == 0)
{ {
@ -319,13 +319,13 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("id")) if (prompt.find("id") == 0)
{ {
std::cout << game.state->unique_id() << std::endl; std::cout << game.state->unique_id() << std::endl;
continue; continue;
} }
if (prompt.starts_with("play")) if (prompt.find("play") == 0)
{ {
const Card card = parse_card(prompt.substr(5, 2)); const Card card = parse_card(prompt.substr(5, 2));
if (prompt.length() < 7) if (prompt.length() < 7)
@ -353,7 +353,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("discard")) if (prompt.find("discard") == 0)
{ {
const auto hand = game.state->cur_hand(); const auto hand = game.state->cur_hand();
hand_index_t trash_index = invalid_hand_idx; hand_index_t trash_index = invalid_hand_idx;
@ -384,7 +384,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("clue")) if (prompt.find("clue") == 0)
{ {
if (game.state->num_clues() == clue_t(0)) if (game.state->num_clues() == clue_t(0))
{ {
@ -396,7 +396,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("actions")) if (prompt.find("actions") == 0)
{ {
auto reasonable_actions = game.state->get_reasonable_actions(); auto reasonable_actions = game.state->get_reasonable_actions();
int max_rational_digit_len = std::accumulate( int max_rational_digit_len = std::accumulate(
@ -422,7 +422,7 @@ namespace Hanabi
continue; continue;
} }
if (prompt.starts_with("opt")) if (prompt.find("opt") == 0)
{ {
const auto reasonable_actions = game.state->get_reasonable_actions(); const auto reasonable_actions = game.state->get_reasonable_actions();
if (reasonable_actions.empty()) if (reasonable_actions.empty())