diff --git a/Userland/Games/Hearts/Game.cpp b/Userland/Games/Hearts/Game.cpp index ee0469fd1e..d17fa9097b 100644 --- a/Userland/Games/Hearts/Game.cpp +++ b/Userland/Games/Hearts/Game.cpp @@ -161,6 +161,32 @@ void Game::timer_event(Core::TimerEvent&) 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) \ do { \ 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); VERIFY(clubs_2.has_value()); return clubs_2.value(); - } else - return player.pick_low_points_low_value_card(); + } else { + 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]; for (auto& card : m_trick) diff --git a/Userland/Games/Hearts/Game.h b/Userland/Games/Hearts/Game.h index 560ca64ecc..79c323d71a 100644 --- a/Userland/Games/Hearts/Game.h +++ b/Userland/Games/Hearts/Game.h @@ -45,6 +45,8 @@ private: Player& current_player(); bool game_ended() const { return m_trick_number == 13; } 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 cards, Gfx::IntPoint const& end, Function did_finish_callback, int initial_delay_ms, int steps = 30); void stop_animation(); diff --git a/Userland/Games/Hearts/Player.cpp b/Userland/Games/Hearts/Player.cpp index ab129f4739..021d79001f 100644 --- a/Userland/Games/Hearts/Player.cpp +++ b/Userland/Games/Hearts/Player.cpp @@ -6,28 +6,39 @@ #include "Player.h" #include "Helpers.h" +#include namespace Hearts { -size_t Player::pick_low_points_low_value_card() +size_t Player::pick_lead_card(Function valid_play, Function prefer_card) { - int min_points = -1; - int min_value = -1; - int card_index = -1; + struct CardWithIndex { + RefPtr card; + size_t index; + }; + Vector sorted_hand; for (size_t i = 0; i < hand.size(); i++) { auto& card = hand[i]; - if (card.is_null()) - continue; - auto points = hearts_card_points(*card); - auto value = hearts_card_value(*card); - if (min_points != -1 && (points > min_points || static_cast(value) > min_value)) - continue; - min_points = points; - min_value = static_cast(value); - card_index = i; + if (card) + sorted_hand.empend(card, i); } - VERIFY(card_index != -1); - return card_index; + quick_sort(sorted_hand, [](auto& cwi1, auto& cwi2) { + 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 Player::pick_low_points_high_value_card(Optional type) diff --git a/Userland/Games/Hearts/Player.h b/Userland/Games/Hearts/Player.h index be1febd6a9..d7737951fe 100644 --- a/Userland/Games/Hearts/Player.h +++ b/Userland/Games/Hearts/Player.h @@ -21,7 +21,7 @@ public: { } - size_t pick_low_points_low_value_card(); + size_t pick_lead_card(Function, Function); Optional pick_low_points_high_value_card(Optional type = {}); Optional pick_lower_value_card(Card& other_card); Optional pick_slightly_higher_value_card(Card& other_card);