コード例 #1
0
ファイル: Position.cs プロジェクト: PenguinF/sandra-three
        /// <summary>
        /// Generates and enumerates all non-castling moves which are legal in this position.
        /// </summary>
        public IEnumerable <MoveInfo> GenerateLegalMoves()
        {
            Debug.Assert(CheckInvariants());

            ulong sideToMoveVector    = colorVectors[SideToMove];
            ulong oppositeColorVector = colorVectors[SideToMove.Opposite()];
            ulong occupied            = sideToMoveVector | oppositeColorVector;

            foreach (var movingPiece in EnumHelper <Piece> .AllValues)
            {
                // Enumerate over all squares occupied by this piece.
                ulong coloredPieceVector = pieceVectors[movingPiece] & colorVectors[SideToMove];
                foreach (var sourceSquare in coloredPieceVector.AllSquares())
                {
                    // Initialize possible target squares of the moving piece.
                    ulong targetSquares = 0;
                    switch (movingPiece)
                    {
                    case Piece.Pawn:
                        ulong legalCaptureSquares = (oppositeColorVector | enPassantVector)
                                                    & Constants.PawnCaptures[SideToMove, sourceSquare];
                        ulong legalMoveToSquares = ~occupied
                                                   & Constants.PawnMoves[SideToMove, sourceSquare]
                                                   & Constants.ReachableSquaresStraight(sourceSquare, occupied);

                        targetSquares = legalCaptureSquares | legalMoveToSquares;
                        break;

                    case Piece.Knight:
                        targetSquares = Constants.KnightMoves[sourceSquare];
                        break;

                    case Piece.Bishop:
                        targetSquares = Constants.ReachableSquaresDiagonal(sourceSquare, occupied);
                        break;

                    case Piece.Rook:
                        targetSquares = Constants.ReachableSquaresStraight(sourceSquare, occupied);
                        break;

                    case Piece.Queen:
                        targetSquares = Constants.ReachableSquaresStraight(sourceSquare, occupied)
                                        | Constants.ReachableSquaresDiagonal(sourceSquare, occupied);
                        break;

                    case Piece.King:
                        targetSquares = Constants.Neighbours[sourceSquare];
                        break;
                    }

                    // Can never capture one's own pieces. This also filters out targetSquare == sourceSquare.
                    targetSquares &= ~sideToMoveVector;

                    foreach (var targetSquare in targetSquares.AllSquares())
                    {
                        // Reset/initialize move.
                        MoveInfo move = new MoveInfo();

                        ulong targetVector = targetSquare.ToVector();

                        // Since en passant doesn't capture a pawn on the target square, separate captureVector from targetVector.
                        bool  isCapture     = false;
                        Piece capturedPiece = default;
                        ulong captureVector;
                        if (movingPiece == Piece.Pawn && enPassantVector.Test(targetVector))
                        {
                            // Don't capture on the target square, but capture the pawn instead.
                            move.MoveType = MoveType.EnPassant;
                            captureVector = EnPassantCaptureVector;
                            capturedPiece = Piece.Pawn;
                            isCapture     = true;
                        }
                        else
                        {
                            // Find the possible piece on the target square.
                            captureVector = targetVector;
                            isCapture     = EnumHelper <Piece> .AllValues.Any(x => pieceVectors[x].Test(captureVector), out capturedPiece);
                        }

                        // Remove whatever was captured.
                        if (isCapture)
                        {
                            colorVectors[SideToMove.Opposite()] = colorVectors[SideToMove.Opposite()] ^ captureVector;
                            pieceVectors[capturedPiece]         = pieceVectors[capturedPiece] ^ captureVector;
                        }

                        // Move from source to target.
                        ulong moveDelta = sourceSquare.ToVector() | targetVector;
                        colorVectors[SideToMove]  = colorVectors[SideToMove] ^ moveDelta;
                        pieceVectors[movingPiece] = pieceVectors[movingPiece] ^ moveDelta;

                        // See if the friendly king is now under attack.
                        bool kingInCheck = IsSquareUnderAttack(FindKing(SideToMove), SideToMove);

                        // Move must be reversed before continuing.
                        colorVectors[SideToMove]  = colorVectors[SideToMove] ^ moveDelta;
                        pieceVectors[movingPiece] = pieceVectors[movingPiece] ^ moveDelta;
                        if (isCapture)
                        {
                            colorVectors[SideToMove.Opposite()] = colorVectors[SideToMove.Opposite()] ^ captureVector;
                            pieceVectors[capturedPiece]         = pieceVectors[capturedPiece] ^ captureVector;
                        }

                        if (!kingInCheck)
                        {
                            move.SourceSquare = sourceSquare;
                            move.TargetSquare = targetSquare;
                            if (movingPiece == Piece.Pawn && Constants.PromotionSquares.Test(targetVector))
                            {
                                move.MoveType  = MoveType.Promotion;
                                move.PromoteTo = Piece.Knight; yield return(move);

                                move.PromoteTo = Piece.Bishop; yield return(move);

                                move.PromoteTo = Piece.Rook; yield return(move);

                                move.PromoteTo = Piece.Queen; yield return(move);
                            }
                            else
                            {
                                yield return(move);
                            }
                        }
                    }
                }
            }

            Debug.Assert(CheckInvariants());
        }
コード例 #2
0
        private static MoveInfo GetMoveInfo(Game game, string moveText, Color sideToMove)
        {
            MoveInfo moveInfo = new MoveInfo();

            // Very free-style parsing, based on the assumption that this is a recognized move.
            if (moveText == "O-O")
            {
                moveInfo.MoveType = MoveType.CastleKingside;
                if (sideToMove == Color.White)
                {
                    moveInfo.SourceSquare = Square.E1;
                    moveInfo.TargetSquare = Square.G1;
                }
                else
                {
                    moveInfo.SourceSquare = Square.E8;
                    moveInfo.TargetSquare = Square.G8;
                }
            }
            else if (moveText == "O-O-O")
            {
                moveInfo.MoveType = MoveType.CastleQueenside;
                if (sideToMove == Color.White)
                {
                    moveInfo.SourceSquare = Square.E1;
                    moveInfo.TargetSquare = Square.C1;
                }
                else
                {
                    moveInfo.SourceSquare = Square.E8;
                    moveInfo.TargetSquare = Square.C8;
                }
            }
            else
            {
                // Piece, disambiguation, capturing 'x', target square, promotion, check/mate/nag.
                Piece movingPiece = Piece.Pawn;
                int   index       = 0;
                if (moveText[index] >= 'A' && moveText[index] <= 'Z')
                {
                    movingPiece = GetPiece(moveText[index]);
                    index++;
                }

                File? disambiguatingSourceFile = null;
                Rank? disambiguatingSourceRank = null;
                File? targetFile = null;
                Rank? targetRank = null;
                Piece?promoteTo  = null;

                while (index < moveText.Length)
                {
                    char currentChar = moveText[index];
                    if (currentChar == '=')
                    {
                        index++;
                        promoteTo = GetPiece(moveText[index]);
                        break;
                    }
                    else if (currentChar >= 'a' && currentChar <= 'h')
                    {
                        if (targetFile != null)
                        {
                            disambiguatingSourceFile = targetFile;
                        }
                        targetFile = (File)(currentChar - 'a');
                    }
                    else if (currentChar >= '1' && currentChar <= '8')
                    {
                        if (targetRank != null)
                        {
                            disambiguatingSourceRank = targetRank;
                        }
                        targetRank = (Rank)(currentChar - '1');
                    }

                    // Ignore 'x', '+', '#', '!', '?', increase index.
                    index++;
                }

                moveInfo.TargetSquare = ((File)targetFile).Combine((Rank)targetRank);

                // Get vector of pieces of the correct color that can move to the target square.
                ulong occupied = ~game.CurrentPosition.GetEmptyVector();
                ulong sourceSquareCandidates = game.CurrentPosition.GetVector(sideToMove) & game.CurrentPosition.GetVector(movingPiece);

                if (movingPiece == Piece.Pawn)
                {
                    // Capture or normal move?
                    if (disambiguatingSourceFile != null)
                    {
                        // Capture, go backwards by using the opposite side to move.
                        sourceSquareCandidates &= Constants.PawnCaptures[sideToMove.Opposite(), moveInfo.TargetSquare];

                        foreach (Square sourceSquareCandidate in sourceSquareCandidates.AllSquares())
                        {
                            if (disambiguatingSourceFile == (File)sourceSquareCandidate.X())
                            {
                                moveInfo.SourceSquare = sourceSquareCandidate;
                                break;
                            }
                        }

                        // En passant special move type, if the target capture square is empty.
                        if (!moveInfo.TargetSquare.ToVector().Test(occupied))
                        {
                            moveInfo.MoveType = MoveType.EnPassant;
                        }
                    }
                    else
                    {
                        // One or two squares backwards.
                        Func <ulong, ulong> direction;
                        if (sideToMove == Color.White)
                        {
                            direction = ChessExtensions.South;
                        }
                        else
                        {
                            direction = ChessExtensions.North;
                        }
                        ulong straightMoves = direction(moveInfo.TargetSquare.ToVector());
                        if (!straightMoves.Test(occupied))
                        {
                            straightMoves |= direction(straightMoves);
                        }
                        sourceSquareCandidates &= straightMoves;

                        foreach (Square sourceSquareCandidate in sourceSquareCandidates.AllSquares())
                        {
                            moveInfo.SourceSquare = sourceSquareCandidate;
                            break;
                        }
                    }

                    if (promoteTo != null)
                    {
                        moveInfo.MoveType  = MoveType.Promotion;
                        moveInfo.PromoteTo = (Piece)promoteTo;
                    }
                }
                else
                {
                    switch (movingPiece)
                    {
                    case Piece.Knight:
                        sourceSquareCandidates &= Constants.KnightMoves[moveInfo.TargetSquare];
                        break;

                    case Piece.Bishop:
                        sourceSquareCandidates &= Constants.ReachableSquaresDiagonal(moveInfo.TargetSquare, occupied);
                        break;

                    case Piece.Rook:
                        sourceSquareCandidates &= Constants.ReachableSquaresStraight(moveInfo.TargetSquare, occupied);
                        break;

                    case Piece.Queen:
                        sourceSquareCandidates &= Constants.ReachableSquaresDiagonal(moveInfo.TargetSquare, occupied)
                                                  | Constants.ReachableSquaresStraight(moveInfo.TargetSquare, occupied);
                        break;

                    case Piece.King:
                        sourceSquareCandidates &= Constants.Neighbours[moveInfo.TargetSquare];
                        break;

                    default:
                        sourceSquareCandidates = 0;
                        break;
                    }

                    foreach (Square sourceSquareCandidate in sourceSquareCandidates.AllSquares())
                    {
                        if (disambiguatingSourceFile != null)
                        {
                            if (disambiguatingSourceFile == (File)sourceSquareCandidate.X())
                            {
                                if (disambiguatingSourceRank != null)
                                {
                                    if (disambiguatingSourceRank == (Rank)sourceSquareCandidate.Y())
                                    {
                                        moveInfo.SourceSquare = sourceSquareCandidate;
                                        break;
                                    }
                                }
                                else
                                {
                                    moveInfo.SourceSquare = sourceSquareCandidate;
                                    break;
                                }
                            }
                        }
                        else if (disambiguatingSourceRank != null)
                        {
                            if (disambiguatingSourceRank == (Rank)sourceSquareCandidate.Y())
                            {
                                moveInfo.SourceSquare = sourceSquareCandidate;
                                break;
                            }
                        }
                        else
                        {
                            moveInfo.SourceSquare = sourceSquareCandidate;
                            break;
                        }
                    }
                }
            }

            return(moveInfo);
        }