set up initial card positions
This commit is contained in:
parent
228eac7af1
commit
ed6f3949b0
3 changed files with 68 additions and 8 deletions
26
game_state.h
26
game_state.h
|
@ -43,6 +43,7 @@ constexpr std::array<std::string, 6> suit_initials{"r", "y", "g", "b", "p", "t"}
|
||||||
struct Card {
|
struct Card {
|
||||||
suit_t suit;
|
suit_t suit;
|
||||||
rank_t rank;
|
rank_t rank;
|
||||||
|
bool was_in_initial_hand;
|
||||||
|
|
||||||
Card &operator++();
|
Card &operator++();
|
||||||
const Card operator++(int);
|
const Card operator++(int);
|
||||||
|
@ -84,12 +85,26 @@ struct CardMultiplicity {
|
||||||
auto operator<=>(const CardMultiplicity &) const = default;
|
auto operator<=>(const CardMultiplicity &) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct InnerCardArray {
|
||||||
|
template<size_t N>
|
||||||
|
using array_t = std::array<T, N>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct InnerCardArray<bool> {
|
||||||
|
template<size_t N>
|
||||||
|
using array_t = std::bitset<N>;
|
||||||
|
};
|
||||||
|
|
||||||
template <suit_t num_suits, typename T> struct CardArray {
|
template <suit_t num_suits, typename T> struct CardArray {
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
CardArray() = default;
|
CardArray() = default;
|
||||||
explicit CardArray(value_type default_val);
|
explicit CardArray(value_type default_val);
|
||||||
|
|
||||||
|
void fill(value_type val);
|
||||||
|
|
||||||
const value_type &operator[](const Card &card) const;
|
const value_type &operator[](const Card &card) const;
|
||||||
|
|
||||||
value_type &operator[](const Card &card);
|
value_type &operator[](const Card &card);
|
||||||
|
@ -97,7 +112,8 @@ template <suit_t num_suits, typename T> struct CardArray {
|
||||||
auto operator<=>(const CardArray &) const = default;
|
auto operator<=>(const CardArray &) const = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<std::array<T, starting_card_rank>, num_suits> _array {};
|
using inner_array_t = typename InnerCardArray<T>::template array_t<starting_card_rank>;
|
||||||
|
std::array<inner_array_t , num_suits> _array {};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ActionType {
|
enum class ActionType {
|
||||||
|
@ -195,6 +211,14 @@ private:
|
||||||
|
|
||||||
static constexpr uint8_t no_endgame = std::numeric_limits<uint8_t>::max();
|
static constexpr uint8_t no_endgame = std::numeric_limits<uint8_t>::max();
|
||||||
|
|
||||||
|
// This will save the card positions of all cards that are in the draw pile when we start backtracking
|
||||||
|
CardArray<num_suits, boost::container::static_vector<player_t, max_card_duplicity>> _card_positions_draw;
|
||||||
|
// This will indicate whether cards that were in hands initially still are in hands
|
||||||
|
CardArray<num_suits, bool> _card_positions_hands;
|
||||||
|
|
||||||
|
// A list of cards (set up once upon initialization) of all good cards that were in starting hands
|
||||||
|
std::array<boost::container::static_vector<Card, hand_size>, num_players> _good_cards_in_initial_draw_pile;
|
||||||
|
|
||||||
// further statistics that we might want to keep track of
|
// further statistics that we might want to keep track of
|
||||||
uint8_t _pace{};
|
uint8_t _pace{};
|
||||||
uint8_t _score{};
|
uint8_t _score{};
|
||||||
|
|
|
@ -37,14 +37,19 @@ namespace Hanabi {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<suit_t num_suits, typename T>
|
template<suit_t num_suits, typename T>
|
||||||
CardArray<num_suits, T>::CardArray(T default_val) {
|
void CardArray<num_suits, T>::fill(T val) {
|
||||||
for (size_t suit = 0; suit < num_suits; suit++) {
|
for (size_t suit = 0; suit < num_suits; suit++) {
|
||||||
for (rank_t rank = 0; rank < starting_card_rank; rank++) {
|
for (rank_t rank = 0; rank < starting_card_rank; rank++) {
|
||||||
_array[suit][rank] = default_val;
|
_array[suit][rank] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<suit_t num_suits, typename T>
|
||||||
|
CardArray<num_suits, T>::CardArray(T default_val) {
|
||||||
|
fill(default_val);
|
||||||
|
}
|
||||||
|
|
||||||
template<suit_t num_suits, typename T>
|
template<suit_t num_suits, typename T>
|
||||||
const T& CardArray<num_suits, T>::operator[](const Card &card) const {
|
const T& CardArray<num_suits, T>::operator[](const Card &card) const {
|
||||||
return _array[card.suit][card.rank];
|
return _array[card.suit][card.rank];
|
||||||
|
@ -247,6 +252,7 @@ namespace Hanabi {
|
||||||
|
|
||||||
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||||
void HanabiState<num_suits, num_players, hand_size>::normalize_draw_and_positions() {
|
void HanabiState<num_suits, num_players, hand_size>::normalize_draw_and_positions() {
|
||||||
|
// Note that this function does not have to be particularly performant, we only call it once to initialize.
|
||||||
const Card trash = [this]() -> Card {
|
const Card trash = [this]() -> Card {
|
||||||
for(suit_t suit = 0; suit < num_suits; suit++) {
|
for(suit_t suit = 0; suit < num_suits; suit++) {
|
||||||
if(_stacks[suit] < starting_card_rank) {
|
if(_stacks[suit] < starting_card_rank) {
|
||||||
|
@ -257,25 +263,44 @@ namespace Hanabi {
|
||||||
}();
|
}();
|
||||||
|
|
||||||
CardArray<num_suits, std::uint8_t> nums_in_draw_pile;
|
CardArray<num_suits, std::uint8_t> nums_in_draw_pile;
|
||||||
std::uint8_t num_trash_in_draw_pile = 0;
|
|
||||||
for(const auto [card, multiplicity] : _draw_pile) {
|
for(const auto [card, multiplicity] : _draw_pile) {
|
||||||
if (_stacks[card.suit] > card.rank) {
|
if (_stacks[card.suit] > card.rank) {
|
||||||
nums_in_draw_pile[card] += multiplicity;
|
nums_in_draw_pile[card] += multiplicity;
|
||||||
} else {
|
} else {
|
||||||
num_trash_in_draw_pile++;
|
nums_in_draw_pile[trash] += multiplicity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare draw pile
|
||||||
_draw_pile.clear();
|
_draw_pile.clear();
|
||||||
for(suit_t suit = 0; suit < num_suits; suit++) {
|
for(suit_t suit = 0; suit < num_suits; suit++) {
|
||||||
for(rank_t rank = 0; rank < starting_card_rank; rank++) {
|
for(rank_t rank = 0; rank < starting_card_rank; rank++) {
|
||||||
Card card {suit, rank};
|
Card card {suit, rank, false};
|
||||||
if (nums_in_draw_pile[card] > 0) {
|
if (nums_in_draw_pile[card] > 0) {
|
||||||
_draw_pile.push_back({card, nums_in_draw_pile[card]});
|
_draw_pile.push_back({card, nums_in_draw_pile[card]});
|
||||||
|
if(!is_trash(card)) {
|
||||||
|
_card_positions_draw[card].clear();
|
||||||
|
_card_positions_draw[card].resize(nums_in_draw_pile[card], draw_pile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_draw_pile.push_back({trash, num_trash_in_draw_pile});
|
}
|
||||||
|
|
||||||
|
// Prepare cards in hands
|
||||||
|
for(player_t player = 0; player < num_players; player++) {
|
||||||
|
for(Card& card : _hands[player]) {
|
||||||
|
if(!is_trash(card)) {
|
||||||
|
if(std::count(_good_cards_in_initial_draw_pile[player].begin(), _good_cards_in_initial_draw_pile[player].end(), card) > 0) {
|
||||||
|
// This card is already in hand, so just replace the second copy by some trash
|
||||||
|
card = trash;
|
||||||
|
} else {
|
||||||
|
_good_cards_in_initial_draw_pile[player].push_back(card);
|
||||||
|
card.was_in_initial_hand = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_card_positions_draw.fill(draw_pile);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||||
|
|
11
main.cpp
11
main.cpp
|
@ -40,7 +40,18 @@ namespace Hanabi {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CHECK(test, condition) if (!(condition)) { std::cerr << "Test " << (test) << " failed." << std::endl; }
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
{
|
||||||
|
auto game = Download::get_game("1005195", 43);
|
||||||
|
auto res = game->backtrack(1);
|
||||||
|
CHECK("1005195", res == static_cast<double>(7) / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
test();
|
||||||
if(argc == 3) {
|
if(argc == 3) {
|
||||||
std::string game (argv[1]);
|
std::string game (argv[1]);
|
||||||
std::string turn (argv[2]);
|
std::string turn (argv[2]);
|
||||||
|
|
Loading…
Reference in a new issue