示例#1
0
        private void AddIndividualRayMoves(MoveGenerationWorkspace workspace, Square fromSquare, PieceType rayType, PieceType pieceType, SquareFlag legalMask)
        {
            var attackableSquaresIncludingSelfCaptures = GetAttackableSquares(fromSquare, rayType, workspace.RelativeBitBoard.OccupiedSquares);
            var attackableSquares      = attackableSquaresIncludingSelfCaptures & ~workspace.RelativeBitBoard.MySquares;
            var legalAttackableSquares = attackableSquares & legalMask;

            ToOrdinaryMoves(workspace, pieceType, fromSquare, legalAttackableSquares);
        }
示例#2
0
        private void AddIndividualKnightMoves(MoveGenerationWorkspace workspace, RelativeBoard relativeBitBoard, Square fromSquare, SquareFlag legalMask)
        {
            var attackableSquaresIncludingSelfCaptures = AttackBitmaps.KnightAttacks[fromSquare.Index];
            var attackableSquares      = attackableSquaresIncludingSelfCaptures & ~relativeBitBoard.MySquares;
            var legalAttackableSquares = attackableSquares & legalMask;

            ToOrdinaryMoves(workspace, PieceType.Knight, fromSquare, legalAttackableSquares);
        }
示例#3
0
        public MoveGenerator(int workspaceCount)
        {
            workspaces = new MoveGenerationWorkspace[workspaceCount];

            for (var i = 0; i < workspaceCount; ++i)
            {
                workspaces[i] = new MoveGenerationWorkspace(i);
            }
        }
示例#4
0
        private SquareFlag AddPinnedMovesInternal(
            MoveGenerationWorkspace workspace,
            Square kingSquare,
            SquareFlag potentialPins,
            SquareFlag pinners,
            bool diagonal,
            SquareFlag pushMask,
            SquareFlag captureMask)
        {
            var pinnedSquares = (SquareFlag)0;
            var pinnersAsList = pinners.ToList();

            foreach (var pinner in pinnersAsList)
            {
                var path = AttackBitmaps.Paths[kingSquare.Index][pinner.ToSquareIndex()];

                var squarePinnedByThisPiece = path & potentialPins;

                if (squarePinnedByThisPiece == 0)
                {
                    continue;
                }

                pinnedSquares |= squarePinnedByThisPiece;

                var pushPath    = path & pushMask;
                var capturePath = path & captureMask;

                var pieceType = workspace.RelativeBitBoard.GetPieceType(squarePinnedByThisPiece);

                switch (pieceType)
                {
                case PieceType.Pawn when !diagonal:
                    AddIndividualPawnPushes(workspace, squarePinnedByThisPiece.ToSquare(), pushPath);
                    break;

                case PieceType.Pawn when diagonal:
                    AddIndividualPawnCaptures(workspace, squarePinnedByThisPiece.ToSquare(), pushPath, capturePath);
                    break;

                case PieceType.Rook:
                    AddIndividualRayMoves(workspace, squarePinnedByThisPiece.ToSquare(), PieceType.Rook, PieceType.Rook, pushPath | capturePath);
                    break;

                case PieceType.Bishop:
                    AddIndividualRayMoves(workspace, squarePinnedByThisPiece.ToSquare(), PieceType.Bishop, PieceType.Bishop, pushPath | capturePath);
                    break;

                case PieceType.Queen:
                    AddIndividualQueenMoves(workspace, squarePinnedByThisPiece.ToSquare(), pushPath | capturePath);
                    break;
                }
            }

            return(pinnedSquares);
        }
示例#5
0
 private void AddPromotions(MoveGenerationWorkspace workspace, Square fromSquare, Square toSquare, PieceType capturePieceType)
 {
     if (capturePieceType != PieceType.None)
     {
         workspace.CaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionQueen, workspace.NumCheckers));
         workspace.CaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionRook, workspace.NumCheckers));
         workspace.CaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionKnight, workspace.NumCheckers));
         workspace.CaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionBishop, workspace.NumCheckers));
     }
     else
     {
         workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionQueen, workspace.NumCheckers));
         workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionRook, workspace.NumCheckers));
         workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionKnight, workspace.NumCheckers));
         workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare, capturePieceType, MoveType.PromotionBishop, workspace.NumCheckers));
     }
 }
示例#6
0
        private void ToOrdinaryMoves(MoveGenerationWorkspace workspace, PieceType pieceType, Square fromSquare, SquareFlag attackableSquares)
        {
            var attackableSquaresAsList = attackableSquares.ToList();

            foreach (var toSquare in attackableSquaresAsList)
            {
                if (!workspace.RelativeBitBoard.OpponentSquares.HasFlag(toSquare))
                {
                    workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, pieceType, fromSquare, toSquare.ToSquare(), PieceType.None, MoveType.Ordinary, workspace.NumCheckers));

                    continue;
                }

                var capturePieceType = workspace.RelativeBitBoard.GetPieceType(toSquare);

                workspace.CaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, pieceType, fromSquare, toSquare.ToSquare(), capturePieceType, MoveType.Ordinary, workspace.NumCheckers));
            }
        }
示例#7
0
        private void AddIndividualPawnPushes(MoveGenerationWorkspace workspace, Square fromSquare, SquareFlag pushMask)
        {
            var relativeBitBoard = workspace.RelativeBitBoard;

            var toSquare = fromSquare.Flag
                           .PawnForward(relativeBitBoard.Colour, 1)
                           .ToSquare();

            if (relativeBitBoard.OccupiedSquares.HasFlag(toSquare.Flag))
            {
                return;
            }

            if (pushMask.HasFlag(toSquare.Flag))
            {
                if (relativeBitBoard.PromotionRank.HasFlag(toSquare.Flag))
                {
                    AddPromotions(workspace, fromSquare, toSquare, PieceType.None);
                }
                else
                {
                    workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(relativeBitBoard.Colour, PieceType.Pawn, fromSquare, toSquare, PieceType.None, MoveType.Ordinary, workspace.NumCheckers));
                }
            }

            // Possible that we can block check with double push
            if (relativeBitBoard.StartRank.HasFlag(fromSquare.Flag))
            {
                toSquare = fromSquare.Flag
                           .PawnForward(relativeBitBoard.Colour, 2)
                           .ToSquare();

                if (!pushMask.HasFlag(toSquare.Flag))
                {
                    return;
                }

                // Promotions not possible from start rank
                if (!relativeBitBoard.OccupiedSquares.HasFlag(toSquare.Flag))
                {
                    workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(relativeBitBoard.Colour, PieceType.Pawn, fromSquare, toSquare, PieceType.None, MoveType.Ordinary, workspace.NumCheckers));
                }
            }
        }
示例#8
0
        private void AddCastles(MoveGenerationWorkspace workspace, Square kingSquare)
        {
            var relativeBitBoard = workspace.RelativeBitBoard;

            if (!relativeBitBoard.CanCastleKingSide && !relativeBitBoard.CanCastleQueenSide)
            {
                return;
            }

            // We lose castle rights if any piece moves so they MUST be in correct locations
            if (relativeBitBoard.CanCastleKingSide)
            {
                var kingSideRookIndex = relativeBitBoard.KingSideRookStartSquare.ToSquareIndex();

                var kingToRook = AttackBitmaps.Paths[kingSquare.Index][kingSideRookIndex];

                var squaresBetween = kingToRook & ~relativeBitBoard.KingStartSquare & ~relativeBitBoard.KingSideRookStartSquare;

                if ((squaresBetween & relativeBitBoard.OccupiedSquares) == 0)
                {
                    var stepSquares       = relativeBitBoard.KingSideCastleStep1 | relativeBitBoard.KingSideCastleStep2;
                    var safeSquaresAsList = FindSafeSquares(workspace, stepSquares.ToList());

                    var safeSquares = (SquareFlag)0;

                    foreach (var safeSquare in safeSquaresAsList)
                    {
                        safeSquares |= safeSquare;
                    }

                    if (squaresBetween == safeSquares)
                    {
                        workspace.NonCaptureMoveBuffer.Add(MoveBuilder.CreateCastle(relativeBitBoard.Colour, MoveType.CastleKing));
                    }
                }
            }

            if (relativeBitBoard.CanCastleQueenSide)
            {
                var queenSideRookIndex = relativeBitBoard.QueenSideRookStartSquare.ToSquareIndex();

                var kingToRook = AttackBitmaps.Paths[kingSquare.Index][queenSideRookIndex];

                var squaresBetween = kingToRook & ~relativeBitBoard.KingStartSquare & ~relativeBitBoard.QueenSideRookStartSquare;

                if ((squaresBetween & relativeBitBoard.OccupiedSquares) == 0)
                {
                    var stepSquares       = relativeBitBoard.QueenSideCastleStep1 | relativeBitBoard.QueenSideCastleStep2;
                    var safeSquaresAsList = FindSafeSquares(workspace, stepSquares.ToList());

                    var safeSquares = (SquareFlag)0;

                    foreach (var safeSquare in safeSquaresAsList)
                    {
                        safeSquares |= safeSquare;
                    }

                    // On Queen side the King doesn't pass through B file so we don't look for Check there
                    var squaresBetweenMinusFirstRookStep = squaresBetween & ~relativeBitBoard.QueenSideRookStep1Square;

                    if (squaresBetweenMinusFirstRookStep == safeSquares)
                    {
                        workspace.NonCaptureMoveBuffer.Add(MoveBuilder.CreateCastle(relativeBitBoard.Colour, MoveType.CastleQueen));
                    }
                }
            }
        }
示例#9
0
 private void AddIndividualQueenMoves(MoveGenerationWorkspace workspace, Square fromSquare, SquareFlag legalMask)
 {
     AddIndividualRayMoves(workspace, fromSquare, PieceType.Rook, PieceType.Queen, legalMask);
     AddIndividualRayMoves(workspace, fromSquare, PieceType.Bishop, PieceType.Queen, legalMask);
 }
示例#10
0
        private void AddIndividualPawnCaptures(MoveGenerationWorkspace workspace, Square fromSquare, SquareFlag pushMask, SquareFlag captureMask)
        {
            var relativeBitBoard = workspace.RelativeBitBoard;

            var captureSquares = relativeBitBoard.Colour == Colour.White
                ? AttackBitmaps.PawnCapturesWhite[fromSquare.Index].ToList()
                : AttackBitmaps.PawnCapturesBlack[fromSquare.Index].ToList();

            foreach (var toSquare in captureSquares)
            {
                var moveType = relativeBitBoard.EnPassant.HasFlag(toSquare) ? MoveType.EnPassant : MoveType.Ordinary;

                if (relativeBitBoard.OpponentSquares.HasFlag(toSquare) || moveType == MoveType.EnPassant)
                {
                    var capturePieceType = relativeBitBoard.GetPieceType(toSquare);

                    var discoveredCheck = false;

                    if (moveType != MoveType.EnPassant)
                    {
                        if (!captureMask.HasFlag(toSquare))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        // Abuse the push system - push an imaginary pawn from the en passant square as opponent to find piece
                        var enPassantCaptureSquare = relativeBitBoard.EnPassant.PawnForward(relativeBitBoard.OpponentColour, 1);

                        var blockWithPush = pushMask.HasFlag(relativeBitBoard.EnPassant);

                        var evadeWithCapture = captureMask.HasFlag(enPassantCaptureSquare);

                        if (!blockWithPush && !evadeWithCapture)
                        {
                            continue;
                        }

                        capturePieceType = PieceType.Pawn;

                        // Looking for DISCOVERED CHECK (not spotted by pinned pieces as there are 2 pawns in the way)
                        // Slight duplication here but probably cleaner than passing in
                        var kingSquare = relativeBitBoard.MyKing.ToSquare();

                        var enPassantDiscoveredCheckRank = relativeBitBoard.EnPassantDiscoveredCheckRank;

                        // This should be super rare. Performing an en passant capture with our King on same rank.
                        if (enPassantDiscoveredCheckRank.HasFlag(kingSquare.Flag))
                        {
                            if ((enPassantDiscoveredCheckRank & relativeBitBoard.OpponentRooks) > 0 ||
                                (enPassantDiscoveredCheckRank & relativeBitBoard.OpponentQueens) > 0)
                            {
                                var occupancyMask = MagicNumbers.RookOccupancyMasks[kingSquare.Index];

                                var occupancyBeforeCapture = relativeBitBoard.OccupiedSquares & occupancyMask;

                                var occupancyAfterCapture = occupancyBeforeCapture
                                                            & ~enPassantCaptureSquare
                                                            & ~fromSquare.Flag;

                                // Search for magic moves using just the occupancy of rank (the rest is not relevant)
                                var magicIndex = MagicIndexHelpers.GetMagicIndex(PieceType.Rook, kingSquare.Index, occupancyAfterCapture);

                                var kingRayAttacks = AttackBitmaps.RookAttacks[kingSquare.Index][magicIndex];

                                var kingRayAttacksOnRank = kingRayAttacks & enPassantDiscoveredCheckRank;

                                discoveredCheck = (kingRayAttacksOnRank & relativeBitBoard.OpponentRooks) > 0 ||
                                                  (kingRayAttacksOnRank & relativeBitBoard.OpponentQueens) > 0;
                            }
                        }
                    }

                    if (relativeBitBoard.PromotionRank.HasFlag(toSquare))
                    {
                        AddPromotions(workspace, fromSquare, toSquare.ToSquare(), capturePieceType);
                    }
                    else if (!discoveredCheck)
                    {
                        if (capturePieceType != PieceType.None)
                        {
                            workspace.CaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare.ToSquare(), capturePieceType, moveType, workspace.NumCheckers));
                        }
                        else
                        {
                            workspace.NonCaptureMoveBuffer.Add(MoveBuilder.Create(workspace.Colour, PieceType.Pawn, fromSquare, toSquare.ToSquare(), capturePieceType, moveType, workspace.NumCheckers));
                        }
                    }
                }
            }
        }
示例#11
0
        private SquareFlag AddPinnedMoves(
            MoveGenerationWorkspace workspace,
            Square kingSquare,
            SquareFlag kingRayAttackSquares,
            SquareFlag pushMask,
            SquareFlag captureMask)
        {
            var relativeBitBoard = workspace.RelativeBitBoard;

            var potentialPins = kingRayAttackSquares & relativeBitBoard.MySquares;

            var occupiedSquaresWithoutPotentialPins = relativeBitBoard.OccupiedSquares & ~potentialPins;

            var attackableSquaresBeyondPinsRook   = GetAttackableSquares(kingSquare, PieceType.Rook, occupiedSquaresWithoutPotentialPins);
            var attackableSquaresBeyondPinsBishop = GetAttackableSquares(kingSquare, PieceType.Bishop, occupiedSquaresWithoutPotentialPins);
            var attackableSquaresBeyondPins       = attackableSquaresBeyondPinsRook | attackableSquaresBeyondPinsBishop;

            var pinningRooks             = (SquareFlag)0;
            var pinningBishops           = (SquareFlag)0;
            var pinningQueensNonDiagonal = (SquareFlag)0;
            var pinningQueensDiagonal    = (SquareFlag)0;

            var buffer1 = workspace.Buffer1;
            var buffer2 = workspace.Buffer2;

            if (Vector <ulong> .Count == 4)
            {
                buffer1[0] = (ulong)attackableSquaresBeyondPinsRook;
                buffer1[1] = (ulong)attackableSquaresBeyondPinsBishop;
                buffer1[2] = (ulong)attackableSquaresBeyondPinsRook;
                buffer1[3] = (ulong)attackableSquaresBeyondPinsBishop;

                buffer2[0] = (ulong)relativeBitBoard.OpponentRooks;
                buffer2[1] = (ulong)relativeBitBoard.OpponentBishops;
                buffer2[2] = (ulong)relativeBitBoard.OpponentQueens;
                buffer2[3] = (ulong)relativeBitBoard.OpponentQueens;

                var vector1 = new Vector <ulong>(buffer1);
                var vector2 = new Vector <ulong>(buffer2);

                var vectorOut = Vector.BitwiseAnd(vector1, vector2);

                var anyGreaterThanZero = Vector.GreaterThanAny(vectorOut, new Vector <ulong>(0));

                if (!anyGreaterThanZero)
                {
                    return(0);
                }

                pinningRooks             = (SquareFlag)vectorOut[0];
                pinningBishops           = (SquareFlag)vectorOut[1];
                pinningQueensNonDiagonal = (SquareFlag)vectorOut[2];
                pinningQueensDiagonal    = (SquareFlag)vectorOut[3];
            }
            else
            {
                pinningRooks             = attackableSquaresBeyondPinsRook & relativeBitBoard.OpponentRooks;
                pinningBishops           = attackableSquaresBeyondPinsBishop & relativeBitBoard.OpponentBishops;
                pinningQueensNonDiagonal = attackableSquaresBeyondPinsRook & relativeBitBoard.OpponentQueens;
                pinningQueensDiagonal    = attackableSquaresBeyondPinsBishop & relativeBitBoard.OpponentQueens;
            }

            var pinnedPieces = (SquareFlag)0;

            if (pinningRooks > 0)
            {
                pinnedPieces |= AddPinnedMovesInternal(workspace, kingSquare, potentialPins, pinningRooks, false, pushMask, captureMask);
            }

            if (pinningBishops > 0)
            {
                pinnedPieces |= AddPinnedMovesInternal(workspace, kingSquare, potentialPins, pinningBishops, true, pushMask, captureMask);
            }

            if (pinningQueensNonDiagonal > 0)
            {
                pinnedPieces |= AddPinnedMovesInternal(workspace, kingSquare, potentialPins, pinningQueensNonDiagonal, false, pushMask, captureMask);
            }

            if (pinningQueensDiagonal > 0)
            {
                pinnedPieces |= AddPinnedMovesInternal(workspace, kingSquare, potentialPins, pinningQueensDiagonal, true, pushMask, captureMask);
            }

            return(pinnedPieces);
        }
示例#12
0
        private IList <SquareFlag> FindSafeSquares(MoveGenerationWorkspace workspace, IEnumerable <SquareFlag> attackableSquares)
        {
            var relativeBitBoard = workspace.RelativeBitBoard;

            var safeSquares = workspace.SafeSquares;

            safeSquares.Clear();

            var unsafeSquares = (SquareFlag)0;

            var buffer1 = workspace.Buffer1;
            var buffer2 = workspace.Buffer2;

            foreach (var attackableSquare in attackableSquares)
            {
                if (unsafeSquares.HasFlag(attackableSquare))
                {
                    continue;
                }

                var targetSquare = attackableSquare.ToSquare();

                var opponentPawnAttacks = relativeBitBoard.Colour == Colour.White
                    ? AttackBitmaps.PawnCapturesWhite[targetSquare.Index]
                    : AttackBitmaps.PawnCapturesBlack[targetSquare.Index];

                var potentialCheckersPawn        = (SquareFlag)0;
                var potentialCheckersKing        = (SquareFlag)0;
                var potentialCheckersKnight      = (SquareFlag)0;
                var occupiedSquaresWithoutMyKing = (SquareFlag)0;

                if (Vector <ulong> .Count == 4)
                {
                    buffer1[0] = (ulong)opponentPawnAttacks;
                    buffer1[1] = (ulong)AttackBitmaps.KingAttacks[targetSquare.Index];
                    buffer1[2] = (ulong)AttackBitmaps.KnightAttacks[targetSquare.Index];
                    buffer1[3] = (ulong)relativeBitBoard.OccupiedSquares;

                    buffer2[0] = (ulong)relativeBitBoard.OpponentPawns;
                    buffer2[1] = (ulong)relativeBitBoard.OpponentKing;
                    buffer2[2] = (ulong)relativeBitBoard.OpponentKnights;
                    buffer2[3] = (ulong)~relativeBitBoard.MyKing;

                    var vector1 = new Vector <ulong>(buffer1);
                    var vector2 = new Vector <ulong>(buffer2);

                    var vectorOut = Vector.BitwiseAnd(vector1, vector2);

                    potentialCheckersPawn        = (SquareFlag)vectorOut[0];
                    potentialCheckersKing        = (SquareFlag)vectorOut[1];
                    potentialCheckersKnight      = (SquareFlag)vectorOut[2];
                    occupiedSquaresWithoutMyKing = (SquareFlag)vectorOut[3];
                }
                else
                {
                    potentialCheckersPawn        = opponentPawnAttacks & relativeBitBoard.OpponentPawns;
                    potentialCheckersKing        = AttackBitmaps.KingAttacks[targetSquare.Index] & relativeBitBoard.OpponentKing;
                    potentialCheckersKnight      = AttackBitmaps.KnightAttacks[targetSquare.Index] & relativeBitBoard.OpponentKnights;
                    occupiedSquaresWithoutMyKing = relativeBitBoard.OccupiedSquares & ~relativeBitBoard.MyKing;
                }

                if (potentialCheckersKing > 0)
                {
                    continue;
                }

                if (potentialCheckersPawn > 0)
                {
                    continue;
                }

                if (potentialCheckersKnight > 0)
                {
                    continue;
                }

                var attackableRookSquares   = GetAttackableSquares(targetSquare, PieceType.Rook, occupiedSquaresWithoutMyKing);
                var attackableBishopSquares = GetAttackableSquares(targetSquare, PieceType.Bishop, occupiedSquaresWithoutMyKing);

                var potentialCheckersRook          = (SquareFlag)0;
                var potentialCheckersBishop        = (SquareFlag)0;
                var potentialCheckersQueenAsRook   = (SquareFlag)0;
                var potentialCheckersQueenAsBishop = (SquareFlag)0;

                if (Vector <ulong> .Count == 4)
                {
                    buffer1[0] = (ulong)attackableRookSquares;
                    buffer1[1] = (ulong)attackableBishopSquares;
                    buffer1[2] = (ulong)attackableRookSquares;
                    buffer1[3] = (ulong)attackableBishopSquares;

                    buffer2[0] = (ulong)relativeBitBoard.OpponentRooks;
                    buffer2[1] = (ulong)relativeBitBoard.OpponentBishops;
                    buffer2[2] = (ulong)relativeBitBoard.OpponentQueens;
                    buffer2[3] = (ulong)relativeBitBoard.OpponentQueens;

                    var vector1 = new Vector <ulong>(buffer1);
                    var vector2 = new Vector <ulong>(buffer2);

                    var vectorOut = Vector.BitwiseAnd(vector1, vector2);

                    potentialCheckersRook          = (SquareFlag)vectorOut[0];
                    potentialCheckersBishop        = (SquareFlag)vectorOut[1];
                    potentialCheckersQueenAsRook   = (SquareFlag)vectorOut[2];
                    potentialCheckersQueenAsBishop = (SquareFlag)vectorOut[3];
                }
                else
                {
                    potentialCheckersRook          = attackableRookSquares & relativeBitBoard.OpponentRooks;
                    potentialCheckersBishop        = attackableBishopSquares & relativeBitBoard.OpponentBishops;
                    potentialCheckersQueenAsRook   = attackableRookSquares & relativeBitBoard.OpponentQueens;
                    potentialCheckersQueenAsBishop = attackableBishopSquares & relativeBitBoard.OpponentQueens;
                }

                if (potentialCheckersRook > 0)
                {
                    foreach (var potentialCheckerRook in potentialCheckersRook.ToList())
                    {
                        unsafeSquares |= AttackBitmaps.Paths[targetSquare.Index][potentialCheckerRook.ToSquareIndex()] & ~potentialCheckerRook;
                    }

                    continue;
                }

                if (potentialCheckersBishop > 0)
                {
                    foreach (var potentialCheckerBishop in potentialCheckersBishop.ToList())
                    {
                        unsafeSquares |= AttackBitmaps.Paths[targetSquare.Index][potentialCheckerBishop.ToSquareIndex()] & ~potentialCheckerBishop;
                    }

                    continue;
                }

                if (potentialCheckersQueenAsRook > 0)
                {
                    foreach (var potentialCheckerQueenAsRook in potentialCheckersQueenAsRook.ToList())
                    {
                        unsafeSquares |= AttackBitmaps.Paths[targetSquare.Index][potentialCheckerQueenAsRook.ToSquareIndex()] & ~potentialCheckerQueenAsRook;
                    }

                    continue;
                }

                if (potentialCheckersQueenAsBishop > 0)
                {
                    foreach (var potentialCheckerQueenAsBishop in potentialCheckersQueenAsBishop.ToList())
                    {
                        unsafeSquares |= AttackBitmaps.Paths[targetSquare.Index][potentialCheckerQueenAsBishop.ToSquareIndex()] & ~potentialCheckerQueenAsBishop;
                    }

                    continue;
                }

                safeSquares.Add(attackableSquare);
            }

            return(safeSquares);
        }