public void FindMagicMultipliers(ColorlessPiece colorlessPiece, Delegates.WriteMessageLine writeMessageLine = null)
    {
        Direction[] directions;
        ulong[]     unoccupiedMoveMasks;
        ulong[]     relevantOccupancyMasks;
        ulong[]     magicMultipliers;
        int[]       shifts;
        ulong[][]   moveMasks;
        // ReSharper disable SwitchStatementHandlesSomeKnownEnumValuesWithDefault
        switch (colorlessPiece)
        {
        case ColorlessPiece.Bishop:
            directions             = new[] { Direction.NorthEast, Direction.SouthEast, Direction.SouthWest, Direction.NorthWest };
            unoccupiedMoveMasks    = Board.BishopMoveMasks;
            relevantOccupancyMasks = _bishopRelevantOccupancyMasks;
            magicMultipliers       = _bishopMagicMultipliers;
            shifts    = _bishopShifts;
            moveMasks = _bishopMoveMasks;
            break;

        case ColorlessPiece.Rook:
            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($"{colorlessPiece} piece not supported.");
        }
        // ReSharper restore SwitchStatementHandlesSomeKnownEnumValuesWithDefault
        // Generate moves mask on each square.
        var occupancyToMovesMask = new Dictionary <ulong, ulong>();
        var uniqueMovesMasks     = new HashSet <ulong>();

        for (var square = Square.A8; square < Square.Illegal; square++)
        {
            occupancyToMovesMask.Clear();
            uniqueMovesMasks.Clear();
            var moveDestinations         = unoccupiedMoveMasks[(int)square];
            var relevantMoveDestinations = moveDestinations & relevantOccupancyMasks[(int)square];
            var uniqueOccupancies        = (int)Math.Pow(2, Bitwise.CountSetBits(relevantMoveDestinations));
            occupancyToMovesMask.EnsureCapacity(uniqueOccupancies);
            // Generate moves mask for every permutation of occupancy of the relevant destination squares.
            var occupancyPermutations = Bitwise.GetAllPermutations(relevantMoveDestinations);
            for (var occupancyIndex = 0; occupancyIndex < occupancyPermutations.Count; occupancyIndex++)
            {
                var occupancy = occupancyPermutations[occupancyIndex];
                var movesMask = Board.CreateMoveDestinationsMask(square, occupancy, directions);
                occupancyToMovesMask.Add(occupancy, movesMask);
                if (!uniqueMovesMasks.Contains(movesMask))
                {
                    uniqueMovesMasks.Add(movesMask);
                }
            }
            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[(int)square] = shift;
            var magicMultiplier      = magicMultipliers[(int)square];
            var knownMagicMultiplier = magicMultiplier == 0 ? null : (ulong?)magicMultiplier;
            (magicMultipliers[(int)square], moveMasks[(int)square]) = FindMagicMultiplier(occupancyToMovesMask, shift, knownMagicMultiplier);
            writeMessageLine?.Invoke($"{Board.SquareLocations[(int)square],6}  {PieceHelper.GetName(colorlessPiece),6}  {shift,5}  {occupancyToMovesMask.Count,18}  {uniqueMovesMasks.Count,12}  {magicMultipliers[(int)square],16:X16}");
        }
    }
Exemple #2
0
 [MethodImpl(MethodImplOptions.AggressiveInlining)] public ulong GetPieces(ColorlessPiece piece) => PieceBitboards[(int)piece] | PieceBitboards[(int)piece + (int)Piece.WhiteKing];