private void AddBishopAttack(SortedDictionary <int, SquareFlag> dictionary, int squareIndex, SquareFlag currentOccupancy)
        {
            var magicIndex = MagicIndexHelpers.GetBishopMagicIndex(squareIndex, currentOccupancy);

            var attack = AttackGenerator.GeneratePotentialBishopAttacks(squareIndex, currentOccupancy);

            var indexTaken = dictionary.ContainsKey(magicIndex) && dictionary[magicIndex] != attack;

            if (indexTaken)
            {
                throw new Exception($"Magic Index {magicIndex} already in use by a different attack");
            }

            dictionary[magicIndex] = attack;
        }
        private SquareFlag GetAttackableSquares(Square fromSquare, PieceType rayType, SquareFlag occupiedSquares)
        {
            var occupancyMask = rayType == PieceType.Rook
                ? MagicNumbers.RookOccupancyMasks[fromSquare.Index]
                : MagicNumbers.BishopOccupancyMasks[fromSquare.Index];

            var occupancyMasked = occupiedSquares & occupancyMask;

            var magicIndex = MagicIndexHelpers.GetMagicIndex(rayType, fromSquare.Index, occupancyMasked);

            var attackableSquaresIncludingSelfCaptures = rayType == PieceType.Rook
                ? AttackBitmaps.RookAttacks[fromSquare.Index][magicIndex]
                : AttackBitmaps.BishopAttacks[fromSquare.Index][magicIndex];

            return(attackableSquaresIncludingSelfCaptures);
        }
        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));
                        }
                    }
                }
            }
        }