// 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)); }