Ejemplo n.º 1
0
 public Board Move(BoardSpace move)
 {
     if (PlayerToMove == Player.X)
     {
         MoveX(move);
         PlayerToMove = Player.O;
     }
     else
     {
         MoveO(move);
         PlayerToMove = Player.X;
     }
     LastMove = move;
     return(this);
 }
Ejemplo n.º 2
0
        // ask user for next opponent move
        private static BoardSpace GetOpponentMove()
        {
            Console.WriteLine("Enter opponent move (row col):");

            BoardSpace move = null;

            while (move == null)
            {
                try
                {
                    move = new BoardSpace(Console.ReadLine());
                }
                catch
                {
                    Console.WriteLine("Error reading move, use the format (row col):");
                }
            }

            return(move);
        }
Ejemplo n.º 3
0
        private static IEnumerable <BoardSpace> GetSurroundingSpaces(BoardSpace space)
        {
            var higherRow = (byte)(space.Row + 1);
            var lowerRow  = (byte)(space.Row - 1);
            var higherCol = (byte)(space.Col + 1);
            var lowerCol  = (byte)(space.Col - 1);

            if (space.Row > 0)
            {
                yield return(new BoardSpace(lowerRow, space.Col));

                if (space.Col > 0)
                {
                    yield return(new BoardSpace(lowerRow, lowerCol));

                    yield return(new BoardSpace(space.Row, lowerCol));
                }
                if (space.Col < 7)
                {
                    yield return(new BoardSpace(lowerRow, higherCol));

                    yield return(new BoardSpace(space.Row, higherCol));
                }
            }
            if (space.Row < 7)
            {
                yield return(new BoardSpace(higherRow, space.Col));

                if (space.Col > 0)
                {
                    yield return(new BoardSpace(higherRow, lowerCol));
                }
                if (space.Col < 7)
                {
                    yield return(new BoardSpace(higherRow, higherCol));
                }
            }
        }
Ejemplo n.º 4
0
 public BestMoveResultWithStats(int score, BoardSpace bestMove)
 {
     Move  = bestMove;
     Score = score;
     NodesGeneratedByDepth = new Dictionary <int, int>();
 }
Ejemplo n.º 5
0
 public BestMoveResult(int score, BoardSpace bestMove)
 {
     Move  = bestMove;
     Score = score;
 }
Ejemplo n.º 6
0
        // recursive alpha beta
        private BestMoveResultWithStats BestMoveInternal(Board board, int depth, int alpha, int beta, CancellationToken cancelToken)
        {
            // if we reached the bottom, return
            if (depth == 0)
            {
                _numNodesAtDepthLimit++;
                return(new BestMoveResultWithStats(_config.Heuristic.Evaluate(board), null));
            }

            var isMaxTurn = board.MyPlayer == board.PlayerToMove;

            var validMoves = board.GetValidMoves();

            // if we hit game over before the depth limit, return infinity/-infinity if it's our/their turn
            if (!validMoves.Any())
            {
                return(new BestMoveResultWithStats(isMaxTurn ? int.MinValue : int.MaxValue, null));
            }

            BoardSpace bestMove = null;

            // generate new boards for each move and evaluate them so we can sort
            var validMovesWithBoard = validMoves.Select(x =>
            {
                var newBoard = board.Copy().Move(x);
                _nodesGeneratedByDepth[depth]++;
                var score = _config.Heuristic.Evaluate(newBoard);
                return(new { move = x, newBoard, score });
            });

            // if we're maxing, sort with largest first, otherwise sort with smallest first
            if (isMaxTurn)
            {
                validMovesWithBoard = validMovesWithBoard.OrderByDescending(x => x.score);
            }
            else
            {
                validMovesWithBoard = validMovesWithBoard.OrderBy(x => x.score);
            }

            // evaluate this board because we'll need to for quiessence search
            var boardScore = _config.Heuristic.Evaluate(board);

            foreach (var move in validMovesWithBoard)
            {
                BestMoveResultWithStats childResult;

                // if we're doing a quiessence search, check to see if heuristic score change is interesting
                if (IsInterestingMove(boardScore, move.score))
                {
                    // extend search depth because this move looks interesting
                    _numNodesQuiessenceSearched++;
                    childResult = BestMoveInternal(move.newBoard, depth, alpha, beta, cancelToken);
                }
                else
                {
                    // normal evaluation
                    childResult = BestMoveInternal(move.newBoard, depth - 1, alpha, beta, cancelToken);
                }

                // if we're near timeout or asked to cancel, just bail :(
                if (_timer.Timeout() || cancelToken.IsCancellationRequested)
                {
                    _timedOut = true;
                    break;
                }

                if (isMaxTurn) // if it's a max turn, we want to check alpha
                {
                    if (childResult.Score > alpha)
                    {
                        alpha    = childResult.Score;
                        bestMove = move.move;
                    }
                }
                else // else it's a min turn, so we want to check beta
                {
                    if (childResult.Score < beta)
                    {
                        beta     = childResult.Score;
                        bestMove = move.move;
                    }
                }

                // alpha-beta trim
                if (alpha >= beta)
                {
                    break;
                }
            }

            // if we didn't find anything good, just return the first one
            if (bestMove == null)
            {
                bestMove = validMoves.First();
            }

            return(new BestMoveResultWithStats(isMaxTurn ? alpha : beta, bestMove));
        }
Ejemplo n.º 7
0
        public IEnumerable <BoardSpace> GetMoves(BoardSpace currentPosition)
        {
            #region vertical moves

            // walk down from currentPosition
            for (var i = currentPosition.Row + 1; i < 8; i++)
            {
                if (_board[i][currentPosition.Col] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace((byte)i, currentPosition.Col));
                }
                else
                {
                    break;
                }
            }

            // walk up from currentPosition
            for (var i = currentPosition.Row - 1; i >= 0; i--)
            {
                if (_board[i][currentPosition.Col] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace((byte)i, currentPosition.Col));
                }
                else
                {
                    break;
                }
            }

            #endregion

            #region horizontal moves

            // walk right from currentPosition
            for (var j = currentPosition.Col + 1; j < 8; j++)
            {
                if (_board[currentPosition.Row][j] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace(currentPosition.Row, (byte)j));
                }
                else
                {
                    break;
                }
            }

            // walk left from currentPosition
            for (var j = currentPosition.Col - 1; j >= 0; j--)
            {
                if (_board[currentPosition.Row][j] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace(currentPosition.Row, (byte)j));
                }
                else
                {
                    break;
                }
            }

            #endregion

            #region diagonal moves

            // walk down-right from currentPosition
            for (int i = currentPosition.Row + 1, j = currentPosition.Col + 1; i < 8 && j < 8; i++, j++)
            {
                if (_board[i][j] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace((byte)i, (byte)j));
                }
                else
                {
                    break;
                }
            }

            // walk down-left from currentPosition
            for (int i = currentPosition.Row + 1, j = currentPosition.Col - 1; i < 8 && j >= 0; i++, j--)
            {
                if (_board[i][j] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace((byte)i, (byte)j));
                }
                else
                {
                    break;
                }
            }

            // walk up-right from currentPosition
            for (int i = currentPosition.Row - 1, j = currentPosition.Col + 1; i >= 0 && j < 8; i--, j++)
            {
                if (_board[i][j] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace((byte)i, (byte)j));
                }
                else
                {
                    break;
                }
            }

            // walk up-left from currentPosition
            for (int i = currentPosition.Row - 1, j = currentPosition.Col - 1; i >= 0 && j >= 0; i--, j--)
            {
                if (_board[i][j] == BoardSpaceValue.Empty)
                {
                    yield return(new BoardSpace((byte)i, (byte)j));
                }
                else
                {
                    break;
                }
            }

            #endregion
        }
Ejemplo n.º 8
0
 public void MoveO(BoardSpace move)
 {
     _board[Oposition.Row][Oposition.Col] = BoardSpaceValue.Filled;
     _board[move.Row][move.Col]           = BoardSpaceValue.PlayerO;
     Oposition = move;
 }
Ejemplo n.º 9
0
 public void MoveX(BoardSpace move)
 {
     _board[Xposition.Row][Xposition.Col] = BoardSpaceValue.Filled;
     _board[move.Row][move.Col]           = BoardSpaceValue.PlayerX;
     Xposition = move;
 }