识别棋盘上的棋子
当棋盘存放在各种棋盘上时,现代象棋引擎如何识别哪种类型/侧面棋子位于特定的单元上? 我在这方面遇到了问题,因为要找出某个特定位置是什么类型/边框,我必须始终这样做:
if((bit_check & occupied) == 0ULL) ... // empty
else if((bit_check & white) != 0ULL) // white
if((bit_check & white_pawns) != 0ULL) ... // white pawns
else if((bit_check & white_rooks) != 0ULL) ... // white rooks
....
else if((bit_check & white_kings) != 0ULL) ... // white kings
else if((bit_check & black) != 0ULL) // black
if((bit_check & black_pawns) != 0ULL) ... // black pawns
....
else if((bit_check) & black_kings) != 0ULL) ... // black kings
这是一个非常乏味的过程,它必须进行很多次(例如,在移动生成过程中才能看到捕获的内容)。 我不确定我是否应该继续这样做,还是仅仅创建一个Piece[64]
类型的64阵列会更快,这将会固有地存储片类型。
考虑到它必须达到数百万次,搜索功能中的捕获分析才会更好。 我做错了吗?
位检查本身很快; 我主要担心分支。
相反,考虑uint64_t bitboards[12]
作为所有棋子的12个棋盘阵列。 这在内存中是连续的,可以循环扫描:
for (int i = 0; i != 12; ++i)
{
if (bitboards[i] && bit_check) return i;
}
return -1; // empty.
分支预测器只有两个分支(循环和检查)更容易,而连续内存优化了预取器。
显而易见的变化是仅检查白片的位置[0]至[5],而仅检测黑片的位置[6]至[11]。
更微妙的变体:
uint64_t bitboards[13];
bitboards[12] = ~uint64_t(0);
for (int i = 0; /* NO TEST*/ ; ++i)
{
if (bitboards[i] && bit_check) return i;
}
而不是返回-1为空,这将返回12(哨兵价值)。 但是,这将使用更快的无条件分支替换条件循环分支。 这也意味着返回值总是int i
。
另一个无关的优化是识别棋子是最常见的棋子,所以对于白棋使用bitboards[0]
以及对bitboards[1]
使用bitboards[1]
或bitboards[6]
更有效率,这取决于你是交错黑或白件。
如果你有一个单独的color
,那么你不需要两个白色棋子和黑色棋子的棋盘。 相反,有一个单兵棋子的棋子。 检查一个黑色的棋子,并将这两个值。 ( bit_check & color & bitboard[0]
)。 要检查白色棋子,请反转颜色( bit_check & ~color & bitboard[0]
)
这是一个比特板最慢的操作。 但是,你很少需要执行它。
我看到你正在保持所有白色的部分,或者white
,或者是所有的黑色部分,或者是black
。 使用这些,您可以快速拒绝移动到您自己的部分并轻松检测捕获。
在不太可能发生的情况下,你必须测试6个敌方棋子中的5个,因为国王捕获应该已经被排除了。 而且,这并不像你想象的那样单调乏味。 在64位系统上,每个掩码只有每个位板1个操作,然后进行比较,因此有10个整数操作。 And
/ Or
处理器上最轻的一些操作。 单独维护Piece[64]
比这花费更多的时间。
我相信没有其他的情况(在引擎代码中),您需要从给定的方块中获取pieceID。
棋盘的主要优点是移动生成和位置分析。 没有什么比较,所以无论如何你都会保持这种结构。
链接地址: http://www.djcxy.com/p/14819.html上一篇: Recognising a chess piece with bitboards
下一篇: Connecting a Chess Engine to an Existing GUI made with Javascript