예제 #1
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);
            }
        }
예제 #2
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}");
            }
        }