我正在开发我自己的国际象棋引擎,如果有什么可以预先初始化/预先计算的话,应该是。这是因为速度是第一位的,每多花一秒时间,你就会把原本可以事先计算出来的计算方法花在计算上,堆叠起来,最终让你失去很多重要的时间,而这些时间本来是不能预先计算的,比如评估。
主要的预初始化变量是各种比特板掩码.
constepxr无处不在。
我有一个单独的头文件来管理所有这些。它们可以在开始时初始化一次,然后在整个程序中使用几次。
我目前所做的是使用嵌套的命名空间。
// Bitboard is an alias for uint64_t
// NB_SQ is the number of squares (64)
namespace Mask
{
void InitMasks();
void InitAttacks();
namespace File
{ // few examples
constexpr Bitboard FileA = 0x0101010101010101;
constexpr Bitboard FileB = FileA << 1;
constexpr Bitboard FileC = FileB << 1;
constexpr Bitboard FileD = FileC << 1;
constexpr Bitboard FileE = FileD << 1;
constexpr Bitboard FileF = FileE << 1;
...
constexpr Bitboard notFileAB = ~(FileA | FileB)
constexpr Bitboard notFileGF = ~(FileG | FileF)
extern uint64_t AllFiles[NB_SQ]
}
namespace Rank{...}
namespace Diagonal {...}
namespace Attack
{
extern Bitboard PawnAttacks[NB_SQ];
extern Bitboard KnightAttacks[NB_SQ];
...
}
}所有extern数组都使用InitMasks()和InitAttacks()初始化一次
我能知道第七军衔的白卒有多少
WhitePawnsBB & Mask::Rank::Rank7或者如果我想获得特定正方形的文件掩码
Mask::File::AllFiles[SQ]如果我需要对任何广场上的骑士进行预先计算的攻击
Mask::Attack::KnightAttacks[SQ];但是我真的很不满意,知道哪种面具可以属于哪里就会变得非常混乱。而且,这不是名称空间的目的,我是否有更好的方法来构建命名空间呢?
发布于 2020-11-11 06:44:50
使用预先计算的位掩码仍有代价,因为它填充了缓存。内存是SSSSOOOOOOO SSSSSSSLLLLLOOOOOOOOOWWWWWWWWWWWW,因此动态计算这些位图可能会更快。
但假设你已经做了尽职调查。编译时函数怎么样?这允许您对逻辑进行具体说明,并允许编译器决定预编译位掩码或动态计算是否是更好的方法。
constexpr uint64_t horse_attack(uint32_t location)
{
return /*bit twiddles on the constant location*/;
}但是,如果确实需要常量,请考虑预先分配的数组。是的,有一个取消引用操作,但它确实避免了在操作码流中包含位掩码(可能多次),并且可以更容易地缓存。
如果检测到缓存的内存对齐,并强制数组在缓存边界上过度对齐,则需要额外的点数。
uint64_t horse_move[64] = {
//each mask for each successive location.
};如果不需要手工计算,请考虑编写一个程序来生成和列出这些常量。它不会像你写板面具时那样无聊。
https://softwareengineering.stackexchange.com/questions/418836
复制相似问题