Example #1
0
        private void GenerateQueenMoves(MoveGeneration MoveGeneration, ulong FromSquareMask, ulong ToSquareMask)
        {
            ulong queens;
            ulong unOrEnemyOccupiedSquares;
            ulong enemyOccupiedSquares;
            int   attacker;

            if (WhiteMove)
            {
                // White Move
                queens = WhiteQueens & FromSquareMask;
                unOrEnemyOccupiedSquares = ~OccupancyWhite;
                enemyOccupiedSquares     = OccupancyBlack;
                attacker = Piece.WhiteQueen;
            }
            else
            {
                // Black Move
                queens = BlackQueens & FromSquareMask;
                unOrEnemyOccupiedSquares = ~OccupancyBlack;
                enemyOccupiedSquares     = OccupancyWhite;
                attacker = Piece.BlackQueen;
            }
            int fromSquare;

            while ((fromSquare = Bitwise.FindFirstSetBit(queens)) != Square.Illegal)
            {
                var bishopOccupancy   = Board.BishopMoveMasks[fromSquare] & Occupancy;
                var rookOccupancy     = Board.RookMoveMasks[fromSquare] & Occupancy;
                var queenDestinations = MoveGeneration switch
                {
                    MoveGeneration.AllMoves => (Board.PrecalculatedMoves.GetBishopMovesMask(fromSquare, bishopOccupancy) | Board.PrecalculatedMoves.GetRookMovesMask(fromSquare, rookOccupancy)) & unOrEnemyOccupiedSquares & ToSquareMask,
                    MoveGeneration.OnlyCaptures => (Board.PrecalculatedMoves.GetBishopMovesMask(fromSquare, bishopOccupancy) | Board.PrecalculatedMoves.GetRookMovesMask(fromSquare, rookOccupancy)) & enemyOccupiedSquares & ToSquareMask,
                    MoveGeneration.OnlyNonCaptures => (Board.PrecalculatedMoves.GetBishopMovesMask(fromSquare, bishopOccupancy) | Board.PrecalculatedMoves.GetRookMovesMask(fromSquare, rookOccupancy)) & ~Occupancy & ToSquareMask,
                    _ => throw new Exception($"{MoveGeneration} move generation not supported.")
                };
                int toSquare;
                while ((toSquare = Bitwise.FindFirstSetBit(queenDestinations)) != Square.Illegal)
                {
                    var victim = GetPiece(toSquare);
                    var move   = Move.Null;
                    Move.SetFrom(ref move, fromSquare);
                    Move.SetTo(ref move, toSquare);
                    if (victim != Piece.None)
                    {
                        Move.SetCaptureAttacker(ref move, attacker);
                    }
                    Move.SetCaptureVictim(ref move, victim);
                    Move.SetIsQuiet(ref move, victim == Piece.None);
                    Moves[MoveIndex] = move;
                    MoveIndex++;
                    Bitwise.ClearBit(ref queenDestinations, toSquare);
                }
                Bitwise.ClearBit(ref queens, fromSquare);
            }
        }
Example #2
0
        private void GenerateKnightMoves(MoveGeneration MoveGeneration, ulong FromSquareMask, ulong ToSquareMask)
        {
            ulong knights;
            ulong unOrEnemyOccupiedSquares;
            ulong enemyOccupiedSquares;
            int   attacker;

            if (WhiteMove)
            {
                // White Move
                knights = WhiteKnights & FromSquareMask;
                unOrEnemyOccupiedSquares = ~OccupancyWhite;
                enemyOccupiedSquares     = OccupancyBlack;
                attacker = Piece.WhiteKnight;
            }
            else
            {
                // Black Move
                knights = BlackKnights & FromSquareMask;
                unOrEnemyOccupiedSquares = ~OccupancyBlack;
                enemyOccupiedSquares     = OccupancyWhite;
                attacker = Piece.BlackKnight;
            }
            int fromSquare;

            while ((fromSquare = Bitwise.FindFirstSetBit(knights)) != Square.Illegal)
            {
                var knightDestinations = MoveGeneration switch
                {
                    MoveGeneration.AllMoves => Board.KnightMoveMasks[fromSquare] & unOrEnemyOccupiedSquares & ToSquareMask,
                    MoveGeneration.OnlyCaptures => Board.KnightMoveMasks[fromSquare] & enemyOccupiedSquares & ToSquareMask,
                    MoveGeneration.OnlyNonCaptures => Board.KnightMoveMasks[fromSquare] & ~Occupancy & ToSquareMask,
                    _ => throw new Exception($"{MoveGeneration} move generation not supported.")
                };
                int toSquare;
                while ((toSquare = Bitwise.FindFirstSetBit(knightDestinations)) != Square.Illegal)
                {
                    var victim = GetPiece(toSquare);
                    var move   = Move.Null;
                    Move.SetFrom(ref move, fromSquare);
                    Move.SetTo(ref move, toSquare);
                    if (victim != Piece.None)
                    {
                        Move.SetCaptureAttacker(ref move, attacker);
                    }
                    Move.SetCaptureVictim(ref move, victim);
                    Move.SetIsQuiet(ref move, victim == Piece.None);
                    Moves[MoveIndex] = move;
                    MoveIndex++;
                    Bitwise.ClearBit(ref knightDestinations, toSquare);
                }
                Bitwise.ClearBit(ref knights, fromSquare);
            }
        }
Example #3
0
        public void FindPotentiallyPinnedPieces()
        {
            int   kingSquare;
            ulong pieces;
            ulong enemyBishopsQueens;
            ulong enemyRooksQueens;

            if (WhiteMove)
            {
                // White Move
                kingSquare         = Bitwise.FindFirstSetBit(WhiteKing);
                pieces             = OccupancyWhite;
                enemyBishopsQueens = BlackBishops | BlackQueens;
                enemyRooksQueens   = BlackRooks | BlackQueens;
            }
            else
            {
                // Black Move
                kingSquare         = Bitwise.FindFirstSetBit(BlackKing);
                pieces             = OccupancyBlack;
                enemyBishopsQueens = WhiteBishops | WhiteQueens;
                enemyRooksQueens   = WhiteRooks | WhiteQueens;
            }
            PotentiallyPinnedPieces = 0;
            var fileAttackers = Board.FileMasks[Board.Files[kingSquare]] & enemyRooksQueens;

            if (fileAttackers > 0)
            {
                PotentiallyPinnedPieces |= Board.FileMasks[Board.Files[kingSquare]] & pieces;
            }
            var rankAttackers = Board.RankMasks[Board.WhiteRanks[kingSquare]] & enemyRooksQueens;

            if (rankAttackers > 0)
            {
                PotentiallyPinnedPieces |= Board.RankMasks[Board.WhiteRanks[kingSquare]] & pieces;
            }
            var upDiagonalAttackers = Board.UpDiagonalMasks[Board.UpDiagonals[kingSquare]] & enemyBishopsQueens;

            if (upDiagonalAttackers > 0)
            {
                PotentiallyPinnedPieces |= Board.UpDiagonalMasks[Board.UpDiagonals[kingSquare]] & pieces;
            }
            var downDiagonalAttackers = Board.DownDiagonalMasks[Board.DownDiagonals[kingSquare]] & enemyBishopsQueens;

            if (downDiagonalAttackers > 0)
            {
                PotentiallyPinnedPieces |= Board.DownDiagonalMasks[Board.DownDiagonals[kingSquare]] & pieces;
            }
        }
Example #4
0
        public static string ToString(ulong Occupancy)
        {
            var stringBuilder = new StringBuilder();

            for (var rank = 7; rank >= 0; rank--)
            {
                for (var file = 0; file < 8; file++)
                {
                    var square = Board.GetSquare(file, rank);
                    stringBuilder.Append(Bitwise.IsBitSet(Occupancy, square) ? " 1 " : " . ");
                }
                stringBuilder.AppendLine();
            }
            return(stringBuilder.ToString());
        }
Example #5
0
        // Castling Bits

        // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
        // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
        //                                                         K|Q|k|q

        // K = White Castle Kingside
        // Q = White Castle Queenside
        // k = Black Castle Kingside
        // q = Black Castle Queenside


        static Castling()
        {
            // Create bit shifts and masks.
            _whiteKingsideShift   = 3;
            _whiteKingsideMask    = Bitwise.CreateUIntMask(3, 3);
            _whiteKingsideUnmask  = Bitwise.CreateUIntUnmask(3, 3);
            _whiteQueensideShift  = 2;
            _whiteQueensideMask   = Bitwise.CreateUIntMask(2, 2);
            _whiteQueensideUnmask = Bitwise.CreateUIntUnmask(2, 2);
            _blackKingsideShift   = 1;
            _blackKingsideMask    = Bitwise.CreateUIntMask(1, 1);
            _blackKingsideUnmask  = Bitwise.CreateUIntUnmask(1, 1);
            _blackQueensideMask   = Bitwise.CreateUIntMask(0, 0);
            _blackQueensideUnmask = Bitwise.CreateUIntUnmask(0, 0);
        }
Example #6
0
        // CachedPosition.Data Bits

        // 6 6 6 6 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
        // 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
        // To Horizon |Best From    |Best To      |BMP    |Score                                                      |SP |Last Accessed

        // Best From = Best Move From (one extra bit for illegal square)
        // Best To =   Best Move To   (one extra bit for illegal square)
        // BMP =       Best Move Promoted Piece
        // SP =        Score Precision


        static CachedPositionData()
        {
            // Create bit shifts and masks.
            _toHorizonShift              = 58;
            _toHorizonMask               = Bitwise.CreateULongMask(58, 63);
            _toHorizonUnmask             = Bitwise.CreateULongUnmask(58, 63);
            _bestMoveFromShift           = 51;
            _bestMoveFromMask            = Bitwise.CreateULongMask(51, 57);
            _bestMoveFromUnmask          = Bitwise.CreateULongUnmask(51, 57);
            _bestMoveToShift             = 44;
            _bestMoveToMask              = Bitwise.CreateULongMask(44, 50);
            _bestMoveToUnmask            = Bitwise.CreateULongUnmask(44, 50);
            _bestMovePromotedPieceShift  = 40;
            _bestMovePromotedPieceMask   = Bitwise.CreateULongMask(40, 43);
            _bestMovePromotedPieceUnmask = Bitwise.CreateULongUnmask(40, 43);
            _scoreShift           = 10;
            _scoreMask            = Bitwise.CreateULongMask(10, 39);
            _scoreUnmask          = Bitwise.CreateULongUnmask(10, 39);
            _scorePrecisionShift  = 8;
            _scorePrecisionMask   = Bitwise.CreateULongMask(8, 9);
            _scorePrecisionUnmask = Bitwise.CreateULongUnmask(8, 9);
            _lastAccessedMask     = Bitwise.CreateULongMask(0, 7);
            _lastAccessedUnmask   = Bitwise.CreateULongUnmask(0, 7);
        }
Example #7
0
        public void FindPinnedPieces()
        {
            int   ownKingSquare;
            ulong ownPieces;
            ulong enemyRankFileAttackers;
            ulong enemyDiagonalAttackers;
            ulong enemyPieces;

            if (WhiteMove)
            {
                // White Move
                ownKingSquare          = Bitwise.FindFirstSetBit(WhiteKing);
                ownPieces              = OccupancyWhite;
                enemyRankFileAttackers = BlackRooks | BlackQueens;
                enemyDiagonalAttackers = BlackBishops | BlackQueens;
                enemyPieces            = OccupancyBlack;
            }
            else
            {
                // Black Move
                ownKingSquare          = Bitwise.FindFirstSetBit(BlackKing);
                ownPieces              = OccupancyBlack;
                enemyRankFileAttackers = WhiteRooks | WhiteQueens;
                enemyDiagonalAttackers = WhiteBishops | WhiteQueens;
                enemyPieces            = OccupancyWhite;
            }
            // Find pieces pinned to own king by enemy rank / file attackers.
            PinnedPieces = 0;
            int attackerSquare;

            while ((attackerSquare = Bitwise.FindFirstSetBit(enemyRankFileAttackers)) != Square.Illegal)
            {
                var betweenSquares = Board.RankFileBetweenSquares[attackerSquare][ownKingSquare];
                if (betweenSquares == 0)
                {
                    Bitwise.ClearBit(ref enemyRankFileAttackers, attackerSquare);
                    continue;
                }
                if ((betweenSquares & enemyPieces) == 0)
                {
                    // No enemy pieces between enemy attacker and own king.
                    var potentiallyPinnedPieces = betweenSquares & ownPieces;
                    if (Bitwise.CountSetBits(potentiallyPinnedPieces) == 1)
                    {
                        // Exactly one own piece between enemy attacker and own king.
                        // Piece is pinned to own king.
                        PinnedPieces |= potentiallyPinnedPieces;
                    }
                }
                Bitwise.ClearBit(ref enemyRankFileAttackers, attackerSquare);
            }
            // Find pieces pinned to own king by enemy diagonal attackers.
            while ((attackerSquare = Bitwise.FindFirstSetBit(enemyDiagonalAttackers)) != Square.Illegal)
            {
                var betweenSquares = Board.DiagonalBetweenSquares[attackerSquare][ownKingSquare];
                if (betweenSquares == 0)
                {
                    Bitwise.ClearBit(ref enemyDiagonalAttackers, attackerSquare);
                    continue;
                }
                if ((betweenSquares & enemyPieces) == 0)
                {
                    // No enemy pieces between enemy attacker and own king.
                    var potentiallyPinnedPieces = betweenSquares & ownPieces;
                    if (Bitwise.CountSetBits(potentiallyPinnedPieces) == 1)
                    {
                        // Exactly one own piece between enemy attacker and own king.
                        // Piece is pinned to own king.
                        PinnedPieces |= potentiallyPinnedPieces;
                    }
                }
                Bitwise.ClearBit(ref enemyDiagonalAttackers, attackerSquare);
            }
        }
Example #8
0
        private void GenerateKingMoves(MoveGeneration MoveGeneration, ulong FromSquareMask, ulong ToSquareMask)
        {
            ulong king;
            ulong unOrEnemyOccupiedSquares;
            ulong enemyOccupiedSquares;
            int   attacker;
            bool  castleQueenside;
            ulong castleQueensideMask;
            bool  castleKingside;
            ulong castleKingsideMask;

            if (WhiteMove)
            {
                // White Move
                king = WhiteKing & FromSquareMask;
                unOrEnemyOccupiedSquares = ~OccupancyWhite;
                enemyOccupiedSquares     = OccupancyBlack;
                attacker            = Piece.WhiteKing;
                castleQueenside     = Engine.Castling.WhiteQueenside(Castling);
                castleQueensideMask = Board.WhiteCastleQEmptySquaresMask;
                castleKingside      = Engine.Castling.WhiteKingside(Castling);
                castleKingsideMask  = Board.WhiteCastleKEmptySquaresMask;
            }
            else
            {
                // Black Move
                king = BlackKing & FromSquareMask;
                unOrEnemyOccupiedSquares = ~OccupancyBlack;
                enemyOccupiedSquares     = OccupancyWhite;
                attacker            = Piece.BlackKing;
                castleQueenside     = Engine.Castling.BlackQueenside(Castling);
                castleQueensideMask = Board.BlackCastleQEmptySquaresMask;
                castleKingside      = Engine.Castling.BlackKingside(Castling);
                castleKingsideMask  = Board.BlackCastleKEmptySquaresMask;
            }
            ulong move;
            var   fromSquare = Bitwise.FindFirstSetBit(king);

            if (fromSquare == Square.Illegal)
            {
                return;
            }
            var kingDestinations = MoveGeneration switch
            {
                MoveGeneration.AllMoves => Board.KingMoveMasks[fromSquare] & unOrEnemyOccupiedSquares & ToSquareMask,
                MoveGeneration.OnlyCaptures => Board.KingMoveMasks[fromSquare] & enemyOccupiedSquares & ToSquareMask,
                MoveGeneration.OnlyNonCaptures => Board.KingMoveMasks[fromSquare] & ~Occupancy & ToSquareMask,
                _ => throw new Exception($"{MoveGeneration} move generation not supported.")
            };
            int toSquare;

            while ((toSquare = Bitwise.FindFirstSetBit(kingDestinations)) != Square.Illegal)
            {
                var victim = GetPiece(toSquare);
                move = Move.Null;
                Move.SetFrom(ref move, fromSquare);
                Move.SetTo(ref move, toSquare);
                if (victim != Piece.None)
                {
                    Move.SetCaptureAttacker(ref move, attacker);
                }
                Move.SetCaptureVictim(ref move, victim);
                Move.SetIsKingMove(ref move, true);
                Move.SetIsQuiet(ref move, victim == Piece.None);
                Moves[MoveIndex] = move;
                MoveIndex++;
                Bitwise.ClearBit(ref kingDestinations, toSquare);
            }
            if (MoveGeneration != MoveGeneration.OnlyCaptures)
            {
                if (castleQueenside && ((Occupancy & castleQueensideMask) == 0))
                {
                    // Castle Queenside
                    if (WhiteMove)
                    {
                        // White Move
                        fromSquare = Square.e1;
                        toSquare   = Square.c1;
                    }
                    else
                    {
                        // Black Move
                        fromSquare = Square.e8;
                        toSquare   = Square.c8;
                    }
                    if ((Board.SquareMasks[toSquare] & ToSquareMask) > 0)
                    {
                        move = Move.Null;
                        Move.SetFrom(ref move, fromSquare);
                        Move.SetTo(ref move, toSquare);
                        Move.SetIsCastling(ref move, true);
                        Move.SetIsKingMove(ref move, true);
                        Move.SetIsQuiet(ref move, false);
                        Moves[MoveIndex] = move;
                        MoveIndex++;
                    }
                }
                if (castleKingside && ((Occupancy & castleKingsideMask) == 0))
                {
                    // Castle Kingside
                    if (WhiteMove)
                    {
                        // White Move
                        fromSquare = Square.e1;
                        toSquare   = Square.g1;
                    }
                    else
                    {
                        // Black Move
                        fromSquare = Square.e8;
                        toSquare   = Square.g8;
                    }
                    if ((Board.SquareMasks[toSquare] & ToSquareMask) > 0)
                    {
                        move = Move.Null;
                        Move.SetFrom(ref move, fromSquare);
                        Move.SetTo(ref move, toSquare);
                        Move.SetIsCastling(ref move, true);
                        Move.SetIsKingMove(ref move, true);
                        Move.SetIsQuiet(ref move, false);
                        Moves[MoveIndex] = move;
                        MoveIndex++;
                    }
                }
            }
        }
Example #9
0
        private void GeneratePawnMoves(MoveGeneration MoveGeneration, ulong FromSquareMask, ulong ToSquareMask)
        {
            ulong pawns;

            ulong[] pawnMoveMasks;
            ulong[] pawnDoubleMoveMasks;
            ulong[] pawnAttackMasks;
            ulong   enemyOccupiedSquares;
            var     unoccupiedSquares = ~Occupancy;

            int[] ranks;
            int   attacker;
            int   queen;
            int   rook;
            int   bishop;
            int   knight;
            int   enPassantVictim;

            if (WhiteMove)
            {
                // White Move
                pawns                = WhitePawns & FromSquareMask;
                pawnMoveMasks        = Board.WhitePawnMoveMasks;
                pawnDoubleMoveMasks  = Board.WhitePawnDoubleMoveMasks;
                pawnAttackMasks      = Board.WhitePawnAttackMasks;
                enemyOccupiedSquares = OccupancyBlack;
                ranks                = Board.WhiteRanks;
                attacker             = Piece.WhitePawn;
                queen                = Piece.WhiteQueen;
                rook            = Piece.WhiteRook;
                bishop          = Piece.WhiteBishop;
                knight          = Piece.WhiteKnight;
                enPassantVictim = Piece.BlackPawn;
            }
            else
            {
                // Black Move
                pawns                = BlackPawns & FromSquareMask;
                pawnMoveMasks        = Board.BlackPawnMoveMasks;
                pawnDoubleMoveMasks  = Board.BlackPawnDoubleMoveMasks;
                pawnAttackMasks      = Board.BlackPawnAttackMasks;
                enemyOccupiedSquares = OccupancyWhite;
                ranks                = Board.BlackRanks;
                attacker             = Piece.BlackPawn;
                queen                = Piece.BlackQueen;
                rook            = Piece.BlackRook;
                bishop          = Piece.BlackBishop;
                knight          = Piece.BlackKnight;
                enPassantVictim = Piece.WhitePawn;
            }
            int   fromSquare;
            ulong move;

            if ((EnPassantSquare != Square.Illegal) && ((Board.SquareMasks[EnPassantSquare] & ToSquareMask) > 0) && (MoveGeneration != MoveGeneration.OnlyNonCaptures))
            {
                var enPassantAttackers = Board.EnPassantAttackerMasks[EnPassantSquare] & pawns;
                while ((fromSquare = Bitwise.FindFirstSetBit(enPassantAttackers)) != Square.Illegal)
                {
                    // Capture pawn en passant.
                    move = Move.Null;
                    Move.SetFrom(ref move, fromSquare);
                    Move.SetTo(ref move, EnPassantSquare);
                    Move.SetCaptureAttacker(ref move, attacker);
                    Move.SetCaptureVictim(ref move, enPassantVictim);
                    Move.SetIsEnPassantCapture(ref move, true);
                    Move.SetIsPawnMove(ref move, true);
                    Move.SetIsQuiet(ref move, false);
                    Moves[MoveIndex] = move;
                    MoveIndex++;
                    Bitwise.ClearBit(ref enPassantAttackers, fromSquare);
                }
            }
            while ((fromSquare = Bitwise.FindFirstSetBit(pawns)) != Square.Illegal)
            {
                ulong pawnDestinations;
                int   toSquare;
                int   toSquareRank;
                if (MoveGeneration != MoveGeneration.OnlyCaptures)
                {
                    // Pawns may move forward one square (or two if on initial square) if forward squares are unoccupied.
                    pawnDestinations = pawnMoveMasks[fromSquare] & unoccupiedSquares & ToSquareMask;
                    while ((toSquare = Bitwise.FindFirstSetBit(pawnDestinations)) != Square.Illegal)
                    {
                        var doubleMove = Board.SquareDistances[fromSquare][toSquare] == 2;
                        if (doubleMove && ((Occupancy & pawnDoubleMoveMasks[fromSquare]) > 0))
                        {
                            // Double move is blocked.
                            Bitwise.ClearBit(ref pawnDestinations, toSquare);
                            continue;
                        }
                        toSquareRank = ranks[toSquare];
                        if (toSquareRank < 7)
                        {
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetIsDoublePawnMove(ref move, doubleMove);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, true);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                        }
                        else
                        {
                            // Promote pawn to queen.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, queen);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                            // Promote pawn to rook.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, rook);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                            // Promote pawn to bishop.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, bishop);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                            // Promote pawn to knight.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, knight);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                        }
                        Bitwise.ClearBit(ref pawnDestinations, toSquare);
                    }
                }
                if (MoveGeneration != MoveGeneration.OnlyNonCaptures)
                {
                    // Pawns may attack diagonally forward one square if occupied by enemy.
                    pawnDestinations = pawnAttackMasks[fromSquare] & enemyOccupiedSquares & ToSquareMask;
                    while ((toSquare = Bitwise.FindFirstSetBit(pawnDestinations)) != Square.Illegal)
                    {
                        toSquareRank = ranks[toSquare];
                        var victim = GetPiece(toSquare);
                        if (toSquareRank < 7)
                        {
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetCaptureAttacker(ref move, attacker);
                            Move.SetCaptureVictim(ref move, victim);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                        }
                        else
                        {
                            // Promote pawn to queen.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, queen);
                            Move.SetCaptureAttacker(ref move, attacker);
                            Move.SetCaptureVictim(ref move, victim);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                            // Promote pawn to rook.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, rook);
                            Move.SetCaptureAttacker(ref move, attacker);
                            Move.SetCaptureVictim(ref move, victim);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                            // Promote pawn to bishop.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, bishop);
                            Move.SetCaptureAttacker(ref move, attacker);
                            Move.SetCaptureVictim(ref move, victim);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                            // Promote pawn to knight.
                            move = Move.Null;
                            Move.SetFrom(ref move, fromSquare);
                            Move.SetTo(ref move, toSquare);
                            Move.SetPromotedPiece(ref move, knight);
                            Move.SetCaptureAttacker(ref move, attacker);
                            Move.SetCaptureVictim(ref move, victim);
                            Move.SetIsPawnMove(ref move, true);
                            Move.SetIsQuiet(ref move, false);
                            Moves[MoveIndex] = move;
                            MoveIndex++;
                        }
                        Bitwise.ClearBit(ref pawnDestinations, toSquare);
                    }
                }
                Bitwise.ClearBit(ref pawns, fromSquare);
            }
        }
Example #10
0
        // Move Bits
        // Higher priority moves have higher ulong value.

        // 6 6 6 6 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
        // 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
        // B|CapV   |CapA   |Promo  |Kil|History                                              |!|O|K|E|2|P|C|Q|From         |To
        //                               1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

        // B =     Best Move
        // CapV =  Capture Victim
        // CapA =  Capture Attacker (inverted)
        // Promo = Promoted Piece
        // Kil =   Killer Move
        // ! =     Played
        // O =     Castling
        // K =     King Move
        // E =     En Passant Capture
        // 2 =     Double Pawn Move
        // P =     Pawn Move
        // C =     Check
        // Q =     Quiet (not capture, pawn promotion, castling, or check)
        // From =  From (one extra bit for illegal square)
        // To =    To (one extra bit for illegal square)


        static Move()
        {
            // Create bit masks and shifts.
            _bestShift             = 63;
            _bestMask              = Bitwise.CreateULongMask(63);
            _bestUnmask            = Bitwise.CreateULongUnmask(63);
            _captureVictimShift    = 59;
            _captureVictimMask     = Bitwise.CreateULongMask(59, 62);
            _captureVictimUnmask   = Bitwise.CreateULongUnmask(59, 62);
            _captureAttackerShift  = 55;
            _captureAttackerMask   = Bitwise.CreateULongMask(55, 58);
            _captureAttackerUnmask = Bitwise.CreateULongUnmask(55, 58);
            _promotedPieceShift    = 51;
            _promotedPieceMask     = Bitwise.CreateULongMask(51, 54);
            _promotedPieceUnmask   = Bitwise.CreateULongUnmask(51, 54);
            _killerShift           = 49;
            _killerMask            = Bitwise.CreateULongMask(49, 50);
            _killerUnmask          = Bitwise.CreateULongUnmask(49, 50);
            _historyShift          = 22;
            _historyMask           = Bitwise.CreateULongMask(22, 48);
            _historyUnmask         = Bitwise.CreateULongUnmask(22, 48);
            _playedShift           = 21;
            _playedMask            = Bitwise.CreateULongMask(21);
            _playedUnmask          = Bitwise.CreateULongUnmask(21);
            _castlingShift         = 20;
            _castlingMask          = Bitwise.CreateULongMask(20);
            _castlingUnmask        = Bitwise.CreateULongUnmask(20);
            _kingMoveShift         = 19;
            _kingMoveMask          = Bitwise.CreateULongMask(19);
            _kingMoveUnmask        = Bitwise.CreateULongUnmask(19);
            _enPassantShift        = 18;
            _enPassantMask         = Bitwise.CreateULongMask(18);
            _enPassantUnmask       = Bitwise.CreateULongUnmask(18);
            _doublePawnMoveShift   = 17;
            _doublePawnMoveMask    = Bitwise.CreateULongMask(17);
            _doublePawnMoveUnmask  = Bitwise.CreateULongUnmask(17);
            _pawnMoveShift         = 16;
            _pawnMoveMask          = Bitwise.CreateULongMask(16);
            _pawnMoveUnmask        = Bitwise.CreateULongUnmask(16);
            _checkShift            = 15;
            _checkMask             = Bitwise.CreateULongMask(15);
            _checkUnmask           = Bitwise.CreateULongUnmask(15);
            _quietShift            = 14;
            _quietMask             = Bitwise.CreateULongMask(14);
            _quietUnmask           = Bitwise.CreateULongUnmask(14);
            _fromShift             = 7;
            _fromMask              = Bitwise.CreateULongMask(7, 13);
            _fromUnmask            = Bitwise.CreateULongUnmask(7, 13);
            _toMask   = Bitwise.CreateULongMask(0, 6);
            _toUnmask = Bitwise.CreateULongUnmask(0, 6);
            // Set null move.
            Null = 0;
            SetIsBest(ref Null, false);
            SetCaptureVictim(ref Null, Piece.None);
            SetCaptureAttacker(ref Null, Piece.None);
            SetPromotedPiece(ref Null, Piece.None);
            SetKiller(ref Null, 0);
            SetHistory(ref Null, 0);
            SetPlayed(ref Null, false);
            SetIsCastling(ref Null, false);
            SetIsKingMove(ref Null, false);
            SetIsEnPassantCapture(ref Null, false);
            SetIsDoublePawnMove(ref Null, false);
            SetIsPawnMove(ref Null, false);
            SetIsCheck(ref Null, false);
            SetIsQuiet(ref Null, false);
            SetFrom(ref Null, Square.Illegal);
            SetTo(ref Null, Square.Illegal);
        }
Example #11
0
        public void FindMagicMultipliers(int Piece, Delegates.WriteMessageLine WriteMessageLine = null)
        {
            Direction[] directions;
            ulong[]     unoccupiedMoveMasks;
            ulong[]     relevantOccupancyMasks;
            ulong[]     magicMultipliers;
            int[]       shifts;
            ulong[][]   moveMasks;
            switch (Piece)
            {
            case Engine.Piece.WhiteBishop:
            case Engine.Piece.BlackBishop:
                directions             = new[] { Direction.NorthEast, Direction.SouthEast, Direction.SouthWest, Direction.NorthWest };
                unoccupiedMoveMasks    = Board.BishopMoveMasks;
                relevantOccupancyMasks = _bishopRelevantOccupancyMasks;
                magicMultipliers       = _bishopMagicMultipliers;
                shifts    = _bishopShifts;
                moveMasks = _bishopMoveMasks;
                break;

            case Engine.Piece.WhiteRook:
            case Engine.Piece.BlackRook:
                directions             = new[] { Direction.North, Direction.East, Direction.South, Direction.West };
                unoccupiedMoveMasks    = Board.RookMoveMasks;
                relevantOccupancyMasks = _rookRelevantOccupancyMasks;
                magicMultipliers       = _rookMagicMultipliers;
                shifts    = _rookShifts;
                moveMasks = _rookMoveMasks;
                break;

            default:
                throw new ArgumentException($"{Piece} piece not supported.");
            }
            // Generate moves mask on each square.
            var occupancyToMovesMask = new Dictionary <ulong, ulong>();
            var uniqueMovesMasks     = new HashSet <ulong>();

            for (var square = 0; square < 64; square++)
            {
                occupancyToMovesMask.Clear();
                uniqueMovesMasks.Clear();
                var moveDestinations         = unoccupiedMoveMasks[square];
                var relevantMoveDestinations = moveDestinations & relevantOccupancyMasks[square];
                var uniqueOccupancies        = (int)Math.Pow(2, Bitwise.CountSetBits(relevantMoveDestinations));
                occupancyToMovesMask.EnsureCapacity(uniqueOccupancies);
                // Generate moves mask for every permutation of relevant occupancy bits.
                using (var occupancyPermutations = Bitwise.GetAllPermutations(relevantMoveDestinations).GetEnumerator())
                {
                    while (occupancyPermutations.MoveNext())
                    {
                        var occupancy = occupancyPermutations.Current;
                        if (!occupancyToMovesMask.ContainsKey(occupancy))
                        {
                            // Have not yet generated moves for this occupancy mask.
                            var movesMask = Board.CreateMoveDestinationsMask(square, occupancy, directions);
                            occupancyToMovesMask.Add(occupancy, movesMask);
                            if (!uniqueMovesMasks.Contains(movesMask))
                            {
                                uniqueMovesMasks.Add(movesMask);
                            }
                        }
                    }
                }
                // Validate enumerator found all permutations of relevant occupancy bits.
                Debug.Assert(occupancyToMovesMask.Count == uniqueOccupancies);
                // Determine bit shift that produces number >= unique occupancies.
                // A stricter condition is number >= unique moves but this requires more computing time to find magic multipliers.
                var shift = 64 - (int)Math.Ceiling(Math.Log(uniqueOccupancies, 2d));
                shifts[square] = shift;
                var magicMultiplier = magicMultipliers[square];
                if (magicMultiplier == 0)
                {
                    (magicMultipliers[square], moveMasks[square]) = FindMagicMultiplier(occupancyToMovesMask, shift, null);
                }
                else
                {
                    (magicMultipliers[square], moveMasks[square]) = FindMagicMultiplier(occupancyToMovesMask, shift, magicMultiplier);
                }
                WriteMessageLine?.Invoke($"{Board.SquareLocations[square],6}  {Engine.Piece.GetName(Piece),6}  {shift,5}  {occupancyToMovesMask.Count,18}  {uniqueMovesMasks.Count,12}  {magicMultipliers[square],16:X16}");
            }
        }