Files
FaraonCardGame/Faraon.Core/AI/FaraonAI.cs
T
2026-09-03 17:54:36 +02:00

189 lines
6.1 KiB
C#

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<Card>? 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<Card> 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<Card> playable, Player player, GameState state)
{
// 1. Ak čelíme sedme, zahráme obyčajnú sedmu, Zeleného dolníka na zrušenie trestu, alebo Červenú sedmu
if (state.PendingDrawCount > 0)
{
var regularSeven = playable.FirstOrDefault(c => c.IsSeven && !c.IsRedSeven);
if (regularSeven != null) return regularSeven;
var greenUnderKnave = playable.FirstOrDefault(c => c.IsGreenUnderKnave);
if (greenUnderKnave != null) return greenUnderKnave;
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 && state.ReviveTurnsRemaining > 0)
{
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<Card> 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;
}
}