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}"); } }
[MethodImpl(MethodImplOptions.AggressiveInlining)] public ulong GetPieces(ColorlessPiece piece) => PieceBitboards[(int)piece] | PieceBitboards[(int)piece + (int)Piece.WhiteKing];