Example #1
0
        /// <summary>
        /// Generates a random, unpredictable move.
        /// </summary>
        /// <returns>Returns a move structure with defined X, Y coordinates.</returns>
        private Move GenerateMediumDifficultyMove()
        {
            bool isValidMoveFound     = false;
            Move mediumDifficultyMove = new Move();

            while (!isValidMoveFound)
            {
                // Generate random coordinates
                mediumDifficultyMove.X = RandomGenerator.Next(0, Tictactoe.GetBoardHorizontalSize());
                mediumDifficultyMove.Y = RandomGenerator.Next(0, Tictactoe.GetBoardVerticalSize());

                // Check if the field is empty
                if (IsBoardFieldEmpty(Board, mediumDifficultyMove.X, mediumDifficultyMove.Y))
                {
                    isValidMoveFound = true;
                }
            }

            return(mediumDifficultyMove);
        }
Example #2
0
        /// <summary>
        /// Generates the best move available using the negamax algorithm.
        /// </summary>
        /// <param name="board">Board on which to do the calculations.</param>
        /// <param name="playerMark">Mark of the player who is calling the function.</param>
        /// <returns>An optimal move for the given board and player.</returns>
        /// Can be upgraded with alpha-beta pruning to increase performance.
        private Move GenerateImpossibleDifficultyMove(string[,] board, string playerMark)
        {
            // Set the oponent players mark
            string oponentPlayerMark = (playerMark == Resources.BoardCrossMark) ? Resources.BoardCircleMark : Resources.BoardCrossMark;

            // Check if the player calling the function has won
            if (Tictactoe.HasPlayerWon(board, playerMark))
            {
                return(new Move()
                {
                    Value = 1
                });
            }

            // Check if the player calling the function has lost
            if (Tictactoe.HasPlayerWon(board, oponentPlayerMark))
            {
                return(new Move()
                {
                    Value = -1
                });
            }

            // Check for a draw
            if (Tictactoe.HavePlayersDraw(board))
            {
                return(new Move()
                {
                    Value = 0
                });
            }

            // Set initial bestMove value to -2 because thats lower than the lowest possible value you can generate for a valid move from this implementation (which is -1)
            var bestMove = new Move()
            {
                Value = -2
            };

            // Loop through the board
            for (int i = 0; i < Tictactoe.GetBoardHorizontalSize(); i++)
            {
                for (int j = 0; j < Tictactoe.GetBoardVerticalSize(); j++)
                {
                    if (IsBoardFieldEmpty(board, i, j))
                    {
                        // Mark the board field
                        board[i, j] = playerMark;

                        // Assign a new value to the opposite of a recursive function call
                        int value = -GenerateImpossibleDifficultyMove(board, oponentPlayerMark).Value;

                        // Store move information if it has better value than the current best move
                        if (value > bestMove.Value)
                        {
                            bestMove.Value = value;
                            bestMove.X     = i;
                            bestMove.Y     = j;
                        }

                        // Change the board field back to empty
                        board[i, j] = Resources.BoardEmptyField;
                    }
                }
            }

            return(bestMove);
        }