diff --git a/Game.Blackjack.Tests/TestHelpers.cs b/Game.Blackjack.Tests/TestHelpers.cs new file mode 100644 index 0000000..8795743 --- /dev/null +++ b/Game.Blackjack.Tests/TestHelpers.cs @@ -0,0 +1,131 @@ +using Game.Blackjack; +using OECS; +using System.Text; + +namespace Game.Blackjack.Tests; + +internal static class TestHelpers +{ + private const int StartingChips = 100; + + /// + /// Creates a fresh Blackjack world with systems registered and GameState singleton initialized. + /// + public static (World World, SystemGroup Group) SetupGame(uint seed = 42) + { + var world = new World(); + var group = new SystemGroup(world); + group.Add(new DeckSetupSystem()); + group.Add(new DealSystem()); + group.Add(new PlayerBustCheckSystem()); + group.Add(new DealerSystem()); + + world.SetSingleton(new GameState + { + Phase = GamePhase.Betting, + Result = RoundResult.None, + Chips = StartingChips, + CurrentBet = 0, + RoundNumber = 1, + Seed = seed + }); + world.PostChanges(); + + return (world, group); + } + + /// + /// Returns a human-readable textual snapshot of the world state. + /// + public static string SnapshotWorld(World world) + { + var sb = new StringBuilder(); + var state = world.ReadSingleton(); + sb.AppendLine($"Phase: {state.Phase}"); + sb.AppendLine($"Chips: {state.Chips}"); + sb.AppendLine($"Bet: {state.CurrentBet}"); + sb.AppendLine($"Round: {state.RoundNumber}"); + sb.AppendLine($"Result: {state.Result}"); + sb.AppendLine($"Seed: {state.Seed}"); + + var deckEntity = FindEntity(world); + if (deckEntity != Entity.Null) + { + var cardsInDeck = world.GetSources(deckEntity).ToList(); + sb.AppendLine($"Cards in deck: {cardsInDeck.Count}"); + } + + var playerHand = FindEntity(world); + if (playerHand != Entity.Null) + { + var cards = world.GetSources(playerHand).ToList(); + sb.AppendLine($"Player hand: {cards.Count} cards"); + foreach (var cardEntity in cards) + { + var card = world.ReadComponent(cardEntity); + sb.AppendLine($" {card.Rank} of {card.Suit}"); + } + } + + var dealerHand = FindEntity(world); + if (dealerHand != Entity.Null) + { + var cards = world.GetSources(dealerHand).ToList(); + sb.AppendLine($"Dealer hand: {cards.Count} cards"); + foreach (var cardEntity in cards) + { + var card = world.ReadComponent(cardEntity); + sb.AppendLine($" {card.Rank} of {card.Suit}"); + } + } + + int entityCount = 0; + using (var iter = world.Select()) + { + while (iter.MoveNext()) entityCount++; + } + sb.AppendLine($"Card entities: {entityCount}"); + + return sb.ToString().TrimEnd(); + } + + public static Entity FindEntity(World world) where T : struct + { + return world.FindEntity(); + } + + public static int CountCardsInHand(World world, Entity handEntity) + { + return world.GetSources(handEntity).Count; + } + + public static List GetHandCards(World world, Entity hand) + { + var cards = new List(); + foreach (var cardEntity in world.GetSources(hand)) + { + var card = world.ReadComponent(cardEntity); + cards.Add($"{card.Rank} of {card.Suit}"); + } + return cards; + } + + public static List<(Suit, Rank)> GetAllCards(World world) + { + var cards = new List<(Suit, Rank)>(); + using (var iter = world.Select()) + { + while (iter.MoveNext()) + { + var card = iter.Val1; + cards.Add((card.Suit, card.Rank)); + } + } + cards.Sort((a, b) => + { + int cmp = a.Item1.CompareTo(b.Item1); + return cmp != 0 ? cmp : a.Item2.CompareTo(b.Item2); + }); + return cards; + } +} \ No newline at end of file