// Make an automatic move
        private void DoAutoPlay()
        {
            // Player to play
            IPlayer player = Turn == CellState.X ? PlayerX : PlayerO;

            // Log, to be optionally filled by the AI players
            string log = "";

            // Keep start time
            DateTime startTime = DateTime.Now;

            // Ask player for a move
            Pos pos = player.Play(gameBoard, ref log);

            // Print log, including how much time it took
            Debug.LogFormat("{0} took {1} ms\n{2}",
                            player.GetType().Name,
                            (DateTime.Now - startTime).TotalMilliseconds,
                            log);

            // Is this an invalid move?
            if (gameBoard.GetStateAt(pos) != CellState.Undecided)
            {
                overrideWinner = Turn.Other();
                return;
            }

            // Perform the actual move
            Move(pos);
        }
        // Get board score for the specified player, ignoring the other player
        private float ScoreFor(Board board, CellState player)
        {
            // Current score
            float score = 0;

            // Search all corridors in the board
            foreach (Pos[] corridor in Board.winCorridors)
            {
                // By default we assume a line is available
                bool lineAvailable = true;

                // Cycle through all the positions in the current corridor
                foreach (Pos position in corridor)
                {
                    // Check if there's an opponent piece at this position
                    if (board.GetStateAt(position) == player.Other())
                    {
                        // If so, it means there's no line available here, so
                        // let's take a note of that and skip the rest of the line
                        lineAvailable = false;
                        break;
                    }
                }

                // Was the previous line available for our player?
                if (lineAvailable)
                {
                    // If so, increment score
                    score++;
                }
            }

            // Return the score
            return(score);
        }
Beispiel #3
0
        public Pos Play(Board gameBoard, ref string log)
        {
            // Populate a list with available board positions
            IList <Pos> emptyPositions = new List <Pos>();

            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    Pos pos = new Pos(i, j);
                    if (gameBoard.GetStateAt(pos) == CellState.Undecided)
                    {
                        emptyPositions.Add(pos);
                    }
                }
            }

            // Return a random empty board position
            return(emptyPositions[random.Next(emptyPositions.Count)]);
        }
        // Helper method which obtains valid moves for the given board
        private static IList <Pos> ValidMovesFromBoard(Board board)
        {
            // List of valid moves
            List <Pos> validMoves = new List <Pos>();

            // Search for valid moves
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    // Is current position a valid move?
                    Pos move = new Pos(i, j);
                    if (board.GetStateAt(move) == CellState.Undecided)
                    {
                        // If so, add it to list of valid moves
                        validMoves.Add(move);
                    }
                }
            }
            return(validMoves);
        }
Beispiel #5
0
        // 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);
            }
        }