【发布时间】:2015-06-06 08:16:01
【问题描述】:
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;
}
来自国际象棋编程维基:
https://www.chessprogramming.org/Looking_for_Magics
这是查找magic numbers 的一些代码的一部分。
参数uint64 m 是一个bitboard,表示车或象移动可能的阻塞方格。以 e4 方格上的车为例:
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^bits),位板中设置的位数(10),以及位板。
然后pops_1st_bit 对应每个位数,然后是另一个移位的代码位。 pops_1st_bit 将位板与自身减一进行异或(为什么?)。然后它与一个完整的 32 位进行 AND 运算,我的大脑在这里的某个地方耗尽了 RAM。不知何故,神奇的十六进制数字 0x783a9b23 被牵扯进来(这是《迷失》中的数字序列吗?)。还有这个由 0-63 随机排列的数字组成的荒谬神秘数组 (BitTable[64])。
【问题讨论】:
-
对于喜欢冒险的人来说,这是一篇有用的文章——vicki-chess.blogspot.com/2013/04/magics.html——我认为有问题的代码正在计算第 2 步,尽管我没有不明白怎么做。
-
pop_1st_bit取消设置最低位并返回其索引 -
数字 0x783a9b23 是素数,因此使 BitTable 成为哈希。您可能最好将其视为黑匣子,只注意“if number in = x then number out = y”。
-
-
该代码似乎是基于 deBruijn 序列的方法的变体,用于查找数字的 LSB。我不确定这个常数是如何工作的。从外观上看,这种方法的发明者马特泰勒(Matt Taylor)也没有(或者至少在他发现它时没有回来)groups.google.com/forum/#!topic/comp.lang.asm.x86/3pVGzQGb1ys。顺便说一句,Droidfish implements this 在 64 位机器上使用 deBruijn 序列,在 32 位机器上回退到上述序列。
标签: c bit-manipulation chess