using System.Text; using MinMaxAB; namespace FourInARow; public class GameBoard : ICloneable { public Player[,] cells; public readonly GameDimensions dimensions; protected int lastPlayedRow; protected int lastPlayedColumn; public GameBoard(GameDimensions dim) { cells = Extensions.Fill(dim.Columns, dim.Rows, Player.None); dimensions = dim; } private bool cacheInvalidated = false; private Player winnerCache = Player.None; public bool PlaceCoin(Player player, int column) { int row = 0; while (row < dimensions.Rows && cells[column, row] == Player.None) { row++; } if (row == 0) return false; cells[column, row - 1] = player; cacheInvalidated = true; lastPlayedRow = row; lastPlayedColumn = column; return true; } public bool RemoveFromTop(int column) { int row = 0; while (row < dimensions.Rows && cells[column, row] == Player.None) { row++; } if (row == dimensions.Rows) return false; cells[column, row] = Player.None; cacheInvalidated = true; return true; } public static Player Opposite(Player player) => player switch { Player.Player => Player.Computer, Player.Computer => Player.Player, _ => Player.None }; public Player? GetWinner() { if (!cacheInvalidated) return winnerCache; cacheInvalidated = false; for (int i = 0; i < dimensions.Columns; i++) { for (int j = 0; j < dimensions.Rows; j++) { if (cells[i, j] == Player.None) continue; bool h = i + 3 < dimensions.Columns; bool v = j + 3 < dimensions.Rows; if (!h && !v) continue; bool d = h && v; bool bd = v && i - 3 >= 0; for (int k = 1; k < 4; k++) { h = h && cells[i, j] == cells[i + k, j]; v = v && cells[i, j] == cells[i, j + k]; d = d && cells[i, j] == cells[i + k, j + k]; bd = bd && cells[i, j] == cells[i - k, j + k]; if (!h && !v && !d && !bd) break; } if (h || v || d || bd) { winnerCache = cells[i, j]; return cells[i, j]; } } } winnerCache = Player.None; return Player.None; } public bool HasEmptyColumns() { for (int x = 0; x < dimensions.Columns; x++) { if (cells[x, 0] == Player.None) return true; } return false; } protected char PlayerChar(Player player) => player switch { Player.Player => 'O', Player.Computer => 'X', _ => ' ', }; public override string ToString() { string sep = $"\n{new('-', dimensions.Columns * 4)}"; var builder = new StringBuilder(sep); builder.Append("\n| "); for (int column = 0; column < dimensions.Columns; column++) { builder.Append(column + 1).Append(" | "); } builder.AppendLine(sep); for (int row = 0; row < dimensions.Rows; row++) { builder.Append("| "); for (int column = 0; column < dimensions.Columns; column++) builder.Append(PlayerChar(cells[column, row])).Append(" | "); builder.AppendLine(sep); } return builder.ToString(); } public object Clone() { var newBoard = new GameBoard(dimensions) { cells = (cells.Clone() as Player[,])! }; return newBoard; } }