namespace Faraon.Tests; using Faraon.Core.Models; using Faraon.Core.Engine; using Faraon.Core.AI; public class GameEngineTests { [Fact] public void StartGame_DealsCorrectNumberOfCards() { var engine = new GameEngine(seed: 42); var players = new List { new Player("Hráč 1", PlayerType.Human), new Player("AI 1", PlayerType.AI), new Player("AI 2", PlayerType.AI), new Player("AI 3", PlayerType.AI) }; var rules = new RuleOptions { InitialCardCount = 5 }; engine.StartGame(players, rules); Assert.Equal(4, engine.State.Players.Count); Assert.All(engine.State.Players, p => Assert.Equal(5, p.Hand.Count)); Assert.Single(engine.State.DiscardPile); Assert.Equal(11, engine.State.DrawDeck.Count); } [Fact] public void Seven_IncreasesPendingDrawCount() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var rules = new RuleOptions { StackSevens = true }; engine.StartGame(new List { p1, p2 }, rules); p1.Hand.Clear(); var sevenCard = new Card(Suit.Hearts, Rank.Seven); p1.Hand.Add(sevenCard); p1.Hand.Add(new Card(Suit.Hearts, Rank.Eight)); // extra card so p1 does not finish engine.State.DiscardPile.Clear(); engine.State.DiscardPile.Add(new Card(Suit.Hearts, Rank.Ten)); var played = engine.PlayCard(p1, sevenCard); Assert.True(played); Assert.Equal(2, engine.State.PendingDrawCount); Assert.Equal(p2, engine.State.CurrentPlayer); } [Fact] public void Ace_SetsPendingSkip() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var rules = new RuleOptions { CounterAceWithAce = true }; engine.StartGame(new List { p1, p2 }, rules); p1.Hand.Clear(); var aceCard = new Card(Suit.Bells, Rank.Ace); p1.Hand.Add(aceCard); p1.Hand.Add(new Card(Suit.Bells, Rank.Eight)); // extra card engine.State.DiscardPile.Clear(); engine.State.DiscardPile.Add(new Card(Suit.Bells, Rank.Nine)); var played = engine.PlayCard(p1, aceCard); Assert.True(played); Assert.True(engine.State.PendingSkip); Assert.Equal(p2, engine.State.CurrentPlayer); // Hráč 2 akceptuje státie engine.DrawOrAcknowledge(p2); Assert.False(engine.State.PendingSkip); Assert.Equal(p1, engine.State.CurrentPlayer); } [Fact] public void Hornik_ChangesSuitSuccessfully() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var rules = new RuleOptions(); engine.StartGame(new List { p1, p2 }, rules); p1.Hand.Clear(); var hornik = new Card(Suit.Acorns, Rank.OverKnave); p1.Hand.Add(hornik); p1.Hand.Add(new Card(Suit.Leaves, Rank.Eight)); // extra card engine.State.DiscardPile.Clear(); engine.State.DiscardPile.Add(new Card(Suit.Hearts, Rank.Eight)); var played = engine.PlayCard(p1, hornik, Suit.Leaves); Assert.True(played); Assert.Equal(Suit.Leaves, engine.State.ActiveSuit); } [Fact] public void RedSeven_RevivesFinishedPlayer() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var p3 = new Player("Hráč 3", PlayerType.Human); var rules = new RuleOptions { RedSevenRevives = true }; engine.StartGame(new List { p1, p2, p3 }, rules); p3.Hand.Clear(); p3.FinishedPosition = 1; engine.State.LastFinishedPlayer = p3; p1.Hand.Clear(); var redSeven = new Card(Suit.Hearts, Rank.Seven); p1.Hand.Add(redSeven); p1.Hand.Add(new Card(Suit.Hearts, Rank.Eight)); engine.State.DiscardPile.Clear(); engine.State.DiscardPile.Add(new Card(Suit.Hearts, Rank.Ten)); var played = engine.PlayCard(p1, redSeven); Assert.True(played); Assert.False(p3.HasFinished); Assert.Null(p3.FinishedPosition); Assert.Equal(3, p3.Hand.Count); } [Fact] public void FourOfAKind_BurnsAndAllowsAnotherMove() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var rules = new RuleOptions { FourOfAKindBurns = true }; engine.StartGame(new List { p1, p2 }, rules); p1.Hand.Clear(); var fourKings = new List { new Card(Suit.Hearts, Rank.King), new Card(Suit.Leaves, Rank.King), new Card(Suit.Acorns, Rank.King), new Card(Suit.Bells, Rank.King) }; p1.Hand.AddRange(fourKings); p1.Hand.Add(new Card(Suit.Hearts, Rank.Eight)); var burned = engine.BurnCards(p1, fourKings); Assert.True(burned); Assert.Equal(p1, engine.State.CurrentPlayer); // Hráč pokračuje Assert.Single(p1.Hand); } [Fact] public void MultiSeven_StacksDoublePenalty() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var rules = new RuleOptions { StackSevens = true }; engine.StartGame(new List { p1, p2 }, rules); p1.Hand.Clear(); var sevens = new List { new Card(Suit.Hearts, Rank.Seven), new Card(Suit.Bells, Rank.Seven) }; p1.Hand.AddRange(sevens); p1.Hand.Add(new Card(Suit.Hearts, Rank.Eight)); // extra card engine.State.DiscardPile.Clear(); engine.State.DiscardPile.Add(new Card(Suit.Hearts, Rank.Ten)); var played = engine.PlayCards(p1, sevens); Assert.True(played); Assert.Equal(4, engine.State.PendingDrawCount); // 2x sedma = +4 karty Assert.Equal(p2, engine.State.CurrentPlayer); } [Fact] public void MultiCards_PlaysBatchOfSameRank() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var rules = new RuleOptions(); engine.StartGame(new List { p1, p2 }, rules); p1.Hand.Clear(); var dolniks = new List { new Card(Suit.Hearts, Rank.UnderKnave), new Card(Suit.Leaves, Rank.UnderKnave), new Card(Suit.Bells, Rank.UnderKnave) }; p1.Hand.AddRange(dolniks); p1.Hand.Add(new Card(Suit.Hearts, Rank.Eight)); // extra card engine.State.DiscardPile.Clear(); engine.State.DiscardPile.Add(new Card(Suit.Hearts, Rank.Nine)); var played = engine.PlayCards(p1, dolniks); Assert.True(played); Assert.Single(p1.Hand); // Ostaná len 1 karta Assert.Equal(4, engine.State.DiscardPile.Count); Assert.Equal(p2, engine.State.CurrentPlayer); } [Fact] public void MultiCards_PreservesPlayerChosenOrder_AndSetsTopCard() { var engine = new GameEngine(seed: 42); var p1 = new Player("Hráč 1", PlayerType.Human); var p2 = new Player("Hráč 2", PlayerType.Human); var rules = new RuleOptions(); engine.StartGame(new List { p1, p2 }, rules); p1.Hand.Clear(); var card1 = new Card(Suit.Hearts, Rank.Eight); // Matches table Hearts var card2 = new Card(Suit.Bells, Rank.Eight); // Desired top card (Bells) p1.Hand.Add(card1); p1.Hand.Add(card2); p1.Hand.Add(new Card(Suit.Acorns, Rank.Nine)); // extra engine.State.DiscardPile.Clear(); engine.State.DiscardPile.Add(new Card(Suit.Hearts, Rank.Ten)); // Player explicitly chooses: card1 first, card2 second (so card2 becomes top of discard pile) var sequence = new List { card1, card2 }; var played = engine.PlayCards(p1, sequence); Assert.True(played); Assert.Equal(card2, engine.State.TopCard); // Card2 is on top Assert.NotNull(engine.State.TopCard); Assert.Equal(Suit.Bells, engine.State.TopCard.Suit); } [Fact] public void FaraonAI_MakesValidDecisions() { var engine = new GameEngine(seed: 42); var p1 = new Player("AI Bot", PlayerType.AI, difficulty: AIDifficulty.Hard); var p2 = new Player("AI Bot 2", PlayerType.AI, difficulty: AIDifficulty.Hard); engine.StartGame(new List { p1, p2 }, new RuleOptions()); var ai = new FaraonAI(); var decision = ai.MakeDecision(engine.State, p1); Assert.NotNull(decision); if (decision.Type == AIDecisionType.PlayCard) { Assert.NotNull(decision.Card); Assert.True(engine.CanPlayCard(p1, decision.Card)); } } }