mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 14:57:35 +00:00
Hearts: Let the AI pick better lead cards
Instead of picking the card with the lowest value we should pick the card with the highest value for which we know no lower value card is in play anymore and that someone else still has an even higher value card.
This commit is contained in:
parent
c2a4b581fe
commit
1ae18c1228
4 changed files with 64 additions and 18 deletions
|
@ -161,6 +161,32 @@ void Game::timer_event(Core::TimerEvent&)
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Game::other_player_has_lower_value_card(Player& player, Card& card)
|
||||||
|
{
|
||||||
|
for (auto& other_player : m_players) {
|
||||||
|
if (&player != &other_player) {
|
||||||
|
for (auto& other_card : other_player.hand) {
|
||||||
|
if (other_card && card.type() == other_card->type() && hearts_card_value(*other_card) < hearts_card_value(card))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Game::other_player_has_higher_value_card(Player& player, Card& card)
|
||||||
|
{
|
||||||
|
for (auto& other_player : m_players) {
|
||||||
|
if (&player != &other_player) {
|
||||||
|
for (auto& other_card : other_player.hand) {
|
||||||
|
if (other_card && card.type() == other_card->type() && hearts_card_value(*other_card) > hearts_card_value(card))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#define RETURN_CARD_IF_VALID(card) \
|
#define RETURN_CARD_IF_VALID(card) \
|
||||||
do { \
|
do { \
|
||||||
auto card_index = (card); \
|
auto card_index = (card); \
|
||||||
|
@ -177,8 +203,15 @@ size_t Game::pick_card(Player& player)
|
||||||
auto clubs_2 = player.pick_specific_card(Card::Type::Clubs, CardValue::Number_2);
|
auto clubs_2 = player.pick_specific_card(Card::Type::Clubs, CardValue::Number_2);
|
||||||
VERIFY(clubs_2.has_value());
|
VERIFY(clubs_2.has_value());
|
||||||
return clubs_2.value();
|
return clubs_2.value();
|
||||||
} else
|
} else {
|
||||||
return player.pick_low_points_low_value_card();
|
auto valid_card = [this, &player](Card& card) {
|
||||||
|
return is_valid_play(player, card);
|
||||||
|
};
|
||||||
|
auto prefer_card = [this, &player](Card& card) {
|
||||||
|
return !other_player_has_lower_value_card(player, card) && other_player_has_higher_value_card(player, card);
|
||||||
|
};
|
||||||
|
return player.pick_lead_card(move(valid_card), move(prefer_card));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto* high_card = &m_trick[0];
|
auto* high_card = &m_trick[0];
|
||||||
for (auto& card : m_trick)
|
for (auto& card : m_trick)
|
||||||
|
|
|
@ -45,6 +45,8 @@ private:
|
||||||
Player& current_player();
|
Player& current_player();
|
||||||
bool game_ended() const { return m_trick_number == 13; }
|
bool game_ended() const { return m_trick_number == 13; }
|
||||||
bool is_winner(Player& player);
|
bool is_winner(Player& player);
|
||||||
|
bool other_player_has_lower_value_card(Player& player, Card& card);
|
||||||
|
bool other_player_has_higher_value_card(Player& player, Card& card);
|
||||||
|
|
||||||
void start_animation(NonnullRefPtrVector<Card> cards, Gfx::IntPoint const& end, Function<void()> did_finish_callback, int initial_delay_ms, int steps = 30);
|
void start_animation(NonnullRefPtrVector<Card> cards, Gfx::IntPoint const& end, Function<void()> did_finish_callback, int initial_delay_ms, int steps = 30);
|
||||||
void stop_animation();
|
void stop_animation();
|
||||||
|
|
|
@ -6,28 +6,39 @@
|
||||||
|
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "Helpers.h"
|
#include "Helpers.h"
|
||||||
|
#include <AK/QuickSort.h>
|
||||||
|
|
||||||
namespace Hearts {
|
namespace Hearts {
|
||||||
|
|
||||||
size_t Player::pick_low_points_low_value_card()
|
size_t Player::pick_lead_card(Function<bool(Card&)> valid_play, Function<bool(Card&)> prefer_card)
|
||||||
{
|
{
|
||||||
int min_points = -1;
|
struct CardWithIndex {
|
||||||
int min_value = -1;
|
RefPtr<Card> card;
|
||||||
int card_index = -1;
|
size_t index;
|
||||||
|
};
|
||||||
|
Vector<CardWithIndex> sorted_hand;
|
||||||
for (size_t i = 0; i < hand.size(); i++) {
|
for (size_t i = 0; i < hand.size(); i++) {
|
||||||
auto& card = hand[i];
|
auto& card = hand[i];
|
||||||
if (card.is_null())
|
if (card)
|
||||||
continue;
|
sorted_hand.empend(card, i);
|
||||||
auto points = hearts_card_points(*card);
|
|
||||||
auto value = hearts_card_value(*card);
|
|
||||||
if (min_points != -1 && (points > min_points || static_cast<int>(value) > min_value))
|
|
||||||
continue;
|
|
||||||
min_points = points;
|
|
||||||
min_value = static_cast<int>(value);
|
|
||||||
card_index = i;
|
|
||||||
}
|
}
|
||||||
VERIFY(card_index != -1);
|
quick_sort(sorted_hand, [](auto& cwi1, auto& cwi2) {
|
||||||
return card_index;
|
if (hearts_card_points(*cwi1.card) >= hearts_card_points(*cwi2.card))
|
||||||
|
return true;
|
||||||
|
if (hearts_card_value(*cwi1.card) >= hearts_card_value(*cwi2.card))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
size_t last_index = -1;
|
||||||
|
for (auto& cwi : sorted_hand) {
|
||||||
|
if (!valid_play(*cwi.card))
|
||||||
|
continue;
|
||||||
|
if (prefer_card(*cwi.card))
|
||||||
|
return cwi.index;
|
||||||
|
last_index = cwi.index;
|
||||||
|
}
|
||||||
|
return last_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<size_t> Player::pick_low_points_high_value_card(Optional<Card::Type> type)
|
Optional<size_t> Player::pick_low_points_high_value_card(Optional<Card::Type> type)
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t pick_low_points_low_value_card();
|
size_t pick_lead_card(Function<bool(Card&)>, Function<bool(Card&)>);
|
||||||
Optional<size_t> pick_low_points_high_value_card(Optional<Card::Type> type = {});
|
Optional<size_t> pick_low_points_high_value_card(Optional<Card::Type> type = {});
|
||||||
Optional<size_t> pick_lower_value_card(Card& other_card);
|
Optional<size_t> pick_lower_value_card(Card& other_card);
|
||||||
Optional<size_t> pick_slightly_higher_value_card(Card& other_card);
|
Optional<size_t> pick_slightly_higher_value_card(Card& other_card);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue