const int BitTable[64] = {
63, 30, 3, 32, 25, 41, 22, 33, 15, 50, 42, 13, 11, 53, 19, 34, 61, 29, 2,
51, 21, 43, 45, 10, 18, 47, 1, 54, 9, 57, 0, 35, 62, 31, 40, 4, 49, 5, 52,
26, 60, 6, 23, 44, 46, 27, 56, 16, 7, 39, 48, 24, 59, 14, 12, 55, 38, 28,
58, 20, 37, 17, 36, 8
};
int pop_1st_bit(uint64 *bb) {
uint64 b = *bb ^ (*bb - 1);
unsigned int fold = (unsigned) ((b & 0xffffffff) ^ (b >> 32));
*bb &= (*bb - 1);
return BitTable[(fold * 0x783a9b23) >> 26];
}
uint64 index_to_uint64(int index, int bits, uint64 m) {
int i, j;
uint64 result = 0ULL;
for(i = 0; i < bits; i++) {
j = pop_1st_bit(&m);
if(index & (1 << i)) result |= (1ULL << j);
}
return result;
}
Это из Wiki по программированию шахмат:
https://www.chessprogramming.org/Looking_for_Magics
Это часть некоторого кода для поиска магических чисел.
Аргумент uint64 m
- это битборд, представляющий возможные блокированные квадраты для хода ладьи или слона. Пример ладьи на поле е4:
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 1 1 1 0 1 1 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0
Квадратные ребра равны нулю, потому что они всегда блокируют, и уменьшение количества необходимых битов, по-видимому, полезно.
/* Bitboard, LSB to MSB, a1 through h8:
* 56 - - - - - - 63
* - - - - - - - -
* - - - - - - - -
* - - - - - - - -
* - - - - - - - -
* - - - - - - - -
* - - - - - - - -
* 0 - - - - - - 7
*/
Таким образом, в приведенном выше примере index_to_uint64
принимает индекс (от 0 до 2 ^ бит), а также количество битов, установленных в битовой доске (10) и битовой доске.
Затем это pops_1st_bit
для каждого количества битов, за которым следует еще один сдвинутый бит кода. pops_1st_bit
XOR - это битборд с самим собой минус один (почему?). Затем он с полными 32-битными битами, и где-то здесь мой мозг исчерпывает ОЗУ. Каким-то образом задействовано магическое шестнадцатеричное число 0x783a9b23 (это последовательность чисел из Lost?). И есть этот нелепый загадочный массив случайно упорядоченных чисел от 0 до 63 (BitTable[64]
).