// Implementation of hook method which performs the move on the actual // Tic Tac Toe game board protected override AbstractMCTSNode <Pos, CellState> DoMakeMove(Pos move) { // Get a copy of the game board Board boardCopy = board.Copy(); // Perform the move boardCopy.DoMove(move); // Return a new node representing the new state of the board return(new TicTacToeMCTSNode(boardCopy, move)); }
// Perform a playout / simulation using the given strategy public override CellState Playout(Func <IList <Pos>, Pos> strategy) { // Do the playout on a copy of the board Board boardCopy = board.Copy(); // Keep playing using the given strategy until an endgame is reached while (!boardCopy.Status().HasValue) { // Use the given strategy to obtain a move Pos move = strategy(ValidMovesFromBoard(boardCopy)); // Perform move boardCopy.DoMove(move); } return(boardCopy.Status().Value); }
// Perform a move public void Move(Pos pos) { gameBoard.DoMove(pos); }
// Process given board with ABNegamax private (float score, Pos move) Negamax(Board board, int depth) { // Increment number of evaluations (recursive ABNegamax calls) numEvals++; // Check what's the status of this board if (board.Status().HasValue) { // GAME OVER! Who won? if (board.Status().Value == CellState.Undecided) { // It's a tie, return 0 return(0, Board.NoMove); } else if (board.Status().Value == board.Turn) { // Current player wins, return max heuristic value return(heuristic.WinScore, Board.NoMove); } else { // The other player won, return min heuristic value return(-heuristic.WinScore, Board.NoMove); } } else if (depth == maxDepth) { // We reached the max depth, return the heuristic value for this // board return(heuristic.Evaluate(board, board.Turn), Board.NoMove); } else { // Game is not over and we haven't reached maximum depth, so let's // recursively call Negamax on all possible moves // Declare best move, which for now is no move at all (float score, Pos move)bestMove = (float.NegativeInfinity, Board.NoMove); // Try to play on all board positions for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // Get the current board position Pos pos = new Pos(i, j); // Only consider making a move at this position if it's // not already occupied if (board.GetStateAt(pos) == CellState.Undecided) { // Score for current move float score; // Make a virtual move at this position board.DoMove(pos); // Get score for this move score = -Negamax(board, depth + 1).score; // Undo the move we just evaluated board.UndoMove(); // Is this the best move so far? if (score > bestMove.score) { // If so, keep it bestMove = (score, pos); } } } } // Return the best move found among all the tested moves return(bestMove); } }