static List<int> Greedy(Board board, int player) { List<int> greedyReturn = new List<int>(); // 0: points after move, 1: move X, 2: move Y, 3: helper X, 4: helper Y greedyReturn.Add(board.Evaluate(player)); greedyReturn.Add(-1); greedyReturn.Add(-1); greedyReturn.Add(-1); greedyReturn.Add(-1); List<List<int>> possibilities = board.GetPossibleMoves(player); if (possibilities.Count == 0) { return greedyReturn; } Board newBoard; foreach (List<int> move in board.GetPossibleMoves(player)) { // Get new board configuration newBoard = board.MakeMove(move, player); if (newBoard.Evaluate(player) > greedyReturn[0])//if better than last possible move { greedyReturn.Clear();//clear the last one greedyReturn.Add(newBoard.Evaluate(player)); foreach (int val in move) greedyReturn.Add(val); } } return greedyReturn; }
public void FlipPiece_PositiveTest() { m_board = new Board(8); m_board.SetFieldValue(FieldValue.Black, new Coords(0, 0)); m_board.FlipPiece(new Coords(0, 0)); Assert.AreEqual(FieldValue.White, m_board.GetFieldValue(new Coords(0, 0))); }
public MainWindow() { InitializeComponent(); m_board = new Board(8); m_game = new OthelloGame(m_board); Board.SetBoard(m_board);// DataContext = m_guiboard; Board.BoardClickedEvent += BoardClicked; }
public void ClearBoard_PositiveTest() { m_board = new Board(8); m_board.SetFieldValue(FieldValue.Black, new Coords(3, 2)); m_board.ClearBoard(); var numNotEmpty = m_board.CountBlacks + m_board.CountWhites; Assert.AreEqual(0, numNotEmpty); }
public void CountByFieldValue_PositiveTest() { m_board = new Board(8); m_board.SetStartValues(); m_board.SetFieldValue(FieldValue.Black, new Coords(0, 0)); Assert.AreEqual(3, m_board.CountByFieldValue(FieldValue.Black)); Assert.AreEqual(59, m_board.CountByFieldValue(FieldValue.Empty)); }
public void GetFieldValue_NegativeTest() { m_board = new Board(8); bool exceptionThrown = false; try { m_board.GetFieldValue(new Coords(0, -1)); } catch (ArgumentOutOfRangeException) { exceptionThrown = true; } Assert.IsTrue(exceptionThrown); exceptionThrown = false; try { m_board.GetFieldValue(new Coords(-1, -1)); } catch (ArgumentOutOfRangeException) {exceptionThrown = true;} Assert.IsTrue(exceptionThrown); exceptionThrown = false; try { m_board.GetFieldValue(new Coords(-1, 0)); } catch (ArgumentOutOfRangeException) { exceptionThrown = true; } Assert.IsTrue(exceptionThrown); exceptionThrown = false; try { m_board.GetFieldValue(new Coords(8, 0)); } catch (ArgumentOutOfRangeException) { exceptionThrown = true; } Assert.IsTrue(exceptionThrown); exceptionThrown = false; try { m_board.GetFieldValue(new Coords(0, 8)); } catch (ArgumentOutOfRangeException) { exceptionThrown = true; } Assert.IsTrue(exceptionThrown); exceptionThrown = false; try { m_board.GetFieldValue(new Coords(8, 8)); } catch (ArgumentOutOfRangeException) { exceptionThrown = true; } Assert.IsTrue(exceptionThrown); exceptionThrown = false; try { m_board.GetFieldValue(new Coords(8, -1)); } catch (ArgumentOutOfRangeException) { exceptionThrown = true; } Assert.IsTrue(exceptionThrown); exceptionThrown = false; try { m_board.GetFieldValue(new Coords(-1, 8)); } catch (ArgumentOutOfRangeException) { exceptionThrown = true; } Assert.IsTrue(exceptionThrown); }
public void IsValidMove_PositiveTest() { var board = new Board(8); board.SetFieldValue(FieldValue.Black, new Coords(0, 0)); board.SetFieldValue(FieldValue.White, new Coords(1, 0)); var valid = OthelloRules.IsValidMove(FieldValue.Black, new Coords(2, 0), board); Assert.IsTrue(valid); board.SetFieldValue(FieldValue.White, new Coords(1, 1)); valid = OthelloRules.IsValidMove(FieldValue.Black, new Coords(2, 2), board); Assert.IsTrue(valid); }
/// <summary> /// Sets the board that should be shown in the GUI. /// /// TODO: Remove listener for old board. /// </summary> public void SetBoard(Board board) { Rows = new ObservableCollection<ObservableCollection<GUIField>>(); m_board = board; //Listen for new board m_board.BoardChanged += BoardChanged; for (int row = 0; row < m_board.Size; row++) { var columns = new ObservableCollection<GUIField>(); for (int col = 0; col < m_board.Size; col++) { var coords = new Coords(col, row); var field = new GUIField(board.GetFieldValue(coords), coords); columns.Add(field); } Rows.Add(columns); } this.DataContext = Rows; }
static List<int> Human(Board board, int player) { List<int> humanReturn = new List<int>(); humanReturn.Add(board.Evaluate(player)); humanReturn.Add(-1); humanReturn.Add(-1); humanReturn.Add(-1); humanReturn.Add(-1); if (board.GetPossibleMoves(player).Count == 0) { return humanReturn; } while (true) { Console.Write("enter x-position:"); humanReturn[1] = int.Parse(Console.ReadLine()); Console.WriteLine(); Console.Write("enter y-position:"); humanReturn[2] = int.Parse(Console.ReadLine()); Console.WriteLine(); foreach (List<int> move in board.GetPossibleMoves(player)) { if (humanReturn[1] == move[0] && humanReturn[2] == move[1]) { Board newBoard = board.MakeMove(move, player); humanReturn[3] = move[2]; humanReturn[4] = move[3]; return humanReturn; } } Console.WriteLine("invalid move!"); } }
public Game(int i_BoardSize) { m_Board = new Board(i_BoardSize); }
private void InitBoard() { label5.Text = ""; board = new Board(false); panel1.Width = 8 * Board.WIDTH; panel1.Height = 8 * Board.WIDTH; }
static void Main(string[] args) { // Maximum depth the algorithm should search to int maxDepth = 4; // Board attributes for its size int boardRows = 8, boardCols = 8; // Default empty square value - BE SURE ITS THE SAME HERE AND IN BOARD CLASS int emptySquare = 7; // Containers for the miniMax return values List<int> miniMaxValues = new List<int>(); // Container to store and pass on only the move returned by miniMax List<int> chosenMove = new List<int>(); // Initial values for blackPoint and whitePoints int blackPoints = 0, whitePoints = 0; // String to say who won the game string winner = "None"; #region Create Start // Create rows int[][] startState = new int[boardRows][]; // Create cols for (int i = 0; i < boardRows; ++i) startState[i] = new int[boardCols]; // fill in the board with start state for (int r = 0; r < boardRows; ++r) { for (int c = 0; c < boardCols; ++c) { if (r == 3 && c == 3) startState[r][c] = 1; else if (r == 3 && c == 4) startState[r][c] = 0; else if (r == 4 && c == 3) startState[r][c] = 0; else if (r == 4 && c == 4) startState[r][c] = 1; else startState[r][c] = emptySquare; } } #endregion Board board = new Board(startState, 1); board.DisplayBoard(); #region MiniMax Driver Section while (true) { // Player 1 (Black) Moves first miniMaxValues = MiniMax(board, 1, 1, maxDepth, 0); //miniMaxValues = MiniMaxMove(board, 1, 1, maxDepth, 0); //miniMaxValues = Unpredictable(board, 1); //miniMaxValues = Greedy(board, 1); //miniMaxValues = Human(board, 1); if (((miniMaxValues[1] == -1 || miniMaxValues[2] == -1 || miniMaxValues[3] == -1 || miniMaxValues[4] == -1) && board.IsGameOver(0)) || //other player cannot move also (board.Evaluate(1) == 0) || (board.Evaluate(0) == 0)// one player or the other have 0 point ) { blackPoints = board.Evaluate(1); whitePoints = board.Evaluate(0); break; } else if(miniMaxValues[1] != -1 && miniMaxValues[2] != -1 && miniMaxValues[3] != -1 && miniMaxValues[4] != -1) { // New move coordinates bool skip = true; chosenMove.Clear(); foreach (int val in miniMaxValues) { if (skip) { skip = false; continue; } chosenMove.Add(val); } board = board.MakeMove(chosenMove, 1); board.DisplayBoard(); } // Player 2 (White) Moves second //miniMaxValues = MiniMax(board, 0, 0, maxDepth, 0); //miniMaxValues = MiniMaxMove(board, 0, 0, maxDepth, 0); //miniMaxValues = Unpredictable(board, 0); miniMaxValues = Greedy(board, 0); //miniMaxValues = Human(board, 0); if (((miniMaxValues[1] == -1 || miniMaxValues[2] == -1 || miniMaxValues[3] == -1 || miniMaxValues[4] == -1) && board.IsGameOver(1)) || //other player cannot move also (board.Evaluate(1) == 0) || (board.Evaluate(0) == 0)// one player or the other have 0 point ) { blackPoints = board.Evaluate(1); whitePoints = board.Evaluate(0); break; } else if (miniMaxValues[1] != -1 && miniMaxValues[2] != -1 && miniMaxValues[3] != -1 && miniMaxValues[4] != -1) { // New move coordinates bool skip = true; chosenMove.Clear(); foreach (int val in miniMaxValues) { if (skip) { skip = false; continue; } chosenMove.Add(val); } board = board.MakeMove(chosenMove, 0); board.DisplayBoard(); } } #endregion // End game output if (blackPoints > whitePoints) winner = "Black Wins!"; else if (whitePoints > blackPoints) winner = "White Wins!"; else winner = "It's a Draw!"; Console.WriteLine("Game Over!"); Console.WriteLine("Black: " + blackPoints + " White: " + whitePoints); Console.WriteLine(winner); #region System("pause") Equivalent Console.WriteLine(); Console.Write("Press Enter To Exit"); Console.ReadLine(); #endregion }
//randomly choose a move static List<int> Unpredictable(Board board, int player) { List<int> UnpredictableReturn = new List<int>(); // 0: points after move, 1: move X, 2: move Y, 3: helper X, 4: helper Y List<List<int>> possibilities = board.GetPossibleMoves(player); if (possibilities.Count == 0) { UnpredictableReturn.Add(board.Evaluate(player)); UnpredictableReturn.Add(-1); UnpredictableReturn.Add(-1); UnpredictableReturn.Add(-1); UnpredictableReturn.Add(-1); return UnpredictableReturn; } Random random = new Random(); int randomMove = random.Next(0, possibilities.Count); List<int> move = possibilities[randomMove]; UnpredictableReturn.Add(board.MakeMove(move, player).Evaluate(player)); foreach (int val in move) UnpredictableReturn.Add(val); return UnpredictableReturn; }
private void ResetBoard() { label5.Text = ""; board = new Board(true); }
//MiniMax base on number of moves static List<int> MiniMaxMove(Board board, int player, int callingPlayer, int maxDepth, int currentDepth) { // This array contains: bestScore, bestMoveX, bestMoveY in that order List<int> miniMaxReturn = new List<int>(); // This array contains: bestScore, bestMoveX, bestMoveY in that order List<int> currentReturn = new List<int>(); // Check for recursion end if (board.IsGameOver(player) || currentDepth == maxDepth) { miniMaxReturn.Add(board.GetPossibleMoves(callingPlayer).Count); miniMaxReturn.Add(-1); miniMaxReturn.Add(-1); miniMaxReturn.Add(-1); miniMaxReturn.Add(-1); return miniMaxReturn; } // Depending on the player we choose a starting bestScore // Negative if currentPlayer so we always chose a higher scored board if (board.GetCurrentPlayer() == player) miniMaxReturn.Add(-int.MaxValue); // Positive for opponent so that they always choose a lower scored // board else miniMaxReturn.Add(int.MaxValue); // Contains default moveX, moveY miniMaxReturn.Add(-1); miniMaxReturn.Add(-1); miniMaxReturn.Add(-1); miniMaxReturn.Add(-1); Board newBoard; // Recurse for each move foreach (List<int> move in board.GetPossibleMoves(player)) { // Get new board configuration newBoard = board.MakeMove(move, player); // Recurse till return currentReturn = MiniMaxMove(newBoard, 1 - player, callingPlayer, maxDepth, currentDepth + 1); // Update the best score based on which player is playing if (board.GetCurrentPlayer() == player) { if (currentReturn[0] > miniMaxReturn[0]) { miniMaxReturn.Clear(); miniMaxReturn.Add(currentReturn[0]); //miniMaxReturn[0] = currentReturn[0]; foreach(int val in move) miniMaxReturn.Add(val); } } else { if (currentReturn[0] < miniMaxReturn[0]) { miniMaxReturn.Clear(); miniMaxReturn.Add(currentReturn[0]); //miniMaxReturn[0] = currentReturn[0]; foreach (int val in move) miniMaxReturn.Add(val); } } } return miniMaxReturn; }
/// <summary> /// Tìm nước đi tốt nhất (MiniMax) /// </summary> /// <param name="piece"></param> /// <param name="alpha"></param> /// <param name="depth">Độ sâu</param> /// <param name="board"></param> /// <param name="panel"></param> /// <returns></returns> public static int GetBestStep(int piece, int alpha, int depth, int difficulty, Board board, Panel panel) { // Giới hạn độ sâu if (depth > difficulty || board.WhiteCount + board.BlackCount == 64) { int k = board.GetValue(); return k; } // List các nước đi có thể xảy ra List<int[]> EnableStepsList = board.GetEnableSteps(piece); if (EnableStepsList.Count == 0 && piece == WHITE) return -Int32.MaxValue; int bestvalue = Int32.MaxValue; foreach (int[] s in EnableStepsList) { if (AlphaBetaPruning(alpha, bestvalue, depth)) { return alpha; } Board boardcopy = board.Copy(); boardcopy.Move(s[1], s[0], piece, true); // đệ quy tiếp, tăng độ sâu lên 1 int cur_value = GetBestStep(-piece, alpha, depth + 1, difficulty, boardcopy, panel); bestvalue = MinMaxValue(cur_value, -bestvalue, depth); } return bestvalue; }
/// <summary> /// Copy ma trận bàn cờ /// </summary> /// <returns>Bàn cờ đã copy</returns> public Board Copy() { Board b = new Board(false); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { b.board[i, j] = board[i, j]; } } b.whitecount = this.WhiteCount; b.blackcount = this.BlackCount; return b; }
public void RestartGame() { Board.Restart(); Board.InitNewOthelloGame(); }
// This Function makes a move given a certain player, // the location the move starts from, // and the location the move ends at public Board MakeMove(List<int> move, int player) { // Create temporary board int[][] temp = new int[this.board.Length][]; for (int i = 0; i < this.board[0].Length; ++i) temp[i] = new int[this.board[0].Length]; // Fill it with the current board values for (int r = 0; r < this.board.Length; ++r) { for (int c = 0; c < this.board[r].Length; ++c) temp[r][c] = this.board[r][c]; } // Set new game piece temp[move[1]][move[0]] = player; bool done = false; int indexCtr = 2; // Toggle all taken pieces int nmx = move[0], nmy = move[1]; int mx = move[2], my = move[3]; int incr = 0; // This whole section is for toggling the pieces // my = move-y mx = move-x // nmy = new-move-y nmx = new-move-x // my is strictly greater than nmy while (!done) { if (my > nmy) { // up-left if (mx > nmx) { for (int i = my; i >= nmy; --i) { temp[i][mx + (incr--)] = player; } } // up-right else if (mx < nmx) { for (int i = my; i >= nmy; --i) { temp[i][mx + (incr++)] = player; } } // up else { for (int i = nmy; i <= my; ++i) { for (int j = nmx; j <= mx; ++j) temp[i][j] = player; } } } // nmy is strictly greater than my else if (my < nmy) { // down-left if (mx > nmx) { for (int i = my; i <= nmy; ++i) { temp[i][mx + (incr--)] = player; } } // down-right else if (mx < nmx) { for (int i = my; i <= nmy; ++i) { temp[i][mx + (incr++)] = player; } } // down else { for (int i = my; i <= nmy; ++i) { for (int j = mx; j <= nmx; ++j) temp[i][j] = player; } } } else { // Left if (mx > nmx) { for (int j = nmx; j <= mx; ++j) temp[my][j] = player; } // Right else if (mx < nmx) { for (int j = mx; j <= nmx; ++j) temp[my][j] = player; } // This case is a last resort failure case, // should and never does get reached else { Console.WriteLine("Somehow both x and y are the same"); Console.WriteLine("DEBUG DAMNIT!"); Console.ReadLine(); } } // If there are multiple initial points // Increment the index and reset the incr variable if (indexCtr < move.Count) { mx = move[indexCtr++]; my = move[indexCtr++]; incr = 0; } // Else if there are no more initial points, exit loop else done = true; } Board b = new Board(temp, player); return b; }
public void SetStartValues_PositiveTest() { m_board = new Board(8); m_board.SetStartValues(); Assert.AreEqual(2, m_board.CountWhites); Assert.AreEqual(2, m_board.CountBlacks); Assert.AreEqual(m_board.GetFieldValue(new Coords(4, 4)), m_board.GetFieldValue(new Coords(3, 3))); Assert.AreEqual(m_board.GetFieldValue(new Coords(3, 4)), m_board.GetFieldValue(new Coords(4, 3))); }