namespace Game { public class ConnectFour { public long[] bitboards; public int[] heights; public int counter; public List moves; public ConnectFour() { bitboards = [0, 0]; heights = [0, 7, 14, 21, 28, 35, 42]; counter = 0; moves = []; } public void Play(int column) { bitboards[counter & 1] ^= 1 << heights[column]; moves.Add(column); heights[column] += 1; counter += 1; } public virtual void Undo() { counter -= 1; int prev = moves.ElementAt(counter); moves.RemoveAt(counter); heights[prev] -= 1; bitboards[counter & 1] ^= 1 << heights[prev]; } public bool HasWon() { int[] directions = [1, 7, 6, 8]; long current = bitboards[counter & 1]; foreach (int direction in directions) { long bb = current & current >> direction; if ((bb & bb >> 2 * direction) != 0) { return true; } } return false; } public List NextMoves() { List moves = new(); for (int i = 0; i < 7; i++) { if (heights[i] < 7 * (i + 1) - 1) { moves.Add(i); } } return moves; } public override string ToString() { List board = []; for (int i = 0; i < 6; i++) { var line = ""; for (int j = 0; j < 7; j++) { long sq = 1; sq <<= j * 7 + i; if ((bitboards[0] & sq) != 0) { line += "1 "; } else if ((bitboards[1] & sq) != 0) { line += "2 "; } else { line += ". "; } } board.Add(line); } board.Reverse(); return string.Join('\n', board); } } public class Position : ConnectFour { public static int[] maxHeights = [6, 13, 20, 27, 34, 41, 48]; public Position FullCopy() { // Instantiate a new Position class Position copy = new(); // Copy the bitboards Array.Copy(bitboards, copy.bitboards, 2); // Copy the moves copy.moves = new List(moves); // Copy the counter copy.counter = counter; // Return the copy return copy; } public Position Copy() { // Instantiate a new Position class Position copy = new(); // Shallow copy the class by only bothering to copy the state // of both bitboards and the counter, as these are the bare // minimum for playing a game of Connect Four. (The counter // is needed to know whose turn it is on the board.) copy.bitboards = [bitboards[0], bitboards[1]]; copy.counter = counter; // Return the copy return copy; } public bool CanPlay(int column) { return heights[column] < maxHeights[column]; } public bool CanWin(int column) { // Shallow copy the board and play the move Position copy = Copy(); copy.Play(column); // Get whether or not someone has won bool hasWon = copy.HasWon(); // Return the result of whether or not there is a winner return hasWon; } // Override the Undo function to prevent it from editing // the moves list (raises errors because shallow copy // of the instance doesn't include move history) public override void Undo() { counter -= 1; int prev = moves.ElementAt(counter); moves.RemoveAt(counter); heights[prev] -= 1; bitboards[counter & 1] ^= 1 << heights[prev]; } } }