consider playing trash at 8 clues
This commit is contained in:
parent
03abd08418
commit
863baf3acd
5 changed files with 34 additions and 5 deletions
|
@ -48,6 +48,8 @@ namespace Hanabi
|
||||||
|
|
||||||
[[nodiscard]] virtual clue_t num_clues() 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 unsigned score() const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual std::vector<std::vector<Card>> hands() const = 0;
|
[[nodiscard]] virtual std::vector<std::vector<Card>> hands() const = 0;
|
||||||
|
|
|
@ -94,6 +94,8 @@ namespace Hanabi
|
||||||
|
|
||||||
[[nodiscard]] clue_t num_clues() const final;
|
[[nodiscard]] clue_t num_clues() const final;
|
||||||
|
|
||||||
|
[[nodiscard]] unsigned num_strikes() const final;
|
||||||
|
|
||||||
[[nodiscard]] unsigned score() const final;
|
[[nodiscard]] unsigned score() const final;
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::vector<Card>> hands() const final;
|
[[nodiscard]] std::vector<std::vector<Card>> hands() const final;
|
||||||
|
@ -233,6 +235,7 @@ namespace Hanabi
|
||||||
|
|
||||||
player_t _turn{};
|
player_t _turn{};
|
||||||
clue_t _num_clues{};
|
clue_t _num_clues{};
|
||||||
|
unsigned _num_strikes{};
|
||||||
std::uint8_t _weighted_draw_pile_size{};
|
std::uint8_t _weighted_draw_pile_size{};
|
||||||
Stacks<num_suits> _stacks{};
|
Stacks<num_suits> _stacks{};
|
||||||
std::array<std::array<Card, hand_size>, num_players> _hands{};
|
std::array<std::array<Card, hand_size>, num_players> _hands{};
|
||||||
|
|
|
@ -77,7 +77,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>
|
||||||
HanabiState<num_suits, num_players, hand_size>::HanabiState(const std::vector<Card> & deck, uint8_t score_goal, clue_t num_clues_gained_on_discard_or_stack_finished):
|
HanabiState<num_suits, num_players, hand_size>::HanabiState(const std::vector<Card> & deck, uint8_t score_goal, clue_t num_clues_gained_on_discard_or_stack_finished):
|
||||||
_clues_gained_on_discard_or_stack_finished(num_clues_gained_on_discard_or_stack_finished)
|
_clues_gained_on_discard_or_stack_finished(num_clues_gained_on_discard_or_stack_finished)
|
||||||
, _score_goal(score_goal), _turn(0), _num_clues(max_num_clues), _weighted_draw_pile_size(deck.size()), _stacks(), _hands(), _draw_pile()
|
, _score_goal(score_goal), _turn(0), _num_clues(max_num_clues), _num_strikes(0), _weighted_draw_pile_size(deck.size()), _stacks(), _hands(), _draw_pile()
|
||||||
, _endgame_turns_left(no_endgame), _pace(deck.size() - score_goal - num_players * (hand_size - 1)), _score(0)
|
, _endgame_turns_left(no_endgame), _pace(deck.size() - score_goal - num_players * (hand_size - 1)), _score(0)
|
||||||
, _actions_log(), _relative_representation(), _position_tablebase()
|
, _actions_log(), _relative_representation(), _position_tablebase()
|
||||||
, _enumerated_states(0)
|
, _enumerated_states(0)
|
||||||
|
@ -214,6 +214,7 @@ namespace Hanabi
|
||||||
_num_clues += _clues_gained_on_discard_or_stack_finished;
|
_num_clues += _clues_gained_on_discard_or_stack_finished;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
_num_strikes++;
|
||||||
_num_copies_left[played_card]--;
|
_num_copies_left[played_card]--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +272,7 @@ namespace Hanabi
|
||||||
void HanabiState<num_suits, num_players, hand_size>::print(std::ostream & os) const
|
void HanabiState<num_suits, num_players, hand_size>::print(std::ostream & os) const
|
||||||
{
|
{
|
||||||
os << "Stacks: " << _stacks << " (score " << +_score << ")";
|
os << "Stacks: " << _stacks << " (score " << +_score << ")";
|
||||||
os << ", clues: " << +_num_clues << ", turn: " << +_turn;
|
os << ", clues: " << +_num_clues << ", strikes: " << +_num_strikes << ", turn: " << +_turn;
|
||||||
if (_endgame_turns_left != no_endgame)
|
if (_endgame_turns_left != no_endgame)
|
||||||
{
|
{
|
||||||
os << ", " << +_endgame_turns_left << " turns left";
|
os << ", " << +_endgame_turns_left << " turns left";
|
||||||
|
@ -644,6 +645,7 @@ namespace Hanabi
|
||||||
} else {
|
} else {
|
||||||
// If we misplayed, then we lost the card and have to regain it now
|
// If we misplayed, then we lost the card and have to regain it now
|
||||||
_num_copies_left[last_action.discarded]++;
|
_num_copies_left[last_action.discarded]++;
|
||||||
|
_num_strikes--;
|
||||||
}
|
}
|
||||||
CHECK_DRAW_PILE_INTEGRITY;
|
CHECK_DRAW_PILE_INTEGRITY;
|
||||||
}
|
}
|
||||||
|
@ -738,6 +740,12 @@ namespace Hanabi
|
||||||
return _num_clues;
|
return _num_clues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<suit_t num_suits, player_t num_players, hand_index_t hand_size>
|
||||||
|
unsigned HanabiState<num_suits, num_players, hand_size>::num_strikes() const
|
||||||
|
{
|
||||||
|
return _num_strikes;
|
||||||
|
}
|
||||||
|
|
||||||
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>
|
||||||
unsigned HanabiState<num_suits, num_players, hand_size>::score() const
|
unsigned HanabiState<num_suits, num_players, hand_size>::score() const
|
||||||
{
|
{
|
||||||
|
@ -805,7 +813,7 @@ namespace Hanabi
|
||||||
for (std::uint8_t index = 0; index < hand_size; index++)
|
for (std::uint8_t index = 0; index < hand_size; index++)
|
||||||
{
|
{
|
||||||
Card card = hand[index];
|
Card card = hand[index];
|
||||||
bool const consider_playing = is_playable(card) or (not is_critical(card) and not reasonable and (not is_trash(card) or not played_trash));
|
bool const consider_playing = is_playable(card) or (_num_strikes < max_num_strikes and not is_critical(card) and (not reasonable or _num_clues == max_num_clues) and (not is_trash(card) or not played_trash));
|
||||||
if (consider_playing)
|
if (consider_playing)
|
||||||
{
|
{
|
||||||
if (is_trash(card))
|
if (is_trash(card))
|
||||||
|
@ -1005,10 +1013,14 @@ namespace Hanabi
|
||||||
const std::array<Card, hand_size> & hand = _hands[_turn];
|
const std::array<Card, hand_size> & hand = _hands[_turn];
|
||||||
|
|
||||||
// First, check for playables
|
// First, check for playables
|
||||||
|
bool played_trash = false;
|
||||||
for (std::uint8_t index = 0; index < hand_size; index++)
|
for (std::uint8_t index = 0; index < hand_size; index++)
|
||||||
{
|
{
|
||||||
if (is_playable(hand[index]))
|
if (is_playable(hand[index]) or (_num_clues == max_num_clues and _num_strikes < max_num_strikes and not is_critical(hand[index]) and (not is_trash(hand[index]) or not played_trash)))
|
||||||
{
|
{
|
||||||
|
if (is_trash(hand[index])) {
|
||||||
|
played_trash = true;
|
||||||
|
}
|
||||||
probability_t const probability_play = check_play_or_discard(index, true);
|
probability_t const probability_play = check_play_or_discard(index, true);
|
||||||
|
|
||||||
best_probability = std::max(best_probability, probability_play);
|
best_probability = std::max(best_probability, probability_play);
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace Hanabi
|
||||||
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;
|
||||||
const clue_t max_num_clues = 8;
|
const clue_t max_num_clues = 8;
|
||||||
|
constexpr unsigned max_num_strikes = 2; /** Maximum number of allowed strikes */
|
||||||
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.
|
||||||
|
|
|
@ -397,7 +397,18 @@ namespace Hanabi
|
||||||
|
|
||||||
if (prompt.find("actions") == 0)
|
if (prompt.find("actions") == 0)
|
||||||
{
|
{
|
||||||
auto reasonable_actions = game.state->get_reasonable_actions();
|
std::vector<std::pair<Hanabi::Action, std::optional<boost::rational<Hanabi::probability_base_type>>>> reasonable_actions = game.state->get_reasonable_actions();
|
||||||
|
std::sort(reasonable_actions.begin(), reasonable_actions.end(),
|
||||||
|
[](std::pair<Hanabi::Action, std::optional<probability_t>> const & left,
|
||||||
|
std::pair<Hanabi::Action, std::optional<probability_t>> const & right){
|
||||||
|
if (not left.second.has_value()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (not right.second.has_value()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return left.second.value() < right.second.value();
|
||||||
|
});
|
||||||
int max_rational_digit_len = std::accumulate(
|
int max_rational_digit_len = std::accumulate(
|
||||||
reasonable_actions.begin(), reasonable_actions.end(), 0, [](
|
reasonable_actions.begin(), reasonable_actions.end(), 0, [](
|
||||||
int old, const std::pair<Action
|
int old, const std::pair<Action
|
||||||
|
|
Loading…
Reference in a new issue