用位棋盘识别棋子
Recognising a chess piece with bitboards
当棋盘存储在各种位板中时,现代国际象棋引擎如何识别位于特定单元中的类型/侧面棋子?我对此有问题,因为要找出特定位的类型/侧块是什么,我必须总是这样做:
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数组是否会更快,它将固有地存储piece类型。
考虑到在搜索函数中捕获分析需要数百万次,这将是更好的选择。我做错了吗?
位校验本身很快;我最担心的是分支。
相反,将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;
}
将返回12(哨兵值),而不是为空返回-1。但是,这将条件循环分支替换为更快的无条件分支。这也意味着返回值总是int i
。
另一个不相关的优化是认识到小兵是最常见的小兵,所以使用bitboards[0]
作为白兵,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。
位棋盘的主要优点是移动生成和位置分析。没有什么可以比较的,所以无论如何都要维护这个结构。
- 提升 ASIO 无法识别计时器对象
- 从udp接收帧对于人脸识别来说太慢
- 模板类无法识别友元运算符
- std::visit无法识别类型
- 无法识别模板功能
- 我有两个类需要在同一 cpp 文件中相互引用,但第一个类无法识别第二个类类型的对象
- 如何在LLVM中dyn_cast以识别StoreInst?
- 从不同的附加依赖项中识别等同命名的函数
- C++出现控制台错误.我无法识别源代码的问题
- VSCode IntelliSense无法识别SDL框架的SDL_image扩展库
- Qt:"Q3DScatter"即使包含在内也无法识别
- 使用指针的类识别
- 如何静态识别动态堆分配?
- 为什么C++无法识别我的对象实例化?
- C++ 无法识别创建进程'telnet'
- 识别 2D 矢量C++中的位置
- 如何识别项目是 QT 中的文件还是文件夹
- ESP32 无法识别任何设备已连接到其接入点
- 无法识别 Mac c++ 文件系统库
- 用位棋盘识别棋子