// 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.
        public static void init_magics(PieceType pt, Bitboard[][] attacks, Bitboard[] magics,
                                       Bitboard[] masks, uint[] shifts, Square[] deltas, Fn index)
        {
            int[][] MagicBoosters = new int[2][] {
                new int[] { 969, 1976, 2850, 542, 2069, 2852, 1708, 164 },
                new int[] { 3101, 552, 3555, 926, 834, 26, 2131, 1117 }
            };

            RKISS rk = new RKISS();

            Bitboard[] occupancy = new UInt64[4096], reference = new UInt64[4096];
            Bitboard   edges, b;
            int        i, size, booster;

            for (Square s = SquareS.SQ_A1; s <= SquareS.SQ_H8; s++)
            {
                // Board edges are not considered in the relevant occupancies
                edges = ((BitBoard.Rank1BB | BitBoard.Rank8BB) & ~BitBoard.rank_bb_square(s)) | ((BitBoard.FileABB | BitBoard.FileHBB) & ~BitBoard.file_bb_square(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, 0) & ~edges;
                shifts[s] = 32 - (uint)Bitcount.popcount_Max15(masks[s]);

                // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
                // store the corresponding sliding attack bitboard in reference[].
                b    = 0;
                size = 0;
                do
                {
                    occupancy[size] = b;
                    reference[size] = sliding_attack(deltas, s, b);
                    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 Bitboard[size];
                booster    = MagicBoosters[0][Types.rank_of(s)];

                // Find a magic for square 's' picking up an (almost) random number
                // until we find the one that passes the verification test.
                do
                {
                    do
                    {
                        magics[s] = rk.magic_rand(booster);
                    }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 (i = 0; i < size; i++)
                    {
                        Bitboard attack = attacks[s][index(s, occupancy[i], pt)];

                        if (attack != 0 && attack != reference[i])
                        {
                            break;
                        }

                        Debug.Assert(reference[i] != 0);

                        //attack = reference[i];
                        attacks[s][index(s, occupancy[i], pt)] = reference[i];
                    }
                } while (i != size);
            }
        }
 public PolyglotBook()
 {
     RKiss = new RKISS((int)(Time.now() % 1000));
 }