// // Agent constructor // public Agent() { behavior = null; LookAheadDepth = 0; Move = null; Color = 0; }
// Recursive method that utilizes the Minimax algorithm to help the player make the best move private ComputerMove Minimax(int player, Board board, int depth, int maxDepth) { ComputerMove bestMove = null; Board boardState = new Board(); for (int row = 0; row < 8; row++) { for (int col = 0; col < 8; col++) { if (board.IsValidMove(player, row, col)) { ComputerMove move = new ComputerMove(row, col); boardState.Copy(board); boardState.MakeMove(player, row, col); if (boardState.IsTerminalState() || depth == maxDepth) { move.rank = Evaluate(boardState); } else { move.rank = Minimax(GetNextPlayer(player, boardState), boardState, depth + 1, maxDepth).rank; } if (bestMove == null || betterMove(player, move.rank, bestMove.rank)) { bestMove = move; } } } } return(bestMove); }
public ComputerMove getMove() { Board board = GameObject.FindObjectOfType <Board>(); bestMove = new ComputerMove(board.mAllCells[11, 11], board.mAllCells[11, 11], board.mAllCells[11, 11].mCurrentPiece); minMax(4, -100000000, 1000000000, true); return(bestMove); }
// // Calculates a computer move. // Note: Executed in the worker thread. // private void CalculateComputerMove() { // Load the AI parameters. this.SetAIParameters(); // Find the best available move. ComputerMove move = this.GetBestMove(this.board); // Perform a callback to make the move. _resultMove = move; }
// // This function uses look ahead to evaluate all valid moves for a // given player color and returns the best move it can find. This // method will only be called if there is at least one valid move // for the player of the designated color. // private ComputerMove GetBestMove(int color, Board board, int depth) { //TODO: the lab ComputerMove m_bestMove = null; Board newState = new Board(); List <ComputerMove> Moves = new List <ComputerMove>(); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (board.IsValidMove(color, i, j)) { Moves.Add(new ComputerMove(i, j)); } } } for (int i = 0; i < Moves.Count; i++) { newState.Copy(board); newState.MakeMove(color, Moves[i].row, Moves[i].col); if (newState.IsTerminalState() || depth == 0) { Moves[i].rank = Evaluate(newState); } else { Moves[i].rank = GetBestMove(GetNextPlayer(color, newState), newState, depth - 1).rank; } //white if (color == 1) { if (m_bestMove == null || Moves[i].rank > m_bestMove.rank) { m_bestMove = Moves[i]; } } //black else { if (m_bestMove == null || Moves[i].rank < m_bestMove.rank) { m_bestMove = Moves[i]; } } } return(m_bestMove); }
private ComputerMove MinMax(int color, Board board, int lookAheadDepth, int alpha, int beta) { ComputerMove bestMove = null; Board newState = new Board(); List <ComputerMove> moves = new List <ComputerMove>(); for (int row = 0; row < Board.Height; row++) { for (int col = 0; col < Board.Width; col++) { if (board.IsValidMove(color, row, col)) { moves.Add(new ComputerMove(row, col)); } } } foreach (ComputerMove move in moves) { newState.Copy(board); newState.MakeMove(color, move.row, move.column); if (newState.IsTerminalState() || lookAheadDepth == 0) { move.rank = Evaluate(newState); } else { move.rank = MinMax((newState.HasAnyValidMove(color * -1) ? color * -1 : color), newState, lookAheadDepth - 1, alpha, beta).rank; } if (bestMove == null || move.rank * color > bestMove.rank * color) { bestMove = move; if (color == 1 && bestMove.rank > alpha) { alpha = bestMove.rank; } else if (color == -1 && bestMove.rank < beta) { beta = bestMove.rank; } if (alpha >= beta) { break; } } } return(bestMove); }
// // This function will determine a move based on the behavior supplied // to this agent. This function returns null on failure. // public ComputerMove DetermineMove(Board _board) { // Run the behavior to determine a move. On failure, returns null. Move = null; if (behavior != null) { Move = behavior.Run(Color, _board, LookAheadDepth); } if (Move != null && _board.IsValidMove(Color, Move.row, Move.column)) { return(Move); } throw new System.NotImplementedException("Behavior returned null or invalid move due to incorrect implementation"); }
void undoFakeMove(ComputerMove tempMove) { Cell movedTo = tempMove.secondPosition; Cell movedFrom = tempMove.firstPosition; BasePiece pieceKilled = tempMove.pieceKilled; BasePiece pieceMoved = tempMove.pieceMoved; movedFrom.mCurrentPiece = movedTo.mCurrentPiece; if (pieceKilled != null) { movedTo.mCurrentPiece = pieceKilled; } else { movedTo.mCurrentPiece = null; } }
//////////////////////////////////////// /* * Min-Max Algorithm */ //////////////////////////////////////// private ComputerMove GetBestMove(int color, Board board, int depth) { ComputerMove bestMove = null; Board newBoard = new Board(); List <ComputerMove> moveslist = new List <ComputerMove>(); for (int i = 0; i < Board.Height; ++i) { for (int j = 0; j < Board.Width; ++j) { if (board.IsValidMove(color, i, j)) { moveslist.Add(new ComputerMove(i, j)); } } } for (int i = 0; i < moveslist.Count; ++i) { newBoard.Copy(board); newBoard.MakeMove(color, moveslist[i].row, moveslist[i].col); if (newBoard.IsTerminalState() || depth == 0) { moveslist[i].rank = Evaluate(newBoard); } else if (!newBoard.HasAnyValidMove(-color)) { moveslist[i].rank = GetBestMove(color, newBoard, depth - 1).rank; } else { moveslist[i].rank = GetBestMove(-color, newBoard, depth - 1).rank; } if (bestMove == null || (color == Board.Black && moveslist[i].rank > bestMove.rank) || (color == Board.White && moveslist[i].rank < bestMove.rank)) { bestMove = moveslist[i]; } } return(bestMove); }
public void ComputerChooseCell(bool i_IsFirstChoose) { int randCell = m_Rand.Next(0, m_UnDiscoveredCells.Count); int choosenRow = m_UnDiscoveredCells[randCell] / m_BoardGame.NumOfCols; int chooseCol = m_UnDiscoveredCells[randCell] % m_BoardGame.NumOfCols; int convertToUnDiscoveredCellIndex; Point choose = new Point(choosenRow, chooseCol); if (i_IsFirstChoose) { m_FirstChoose = choose; convertToUnDiscoveredCellIndex = (choosenRow * m_BoardGame.NumOfCols) + chooseCol; m_UnDiscoveredCells.Remove(convertToUnDiscoveredCellIndex); } else { m_SecondChoose = choose; } ComputerMove.Invoke(choose); //m_BoardGame.MakeCellUnAvailable(choosenRow, chooseCol); }
public void ComputerMove(ComputerMove move) { // Get random cell //int i = UnityEngine.Random.Range(0, mHighlightedCells.Count); mTargetCell = move.secondPosition; // Move to new cell Move(); // End turn if (!turnExtra && !this.extraMovement) { mPieceManager.SwitchSides(mColor); } if (this.extraMovement) { extraMovement = false; } if (turnExtra) { turnExtra = false; } }
// // This function starts the look ahead process to find the best move // for this player color. // public ComputerMove Run(int _nextColor, Board _board, int _lookAheadDepth) { ComputerMove nextMove = GetBestMove(_nextColor, _board, _lookAheadDepth); return(nextMove); }
// TODO: Methods go here public ComputerMove Run(int color, Board board, int lookAheadDepth) { //throw new System.NotImplementedException(); ComputerMove bestMove = null; //row, column, rank //int bestRank = -2147483648; int bestRank = 0; if (color == -1) { bestRank = int.MaxValue; } else { bestRank = int.MinValue; } int bestRow = 0; int bestCol = 0; List <ComputerMove> MoveList = new List <ComputerMove>(); Board newState = new Board(); newState.Copy(board); for (int row = 0; row < 8; row++) { for (int col = 0; col < 8; col++) { if (newState.IsValidMove(color, row, col)) { MoveList.Add(new ComputerMove(row, col)); } } } foreach (ComputerMove cm in MoveList) { newState.Copy(board); newState.MakeMove(color, cm.row, cm.column); if (newState.IsTerminalState() || lookAheadDepth == 0) { cm.rank = Evaluate(newState); } else { if (newState.HasAnyValidMove(color * -1)) { cm.rank = Run(color * -1, newState, (lookAheadDepth - 1)).rank; } else { cm.rank = Run(color, newState, (lookAheadDepth - 1)).rank; } } if (color == -1) { if (bestRank > cm.rank) { bestRank = cm.rank; bestRow = cm.row; bestCol = cm.column; } } else { if (bestRank < cm.rank) { bestRank = cm.rank; bestRow = cm.row; bestCol = cm.column; } } } bestMove = new ComputerMove(bestRow, bestCol); bestMove.rank = bestRank; return(bestMove); }
// // This function uses look ahead to evaluate all valid moves for a // given player color and returns the best move it can find. // private ComputerMove GetBestMove(Board board, int color, int depth, int alpha, int beta) { // Initialize the best move. ComputerMove bestMove = new ComputerMove(-1, -1); bestMove.rank = -color * ReversiForm.maxRank; // Find out how many valid moves we have so we can initialize the // mobility score. int validMoves = board.GetValidMoveCount(color); // Start at a random position on the board. This way, if two or // more moves are equally good, we'll take one of them at random. Random random = new Random(); int rowStart = random.Next(8); int colStart = random.Next(8); // Check all valid moves. int i, j; for (i = 0; i < 8; i++) for (j = 0; j < 8; j++) { // Get the row and column. int row = (rowStart + i) % 8; int col = (colStart + j) % 8; if (board.IsValidMove(color, row, col)) { // Update the progress bar for each move when on the // first look ahead depth level. if (depth == 1) this.BeginInvoke(new UpdateStatusProgressDelegate(this.UpdateStatusProgress)); // Make the move. ComputerMove testMove = new ComputerMove(row, col); Board testBoard = new Board(board); testBoard.MakeMove(color, testMove.row, testMove.col); int score = testBoard.WhiteCount - testBoard.BlackCount; // Check the board. int nextColor = -color; int forfeit = 0; bool isEndGame = false; int opponentValidMoves = testBoard.GetValidMoveCount(nextColor); if (opponentValidMoves == 0) { // The opponent cannot move, count the forfeit. forfeit = color; // Switch back to the original color. nextColor = -nextColor; // If that player cannot make a move either, the // game is over. if (!testBoard.HasAnyValidMove(nextColor)) isEndGame = true; } // If we reached the end of the look ahead (end game or // max depth), evaluate the board and set the move // rank. if (isEndGame || depth == this.lookAheadDepth) { // For an end game, max the ranking and add on the // final score. if (isEndGame) { // Negative value for black win. if (score < 0) testMove.rank = -ReversiForm.maxRank + score; // Positive value for white win. else if (score > 0) testMove.rank = ReversiForm.maxRank + score; // Zero for a draw. else testMove.rank = 0; } // It's not an end game so calculate the move rank. else testMove.rank = this.forfeitWeight * forfeit + this.frontierWeight * (testBoard.BlackFrontierCount - testBoard.WhiteFrontierCount) + this.mobilityWeight * color * (validMoves - opponentValidMoves) + this.stabilityWeight * (testBoard.WhiteSafeCount - testBoard.BlackSafeCount) + score; } // Otherwise, perform a look ahead. else { ComputerMove nextMove = this.GetBestMove(testBoard, nextColor, depth + 1, alpha, beta); // Pull up the rank. testMove.rank = nextMove.rank; // Forfeits are cumulative, so if the move did not // result in an end game, add any current forfeit // value to the rank. if (forfeit != 0 && Math.Abs(testMove.rank) < ReversiForm.maxRank) testMove.rank += forfeitWeight * forfeit; // Adjust the alpha and beta values, if necessary. if (color == Board.White && testMove.rank > beta) beta = testMove.rank; if (color == Board.Black && testMove.rank < alpha) alpha = testMove.rank; } // Perform a cutoff if the rank is outside tha alpha-beta range. if (color == Board.White && testMove.rank > alpha) { testMove.rank = alpha; return testMove; } if (color == Board.Black && testMove.rank < beta) { testMove.rank = beta; return testMove; } // If this is the first move tested, assume it is the // best for now. if (bestMove.row < 0) bestMove = testMove; // Otherwise, compare the test move to the current // best move and take the one that is better for this // color. else if (color * testMove.rank > color * bestMove.rank) bestMove = testMove; } } // Return the best move found. return bestMove; }
public void moveComputerPiece(ComputerMove move) { move.pieceMoved.ComputerMove(move); }
// // This function uses look ahead to evaluate all valid moves for a // given player color and returns the best move it can find. // private ComputerMove minimax(Board board, int color, int alpha, int beta, int depth = 1) { // Initialize the best move. ComputerMove bestMove = new ComputerMove(-1, -1); bestMove.rank = -color * int.MaxValue; // Start at a random position on the board. This way, if two or // more moves are equally good, we'll take one of them at random. Random random = new Random(); int rowStart = random.Next(10); int colStart = random.Next(10); // Check every square on the board and try to perform // each and every move (up to the given depth) // to calculate best move for the current player. // We are certain that there are valid moves at this point // as we wouldn't be here if there weren't any // checks are performed in the StartTurn function. for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) { // Get the row and column. int row = (rowStart + i) % 10; int col = (colStart + j) % 10; if (board.IsValidMove(color, row, col)) { // We found a valid move now we copy the board // and try to make that move on the new board // to evaluate its weight. Board tempBoard = new Board(board); tempBoard.MakeMove(color, row, col); // Holds the current move being tested. ComputerMove moveBeingChecked = new ComputerMove(row, col); // Holds the color ID of a player that has no mobility // Initialized to 0 in case both are mobile. int forfeit = 0; // Holds the color ID of the next player. int nextPlayer = -color; // A flag that indicates whether either of // the players is mobile or if game is over. bool gameOver = false; // Just like in StartTurn, after passing a turn // to the next player due to no mobility for the other // we need to check if the new player is mobile // if not then neither can move and game is over. int opponentMobility = tempBoard.GetValidMoveCount(nextPlayer); if (opponentMobility == 0) { forfeit = nextPlayer; nextPlayer = color; if (!tempBoard.HasAnyValidMove(color)) gameOver = true; } if (depth >= lookAheadDepth || gameOver) { // Initialize AI Parameters. if (this.currentColor == Board.White) { moveBeingChecked.rank = heuristicFunction1(tempBoard, forfeit, color, opponentMobility); if (tempBoard.EmptyCount > 0 && Board.isCorner(row, col)) moveBeingChecked.rank += 200; } else moveBeingChecked.rank = heuristicFunction2(tempBoard); } else { ComputerMove nextMove = minimax(tempBoard, nextPlayer, alpha, beta, ++depth); moveBeingChecked.rank = nextMove.rank; // Adjust the alpha and beta values, if necessary. if (color == Board.White && moveBeingChecked.rank > beta) beta = moveBeingChecked.rank; if (color == Board.Black && moveBeingChecked.rank < alpha) alpha = moveBeingChecked.rank; } // If the alpha-beta pruning is enabled // perform a cut off if necessary. if (alphaBeta) { if (color == Board.White && moveBeingChecked.rank > alpha) { moveBeingChecked.rank = alpha; return moveBeingChecked; } if (color == Board.Black && moveBeingChecked.rank < beta) { moveBeingChecked.rank = beta; return moveBeingChecked; } } // If this is the first move tested, assume it is the // best for now. otherwise, compare the test move // to the current best move and take the one that // is better for this color. if (bestMove.row < 0) bestMove = moveBeingChecked; else if (color * moveBeingChecked.rank < color * bestMove.rank) bestMove = moveBeingChecked; } } // Return the best move found. return bestMove; }
int minMax(int depth, int option1, int option2, bool max) { if (depth == 0) { return(evaluation()); } if (max) { int score = -10000000; List <ComputerMove> allMoves = getComputerMoves(new Color32(25, 25, 25, 255)); foreach (ComputerMove move in allMoves) { moveStack.Push(move); fakeMove(move.firstPosition, move.secondPosition); score = minMax(depth - 1, option1, option2, false); undoFakeMove(move); if (score > option1) { move.score = score; if (move.score > bestMove.score && depth == 4) { bestMove = move; } option1 = score; } if (score >= option2) { break; } } return(option1); } else { int score = 10000000; List <ComputerMove> allMoves = getComputerMoves(new Color32(247, 242, 220, 255)); foreach (ComputerMove move in allMoves) { moveStack.Push(move); fakeMove(move.firstPosition, move.secondPosition); score = minMax(depth - 1, option1, option2, true); undoFakeMove(move); if (score < option2) { move.score = score; option2 = score; } if (score <= option1) { break; } } return(option2); } }
// // This function uses look ahead to evaluate all valid moves for a // given player color and returns the best move it can find. // private ComputerMove GetBestMove(Board board, int color, int depth, int alpha, int beta) { // Initialize the best move. ComputerMove bestMove = new ComputerMove(-1, -1); bestMove.rank = -color * maxRank; // Find out how many valid moves we have so we can initialize the // mobility score. int validMoves = board.GetValidMoveCount(color); // Start at a random position on the board. This way, if two or // more moves are equally good, we'll take one of them at random. Random random = new Random(); int rowStart = random.Next(8); int colStart = random.Next(8); // Check all valid moves. int i, j; for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { // Get the row and column. int row = (rowStart + i) % 8; int col = (colStart + j) % 8; if (board.IsValidMove(color, row, col)) { // Make the move. ComputerMove testMove = new ComputerMove(row, col); Board testBoard = new Board(board); testBoard.MakeMove(color, testMove.row, testMove.col); int score = testBoard.WhiteCount - testBoard.BlackCount; // Check the board. int nextColor = -color; int forfeit = 0; bool isEndGame = false; int opponentValidMoves = testBoard.GetValidMoveCount(nextColor); if (opponentValidMoves == 0) { // The opponent cannot move, count the forfeit. forfeit = color; // Switch back to the original color. nextColor = -nextColor; // If that player cannot make a move either, the // game is over. if (!testBoard.HasAnyValidMove(nextColor)) { isEndGame = true; } } // If we reached the end of the look ahead (end game or // max depth), evaluate the board and set the move // rank. if (isEndGame || depth == this.lookAheadDepth) { // For an end game, max the ranking and add on the // final score. if (isEndGame) { // Negative value for black win. if (score < 0) { testMove.rank = -maxRank + score; } // Positive value for white win. else if (score > 0) { testMove.rank = maxRank + score; } // Zero for a draw. else { testMove.rank = 0; } } // It's not an end game so calculate the move rank. else { testMove.rank = this.forfeitWeight * forfeit + this.frontierWeight * (testBoard.BlackFrontierCount - testBoard.WhiteFrontierCount) + this.mobilityWeight * color * (validMoves - opponentValidMoves) + this.stabilityWeight * (testBoard.WhiteSafeCount - testBoard.BlackSafeCount) + score; } } // Otherwise, perform a look ahead. else { ComputerMove nextMove = this.GetBestMove(testBoard, nextColor, depth + 1, alpha, beta); // Pull up the rank. testMove.rank = nextMove.rank; // Forfeits are cumulative, so if the move did not // result in an end game, add any current forfeit // value to the rank. if (forfeit != 0 && Math.Abs(testMove.rank) < maxRank) { testMove.rank += forfeitWeight * forfeit; } // Adjust the alpha and beta values, if necessary. if (color == Board.White && testMove.rank > beta) { beta = testMove.rank; } if (color == Board.Black && testMove.rank < alpha) { alpha = testMove.rank; } } // Perform a cutoff if the rank is outside tha alpha-beta range. if (color == Board.White && testMove.rank > alpha) { testMove.rank = alpha; return(testMove); } if (color == Board.Black && testMove.rank < beta) { testMove.rank = beta; return(testMove); } // If this is the first move tested, assume it is the // best for now. if (bestMove.row < 0) { bestMove = testMove; } // Otherwise, compare the test move to the current // best move and take the one that is better for this // color. else if (color * testMove.rank > color * bestMove.rank) { bestMove = testMove; } } } } // Return the best move found. return(bestMove); }
// // This function uses look ahead to evaluate all valid moves for a // given player color and returns the best move it can find. This // method will only be called if there is at least one valid move // for the player of the designated color. // private ComputerMove GetBestMove(int color, Board board, int depth) { //TODO: the lab List <ComputerMove> Moves = new List <ComputerMove>(); ComputerMove bestMove = null; Board newState = new Board(); // generate valid Moves for player; for (int r = 0; r < Board.Height; r++) { for (int c = 0; c < Board.Width; c++) { if (board.IsValidMove(color, r, c) == true) { ComputerMove move = new ComputerMove(r, c); Moves.Add(move); } } } foreach (ComputerMove move in Moves) { newState.Copy(board); newState.MakeMove(color, move.row, move.col); if (newState.IsTerminalState() || depth == 0) { move.rank = Evaluate(newState); /*ExampleAI.MinimaxAFI.EvaluateTest(newState);*/ } else { if (newState.HasAnyValidMove(color * -1)) { move.rank = GetBestMove(color * -1, newState, depth - 1).rank; } else { move.rank = GetBestMove(color, newState, depth - 1).rank; } } if (color == 1) { if (bestMove == null || move.rank > bestMove.rank) { bestMove = move; } } else { if (bestMove == null || move.rank < bestMove.rank) { bestMove = move; } } } return(bestMove); throw new NotImplementedException(); }