Beispiel #1
0
        private static void Main(string[] args)
        {
            Board b = new Board();

            while (true)
            {
                bool playing = true;
                b.SetForNewGame();
                bool isWhite = true;
                while (playing)
                {
                    isWhite = !isWhite;
                    Board.Color player = isWhite ? Board.Color.White : Board.Color.Black;
                    Console.Clear();
                    Console.Write(" ");
                    for (int i = 0; i < 8; i++)
                    {
                        Console.Write($" {i + 1}");
                    }
                    Console.Write(" X");
                    Console.WriteLine();
                    for (int y = 0; y < 8; y++)
                    {
                        for (int x = 0; x < 8; x++)
                        {
                            Console.Write(x == 0 ? $"{y + 1} " : " ");
                            Console.ForegroundColor =
                                b.IsValidMove(player, y, x) ? ConsoleColor.Green : ConsoleColor.Red;
                            Console.Write(GetChar(b.GetSquareContents(y, x)));
                        }
                        Console.ResetColor();
                        Console.WriteLine();
                    }
                    Console.WriteLine("Y");
                    if (!b.HasAnyValidMove(player))
                    {
                        if (!b.HasAnyValidMove(Board.Invert(player)))
                        {
                            Console.WriteLine(b.WhiteCount == b.BlackCount
                                ? "Tie"
                                : $"{(b.WhiteCount > b.BlackCount ? "White" : "Black")} won");
                            Console.ReadKey();
                            playing = false;
                        }
                        continue;
                    }
                    Console.WriteLine($"Current player: {(isWhite ? "White (+)" : "Black (-)")}");
                    Console.WriteLine($"{b.GetValidMoveCount(player)} moves possible");
                    int  nX;
                    int  nY;
                    bool first = true;
                    do
                    {
                        if (!first)
                        {
                            Console.WriteLine("Invalid move");
                        }
                        first = false;
                        Console.Write("x> ");
                        nX = int.Parse(Console.ReadKey().KeyChar.ToString()) - 1;
                        Console.WriteLine();
                        Console.Write("y> ");
                        nY = int.Parse(Console.ReadKey().KeyChar.ToString()) - 1;
                        Console.WriteLine();
                    } while (!b.IsValidMove(player, nY, nX));
                    b.MakeMove(player, nY, nX);
                }
            }
        }
Beispiel #2
0
        //
        // 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;
        }
Beispiel #3
0
        //
        // 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;
        }
Beispiel #4
0
        int heuristicFunction1(Board newBoard, int forfeit, int color, int opponentMobility)
        {
            SetAIParameters();

            return
                this.forfeitWeight * forfeit +
                this.frontierWeight * (newBoard.WhiteFrontierCount - newBoard.BlackFrontierCount) +
                this.mobilityWeight * color * (newBoard.GetValidMoveCount(color) - newBoard.GetValidMoveCount(-color)) +
                this.stabilityWeight * (newBoard.WhiteSafeCount - newBoard.BlackSafeCount) +
                this.stonesWeight * (newBoard.WhiteCount - newBoard.BlackCount);
        }