using Game.TicTacToe; using OECS; using System.Text; namespace Game.TicTacToe.Tests; internal static class TestHelpers { /// /// Creates a fresh TicTacToe world with 9 empty cells, GameState singleton, and WinCheckSystem. /// public static (World World, SystemGroup Group) SetupGame() { var world = new World(); var group = new SystemGroup(world); group.Add(new WinCheckSystem()); for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++) world.AddComponent(world.CreateEntity(), new Cell { Row = r, Col = c }); world.SetSingleton(new GameState { CurrentPlayer = Player.X, Status = GameStatus.Playing, MoveCount = 0 }); world.PostChanges(); return (world, group); } /// /// Enqueues and runs a sequence of moves. /// public static void PlayMoves(World world, SystemGroup group, params (int Row, int Col)[] moves) { foreach (var (row, col) in moves) { world.Commands.Enqueue(new PlaceMarkCommand { Row = row, Col = col }); group.RunLogical(); } } /// /// Returns a human-readable textual snapshot of the world state. /// public static string SnapshotWorld(World world) { var sb = new StringBuilder(); var state = world.ReadSingleton(); var statusText = state.Status switch { GameStatus.Playing => $"{(state.CurrentPlayer == Player.X ? 'X' : 'O')}'s turn, {state.MoveCount} moves", GameStatus.XWon => "XWon", GameStatus.OWon => "OWon", GameStatus.Draw => "Draw", _ => "Unknown" }; sb.AppendLine($"GameState: {statusText}"); var grid = new char?[3, 3]; foreach (var it in world.Select()) grid[it.Val1.Row, it.Val1.Col] = it.Val2.Player == Player.X ? 'X' : 'O'; int totalCells = 0; int markedCells = 0; for (int r = 0; r < 3; r++) { for (int c = 0; c < 3; c++) { totalCells++; var mark = grid[r, c]; if (mark.HasValue) { markedCells++; sb.AppendLine($" ({r},{c}): {mark.Value}"); } else { sb.AppendLine($" ({r},{c}): ."); } } } sb.AppendLine($"Cells: {totalCells} total, {markedCells} marked"); return sb.ToString().TrimEnd(); } /// /// Returns the (Row, Col) of all empty cells. /// public static List<(int Row, int Col)> GetEmptyCells(World world) { var empty = new List<(int, int)>(); foreach (var it in world.Select(new Query().Without())) empty.Add((it.Val1.Row, it.Val1.Col)); return empty; } /// /// Checks whether placing a mark at (row, col) for the given player would win the game. /// public static bool WouldWin(World world, int row, int col, Player player) { var grid = new Player[3, 3]; foreach (var it in world.Select()) grid[it.Val1.Row, it.Val1.Col] = it.Val2.Player; grid[row, col] = player; for (int r = 0; r < 3; r++) if (grid[r, 0] == player && grid[r, 1] == player && grid[r, 2] == player) return true; for (int c = 0; c < 3; c++) if (grid[0, c] == player && grid[1, c] == player && grid[2, c] == player) return true; if (grid[0, 0] == player && grid[1, 1] == player && grid[2, 2] == player) return true; if (grid[0, 2] == player && grid[1, 1] == player && grid[2, 0] == player) return true; return false; } }