@@ -54,10 +54,150 @@ namespace {
54
54
55
55
int MSBTable[256 ]; // To implement software msb()
56
56
Square BSFTable[SQUARE_NB]; // To implement software bitscan
57
- Bitboard RookTable[0x19000 ]; // To store rook attacks
58
- Bitboard BishopTable[0x1480 ]; // To store bishop attacks
59
57
60
- void init_magics (Bitboard table[], Magic magics[], Direction directions[]);
58
+ Bitboard AttackTable[HasPext ? 107648 : 88772 ] = { 0 };
59
+
60
+ struct MagicInit {
61
+ Bitboard magic;
62
+ unsigned offset;
63
+ };
64
+
65
+ MagicInit BishopMagicInit[SQUARE_NB] = {
66
+ { 0x007fbfbfbfbfbfffu , 5378 },
67
+ { 0x0000a060401007fcu , 4093 },
68
+ { 0x0001004008020000u , 4314 },
69
+ { 0x0000806004000000u , 6587 },
70
+ { 0x0000100400000000u , 6491 },
71
+ { 0x000021c100b20000u , 6330 },
72
+ { 0x0000040041008000u , 5609 },
73
+ { 0x00000fb0203fff80u , 22236 },
74
+ { 0x0000040100401004u , 6106 },
75
+ { 0x0000020080200802u , 5625 },
76
+ { 0x0000004010202000u , 16785 },
77
+ { 0x0000008060040000u , 16817 },
78
+ { 0x0000004402000000u , 6842 },
79
+ { 0x0000000801008000u , 7003 },
80
+ { 0x000007efe0bfff80u , 4197 },
81
+ { 0x0000000820820020u , 7356 },
82
+ { 0x0000400080808080u , 4602 },
83
+ { 0x00021f0100400808u , 4538 },
84
+ { 0x00018000c06f3fffu , 29531 },
85
+ { 0x0000258200801000u , 45393 },
86
+ { 0x0000240080840000u , 12420 },
87
+ { 0x000018000c03fff8u , 15763 },
88
+ { 0x00000a5840208020u , 5050 },
89
+ { 0x0000020008208020u , 4346 },
90
+ { 0x0000804000810100u , 6074 },
91
+ { 0x0001011900802008u , 7866 },
92
+ { 0x0000804000810100u , 32139 },
93
+ { 0x000100403c0403ffu , 57673 },
94
+ { 0x00078402a8802000u , 55365 },
95
+ { 0x0000101000804400u , 15818 },
96
+ { 0x0000080800104100u , 5562 },
97
+ { 0x00004004c0082008u , 6390 },
98
+ { 0x0001010120008020u , 7930 },
99
+ { 0x000080809a004010u , 13329 },
100
+ { 0x0007fefe08810010u , 7170 },
101
+ { 0x0003ff0f833fc080u , 27267 },
102
+ { 0x007fe08019003042u , 53787 },
103
+ { 0x003fffefea003000u , 5097 },
104
+ { 0x0000101010002080u , 6643 },
105
+ { 0x0000802005080804u , 6138 },
106
+ { 0x0000808080a80040u , 7418 },
107
+ { 0x0000104100200040u , 7898 },
108
+ { 0x0003ffdf7f833fc0u , 42012 },
109
+ { 0x0000008840450020u , 57350 },
110
+ { 0x00007ffc80180030u , 22813 },
111
+ { 0x007fffdd80140028u , 56693 },
112
+ { 0x00020080200a0004u , 5818 },
113
+ { 0x0000101010100020u , 7098 },
114
+ { 0x0007ffdfc1805000u , 4451 },
115
+ { 0x0003ffefe0c02200u , 4709 },
116
+ { 0x0000000820806000u , 4794 },
117
+ { 0x0000000008403000u , 13364 },
118
+ { 0x0000000100202000u , 4570 },
119
+ { 0x0000004040802000u , 4282 },
120
+ { 0x0004010040100400u , 14964 },
121
+ { 0x00006020601803f4u , 4026 },
122
+ { 0x0003ffdfdfc28048u , 4826 },
123
+ { 0x0000000820820020u , 7354 },
124
+ { 0x0000000008208060u , 4848 },
125
+ { 0x0000000000808020u , 15946 },
126
+ { 0x0000000001002020u , 14932 },
127
+ { 0x0000000401002008u , 16588 },
128
+ { 0x0000004040404040u , 6905 },
129
+ { 0x007fff9fdf7ff813u , 16076 }
130
+ };
131
+
132
+ MagicInit RookMagicInit[SQUARE_NB] = {
133
+ { 0x00280077ffebfffeu , 26304 },
134
+ { 0x2004010201097fffu , 35520 },
135
+ { 0x0010020010053fffu , 38592 },
136
+ { 0x0040040008004002u , 8026 },
137
+ { 0x7fd00441ffffd003u , 22196 },
138
+ { 0x4020008887dffffeu , 80870 },
139
+ { 0x004000888847ffffu , 76747 },
140
+ { 0x006800fbff75fffdu , 30400 },
141
+ { 0x000028010113ffffu , 11115 },
142
+ { 0x0020040201fcffffu , 18205 },
143
+ { 0x007fe80042ffffe8u , 53577 },
144
+ { 0x00001800217fffe8u , 62724 },
145
+ { 0x00001800073fffe8u , 34282 },
146
+ { 0x00001800e05fffe8u , 29196 },
147
+ { 0x00001800602fffe8u , 23806 },
148
+ { 0x000030002fffffa0u , 49481 },
149
+ { 0x00300018010bffffu , 2410 },
150
+ { 0x0003000c0085fffbu , 36498 },
151
+ { 0x0004000802010008u , 24478 },
152
+ { 0x0004002020020004u , 10074 },
153
+ { 0x0001002002002001u , 79315 },
154
+ { 0x0001001000801040u , 51779 },
155
+ { 0x0000004040008001u , 13586 },
156
+ { 0x0000006800cdfff4u , 19323 },
157
+ { 0x0040200010080010u , 70612 },
158
+ { 0x0000080010040010u , 83652 },
159
+ { 0x0004010008020008u , 63110 },
160
+ { 0x0000040020200200u , 34496 },
161
+ { 0x0002008010100100u , 84966 },
162
+ { 0x0000008020010020u , 54341 },
163
+ { 0x0000008020200040u , 60421 },
164
+ { 0x0000820020004020u , 86402 },
165
+ { 0x00fffd1800300030u , 50245 },
166
+ { 0x007fff7fbfd40020u , 76622 },
167
+ { 0x003fffbd00180018u , 84676 },
168
+ { 0x001fffde80180018u , 78757 },
169
+ { 0x000fffe0bfe80018u , 37346 },
170
+ { 0x0001000080202001u , 370 },
171
+ { 0x0003fffbff980180u , 42182 },
172
+ { 0x0001fffdff9000e0u , 45385 },
173
+ { 0x00fffefeebffd800u , 61659 },
174
+ { 0x007ffff7ffc01400u , 12790 },
175
+ { 0x003fffbfe4ffe800u , 16762 },
176
+ { 0x001ffff01fc03000u , 0 },
177
+ { 0x000fffe7f8bfe800u , 38380 },
178
+ { 0x0007ffdfdf3ff808u , 11098 },
179
+ { 0x0003fff85fffa804u , 21803 },
180
+ { 0x0001fffd75ffa802u , 39189 },
181
+ { 0x00ffffd7ffebffd8u , 58628 },
182
+ { 0x007fff75ff7fbfd8u , 44116 },
183
+ { 0x003fff863fbf7fd8u , 78357 },
184
+ { 0x001fffbfdfd7ffd8u , 44481 },
185
+ { 0x000ffff810280028u , 64134 },
186
+ { 0x0007ffd7f7feffd8u , 41759 },
187
+ { 0x0003fffc0c480048u , 1394 },
188
+ { 0x0001ffffafd7ffd8u , 40910 },
189
+ { 0x00ffffe4ffdfa3bau , 66516 },
190
+ { 0x007fffef7ff3d3dau , 3897 },
191
+ { 0x003fffbfdfeff7fau , 3930 },
192
+ { 0x001fffeff7fbfc22u , 72934 },
193
+ { 0x0000020408001001u , 72662 },
194
+ { 0x0007fffeffff77fdu , 56325 },
195
+ { 0x0003ffffbf7dfeecu , 66501 },
196
+ { 0x0001ffff9dffa333u , 14826 }
197
+ };
198
+
199
+ Bitboard relevant_occupancies (Direction directions[], Square s);
200
+ void init_magics (MagicInit init[], Magic magics[], Direction directions[], unsigned shift);
61
201
62
202
// bsf_index() returns the index into BSFTable[] to look up the bitscan. Uses
63
203
// Matt Taylor's folding for 32 bit case, extended to 64 bit by Kim Walisch.
@@ -205,8 +345,25 @@ void Bitboards::init() {
205
345
Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
206
346
Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
207
347
208
- init_magics (RookTable, RookMagics, RookDirections);
209
- init_magics (BishopTable, BishopMagics, BishopDirections);
348
+ if (HasPext)
349
+ {
350
+ unsigned offset = 0 ;
351
+
352
+ for (Square s = SQ_A1; s <= SQ_H8; ++s)
353
+ {
354
+ RookMagicInit[s].offset = offset;
355
+ offset += 1 << popcount (relevant_occupancies (RookDirections, s));
356
+ }
357
+
358
+ for (Square s = SQ_A1; s <= SQ_H8; ++s)
359
+ {
360
+ BishopMagicInit[s].offset = offset;
361
+ offset += 1 << popcount (relevant_occupancies (BishopDirections, s));
362
+ }
363
+ }
364
+
365
+ init_magics (RookMagicInit, RookMagics, RookDirections, 12 );
366
+ init_magics (BishopMagicInit, BishopMagics, BishopDirections, 9 );
210
367
211
368
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
212
369
{
@@ -270,84 +427,35 @@ namespace {
270
427
return attack;
271
428
}
272
429
430
+ Bitboard relevant_occupancies (Direction directions[], Square s) {
273
431
274
- // init_magics() computes all rook and bishop attacks at startup. Magic
275
- // bitboards are used to look up attacks of sliding pieces. As a reference see
276
- // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
277
- // use the so called "fancy" approach.
278
-
279
- void init_magics (Bitboard table[], Magic magics[], Direction directions[]) {
432
+ Bitboard edges = ((Rank1BB | Rank8BB) & ~rank_bb (s)) | ((FileABB | FileHBB) & ~file_bb (s));
433
+ return sliding_attack (directions, s, 0 ) & ~edges;
434
+ }
280
435
281
- // Optimal PRNG seeds to pick the correct magics in the shortest time
282
- int seeds[][RANK_NB] = { { 8977 , 44560 , 54343 , 38998 , 5731 , 95205 , 104912 , 17020 },
283
- { 728 , 10316 , 55013 , 32803 , 12281 , 15100 , 16645 , 255 } };
436
+ // Magic bitboards are used to look up attacks of sliding pieces.
437
+ // init_magics() initializes the attack tables from precomputed fixed shift
438
+ // magics with overlapping index ranges:
439
+ // <https://chessprogramming.wikispaces.com/Magic+Bitboards#FixedShiftFancy>
284
440
285
- Bitboard occupancy[4096 ], reference[4096 ], edges, b;
286
- int epoch[4096 ] = {}, cnt = 0 , size = 0 ;
441
+ void init_magics (MagicInit init[], Magic magics[], Direction directions[], unsigned shift) {
287
442
288
443
for (Square s = SQ_A1; s <= SQ_H8; ++s)
289
444
{
290
- // Board edges are not considered in the relevant occupancies
291
- edges = ((Rank1BB | Rank8BB) & ~rank_bb (s)) | ((FileABB | FileHBB) & ~file_bb (s));
292
-
293
- // Given a square 's', the mask is the bitboard of sliding attacks from
294
- // 's' computed on an empty board. The index must be big enough to contain
295
- // all the attacks for each possible subset of the mask and so is 2 power
296
- // the number of 1s of the mask. Hence we deduce the size of the shift to
297
- // apply to the 64 or 32 bits word to get the index.
298
445
Magic& m = magics[s];
299
- m.mask = sliding_attack (directions, s, 0 ) & ~edges;
300
- m.shift = (Is64Bit ? 64 : 32 ) - popcount (m.mask );
301
446
302
- // Set the offset for the attacks table of the square. We have individual
303
- // table sizes for each square with "Fancy Magic Bitboards".
304
- m.attacks = s == SQ_A1 ? table : magics[s - 1 ]. attacks + size ;
447
+ m. magic = init[s]. magic ;
448
+ m. mask = relevant_occupancies (directions, s);
449
+ m.attacks = AttackTable + init[s]. offset ;
305
450
306
- // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
307
- // store the corresponding sliding attack bitboard in reference[].
308
- b = size = 0 ;
451
+ Bitboard b = 0 ;
309
452
do {
310
- occupancy[size] = b;
311
- reference[size] = sliding_attack (directions, s, b);
312
-
313
- if (HasPext)
314
- m.attacks [pext (b, m.mask )] = reference[size];
315
-
316
- size++;
453
+ unsigned idx = HasPext ? pext (b, m.mask ) : (m.magic * b) >> (64 - shift);
454
+ Bitboard attack = sliding_attack (directions, s, b);
455
+ assert (!m.attacks [idx] || m.attacks [idx] == attack);
456
+ m.attacks [idx] = attack;
317
457
b = (b - m.mask ) & m.mask ;
318
458
} while (b);
319
-
320
- if (HasPext)
321
- continue ;
322
-
323
- PRNG rng (seeds[Is64Bit][rank_of (s)]);
324
-
325
- // Find a magic for square 's' picking up an (almost) random number
326
- // until we find the one that passes the verification test.
327
- for (int i = 0 ; i < size; )
328
- {
329
- for (m.magic = 0 ; popcount ((m.magic * m.mask ) >> 56 ) < 6 ; )
330
- m.magic = rng.sparse_rand <Bitboard>();
331
-
332
- // A good magic must map every possible occupancy to an index that
333
- // looks up the correct sliding attack in the attacks[s] database.
334
- // Note that we build up the database for square 's' as a side
335
- // effect of verifying the magic. Keep track of the attempt count
336
- // and save it in epoch[], little speed-up trick to avoid resetting
337
- // m.attacks[] after every failed attempt.
338
- for (++cnt, i = 0 ; i < size; ++i)
339
- {
340
- unsigned idx = m.index (occupancy[i]);
341
-
342
- if (epoch[idx] < cnt)
343
- {
344
- epoch[idx] = cnt;
345
- m.attacks [idx] = reference[i];
346
- }
347
- else if (m.attacks [idx] != reference[i])
348
- break ;
349
- }
350
- }
351
459
}
352
460
}
353
461
}
0 commit comments