// returns the score for the current position from the point of view of the given player. public Move evaluate(moveBoard board, Move evalMove) { int boardScore = evalBoardForAI(); evalMove.Score = boardScore; return(evalMove); }
static Move getBestMove(GameBoard.PLAYERS_ID player) { //make a moveBoard of the current state of the board moveBoard currentMoveBoard = new moveBoard(); //this move board is used as a scratch pad to examine possible next moves currentMoveBoard.setCurrentGameBoardToMoveBoard(player); //using the moveboard the minimax function finds the next BEST move Move bestMove = miniMax(currentMoveBoard, currentMoveBoard.Root, player, MAX_DEPTH, 0); return(bestMove); }
// //This function implements the Minimax algorithm // //moveboard board --represents the current game board as a scratch pad to make moves on (before actually making the move) // --board also holds the actual player's turn for the game (first player in the tree) //Move nextMove --represents the next move to be made on the game board // --nexMove also holds a score value for the move //evaluatePlayer --represents the players turn on the tree ( it will change as we traverse each level of the tree ) // //maxDepth --represents the number of levels to use in the minimax algorithm (how far down the tree do we want to go?) // //currentDepth --represents the current level we are evaluating // //return --this function returns the best move to make on the board static public Move miniMax(moveBoard board, Move nextMove, GameBoard.PLAYERS_ID evaluatePlayer, int maxDepth, int currentDepth) { // //create a bestmove to return // Move bestMove = new Move(); // //if game is over ( no more moves left/win/loss ) || we have reached our max depth to search || there are no children for this move and it isnt the very first move // if (board.isGameOver() || currentDepth == maxDepth || ((currentDepth != 0) && nextMove.PossibleMoves.Count == 0)) { // //evaluate the board and return the best move for this board, the move data structure also holds a score value for the board // Move eMove = board.evaluate(board, nextMove); eMove.Depth = currentDepth; // //copy the evaluated move into bestMove // eMove.Copy(bestMove); } else { // //if we haven't reached a terminal node traverse the children and call minimax // Move currentBubbledUpScore = null; // //Initialize the bestmove object // nextMove.Copy(bestMove); bestMove.Score = INFINITY; // //Ask: whose turn is it on the tree? Keep track of the max or min score for all the possible moves (children) // if (board.CurrentPlayer == evaluatePlayer) { bestMove.Score = -INFINITY; } // //Loop through all the possible moves from nextMove // foreach (Move move in nextMove.PossibleMoves) { // //make the move ( take the turn ) and then call minimax for the next move //makeMove also adds the move to our move game board scratch pad // board.makeMove(move, evaluatePlayer); currentBubbledUpScore = miniMax(board, move, GetNextPlayerID(evaluatePlayer), maxDepth, currentDepth + 1); // //remove move from our game board (game board scratch pad) // board.RemoveMoveFromGameMoveBoard(move); // //if we are the current player, then take the highest score found of all the moves // if (board.CurrentPlayer == evaluatePlayer) { if (currentBubbledUpScore.Score > bestMove.Score) { bestMove.Row = move.Row; bestMove.Column = move.Column; bestMove.Score = currentBubbledUpScore.Score; bestMove.Depth = currentBubbledUpScore.Depth; } else if (currentBubbledUpScore.Score == bestMove.Score) { if (currentBubbledUpScore.Depth < bestMove.Depth) { bestMove.Row = move.Row; bestMove.Column = move.Column; bestMove.Score = currentBubbledUpScore.Score; bestMove.Depth = currentBubbledUpScore.Depth; } } } else { if (currentBubbledUpScore.Score < bestMove.Score) { bestMove.Row = move.Row; bestMove.Column = move.Column; bestMove.Score = currentBubbledUpScore.Score; bestMove.Depth = currentBubbledUpScore.Depth; } } // // the opponent is the current player then take the lowest score of all the moves // } } return(bestMove); }