コード例 #1
0
    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}");
        }
    }
コード例 #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}");
            }
        }