Пример #1
0
    // init_magics() computes all rook and bishop attacks at startup. Magic
    // bitboards are used to look up attacks of sliding pieces. As a reference see
    // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
    // use the so called "fancy" approach.

    private static void init_magics(
        BitboardT[][] attacks,
        BitboardT[] magics,
        BitboardT[] masks,
        uint[] shifts,
        SquareT[] deltas,
        Utils.Fn index)
    {
        int[][] seeds =
        {
            new[] {8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020},
            new[] {728, 10316, 55013, 32803, 12281, 15100, 16645, 255}
        };

        var occupancy = new BitboardT[4096];
        var reference = new BitboardT[4096];

        var age = new int[4096];
        int current = 0;

        for (var s = Square.SQ_A1; s <= Square.SQ_H8; ++s)
        {
            // Board edges are not considered in the relevant occupancies
            var edges = ((Bitboard.Rank1BB | Bitboard.Rank8BB) & ~Utils.rank_bb_St(s)
                              | ((Bitboard.FileABB | Bitboard.FileHBB) & ~Utils.file_bb_St(s)));

            // Given a square 's', the mask is the bitboard of sliding attacks from
            // 's' computed on an empty board. The index must be big enough to contain
            // all the attacks for each possible subset of the mask and so is 2 power
            // the number of 1s of the mask. Hence we deduce the size of the shift to
            // apply to the 64 or 32 bits word to get the index.
            masks[s] = sliding_attack(deltas, s, Bitboard.Create(0)) & ~edges;

#if X64
            shifts[(int)s] = (uint) (64 - Bitcount.popcount_Max15(masks[(int)s]));
#else
            shifts[s] = (uint)(32 - Bitcount.popcount_Max15(masks[s]));
#endif

            // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
            // store the corresponding sliding attack bitboard in reference[].
            var b = Bitboard.Create(0);
            var size = 0;
            do
            {
                occupancy[size] = b;
                reference[size] = sliding_attack(deltas, s, b);

                // if (HasPext)
                // attacks[s][pext(b, masks[s])] = reference[size];

                size++;
                b = (b - masks[s]) & masks[s];
            } while (b != 0);

            // Set the offset for the table of the next square. We have individual
            // table sizes for each square with "Fancy Magic Bitboards".
            attacks[s] = new BitboardT[size];

            // if (HasPext)
            //  continue;

#if X64
            var rng = new PRNG((ulong) seeds[1][(int)Square.rank_of(s)]);
#else
            var rng = new PRNG((ulong)seeds[0][Square.rank_of(s)]);
#endif

            // Find a magic for square 's' picking up an (almost) random number
            // until we find the one that passes the verification test.
            int i;
            do
            {
                do
                {
                    magics[s] = Bitboard.Create(rng.sparse_rand());
                }
                while (Bitcount.popcount_Max15((magics[s]*masks[s]) >> 56) < 6);
            
                Array.Clear(attacks[s], 0, size);

                // A good magic must map every possible occupancy to an index that
                // looks up the correct sliding attack in the attacks[s] database.
                // Note that we build up the database for square 's' as a side
                // effect of verifying the magic.
                for (++current, i = 0; i < size; ++i)
                {
                    var idx = index(s, occupancy[i]);

                    if (age[idx] < current)
                    {
                        age[idx] = current;
                        attacks[s][idx] = reference[i];
                    }
                    else if (attacks[s][idx] != reference[i])
                    {
                        break;
                    }
                }
            } while (i < size);
        }
    }