namespace Faraon.Core.AI; using Faraon.Core.Models; using Faraon.Core.Engine; public enum AIDecisionType { PlayCard, BurnCards, DrawOrAcknowledge } public record AIDecision( AIDecisionType Type, Card? Card = null, List? Cards = null, Suit? ChosenSuit = null ); public interface IFaraonAI { AIDecision MakeDecision(GameState state, Player player); } public class FaraonAI : IFaraonAI { private readonly Random _random = new(); public AIDecision MakeDecision(GameState state, Player player) { // 1. Kontrola Spálenia (4 rovnaké karty) if (state.Rules.FourOfAKindBurns && state.PendingDrawCount == 0 && !state.PendingSkip) { var fourOfAKindGroup = player.Hand .GroupBy(c => c.Rank) .FirstOrDefault(g => g.Count() == 4); if (fourOfAKindGroup != null) { var burnList = fourOfAKindGroup.ToList(); if (ActionValidator.CanBurnCards(burnList, state.PendingDrawCount, state.PendingSkip, state.Rules)) { return new AIDecision(AIDecisionType.BurnCards, Cards: burnList); } } } // 2. Nájdi všetky zahrateľné karty var playableCards = player.Hand .Where(c => ActionValidator.CanPlayCard( c, state.TopCard, state.ActiveSuit, state.PendingDrawCount, state.PendingSkip, state.Rules)) .ToList(); // Ak nemá čo zahrať -> musí si potiahnuť alebo akceptovať trest if (playableCards.Count == 0) { return new AIDecision(AIDecisionType.DrawOrAcknowledge); } // 3. Rozhodovanie podľa obtiažnosti Card selectedCard; if (player.Difficulty == AIDifficulty.Easy) { selectedCard = playableCards[_random.Next(playableCards.Count)]; } else if (player.Difficulty == AIDifficulty.Hard) { selectedCard = ChooseBestCardSmart(playableCards, player, state); } else // Medium { selectedCard = ChooseBestCardMedium(playableCards, player, state); } // Zozbierame všetky karty rovnakej hodnoty v ruke (combo vyloženie) var multiCards = player.Hand.Where(c => c.Rank == selectedCard.Rank).ToList(); // 4. Ak je vybraná karta Horník, vyber najvýhodnejšiu farbu Suit? chosenSuit = null; if (selectedCard.IsHornik) { chosenSuit = PickBestSuit(player.Hand.Where(c => !multiCards.Contains(c)).ToList()); } return new AIDecision(AIDecisionType.PlayCard, Card: selectedCard, Cards: multiCards, ChosenSuit: chosenSuit); } private Card ChooseBestCardMedium(List playable, Player player, GameState state) { // Ak sa musí brániť proti sedme, zahrá sedmu if (state.PendingDrawCount > 0) { var seven = playable.FirstOrDefault(c => c.IsSeven); if (seven != null) return seven; } // Ak sa musí brániť proti esu, zahrá eso if (state.PendingSkip) { var ace = playable.FirstOrDefault(c => c.IsAce); if (ace != null) return ace; } // Ak má v ruke len 1 kartu navyše a môže vyhrať if (player.Hand.Count <= 2) { return playable[0]; } // Radšej šetrí Horníka ako žolíka, ak má inú normálnu kartu var nonHornik = playable.Where(c => !c.IsHornik).ToList(); if (nonHornik.Count > 0) { return nonHornik[_random.Next(nonHornik.Count)]; } return playable[0]; } private Card ChooseBestCardSmart(List playable, Player player, GameState state) { // 1. Ak čelíme sedme, prioritne zahráme obyčajnú sedmu pred Červenou sedmou (ak je niekto vonku, šetríme ju) if (state.PendingDrawCount > 0) { var regularSeven = playable.FirstOrDefault(c => c.IsSeven && !c.IsRedSeven); if (regularSeven != null) return regularSeven; var redSeven = playable.FirstOrDefault(c => c.IsRedSeven); if (redSeven != null) return redSeven; } // 2. Ak čelíme esu, prebijeme esom if (state.PendingSkip) { var ace = playable.FirstOrDefault(c => c.IsAce); if (ace != null) return ace; } // 3. Ak môžeme touto kartou hru ukončiť (posledná karta v ruke) if (player.Hand.Count == 1) { return playable[0]; } // 4. Ak má Červenú sedmu a na stole je niekto na oživenie (LastFinishedPlayer), oživíme ho! if (state.Rules.RedSevenRevives && state.LastFinishedPlayer != null) { var redSeven = playable.FirstOrDefault(c => c.IsRedSeven); if (redSeven != null) return redSeven; } // 5. Ak máme iné možnosti, šetríme si Horníka na núdzu var nonHornikCards = playable.Where(c => !c.IsHornik).ToList(); if (nonHornikCards.Count > 0) { // Zvoľ kartu farby, z ktorej máme najviac kariet var suitCounts = player.Hand .GroupBy(c => c.Suit) .ToDictionary(g => g.Key, g => g.Count()); return nonHornikCards .OrderByDescending(c => suitCounts.GetValueOrDefault(c.Suit, 0)) .First(); } return playable[0]; } public static Suit PickBestSuit(List remainingHand) { if (remainingHand.Count == 0) return Suit.Hearts; // Nájdi farbu, ktorej máme najviac v ruke var mostFrequentSuit = remainingHand .GroupBy(c => c.Suit) .OrderByDescending(g => g.Count()) .First() .Key; return mostFrequentSuit; } }