我们将添加一些空格。假设您从一个典当位置开始:
00000000
00000000
00000000
00000000
00000000
10000000
01100101
00011010
00000000
00000000
换行符只是为了便于阅读,所有内容都包含在内。棋子可以移动到哪里?
00000000
00000000
00000000
00000000
10000000
01100101
00011010
00000000
00000000
00000000
在这里,越过边缘的唯一风险是在顶部,这很容易处理。
接下来,棋子可以去哪里?天真的解决方案是您采用上述“移动”蒙版,并将其向左和向右移动 1。正如您所注意到的,这会导致回绕。
00000000
00000000
00000000
00000001
00000000
11001010
00110100
00000000
00000000
00000000
|
00000000
00000000
00000000
00000000
01000000
00110010
10001101
00000000
00000000
00000000
(如果您不喜欢我选择的字节顺序,请道歉)。
我们可以通过一些掩蔽来解决这个问题。将环绕的位位于已知位置。因此,我们在进行操作之前将它们屏蔽掉。
这个面具:
11111110
11111110
11111110
11111110
11111110
11111110
11111110
11111110
在我们向右移动之前,并且
01111111
01111111
01111111
01111111
01111111
01111111
01111111
01111111
在我们左移之前。
因此,要查看受棋子威胁的点,其中“前进”是右移,我们这样做:
auto pawn_moves = pawn_mask >> 8;
auto pawn_left_take = (pawn_moves & not_left_column) << 1;
auto pawn_right_take = (pawn_moves & not_right_column) << 1;
auto pawn_take = pawn_left_take | pawn_right_take;
我们终于得到它了。
可以对其他情况进行类似的掩蔽。例如,如果我们正在计算骑士的面具,我们需要 8 个面具和 8 个班次,那么或者它们全部加在一起。
对于向右移动 3 的车,您屏蔽掉右侧的 3 列,然后在车掩码上进行右 3 移动。
然而,在某些时候,您可能想要使用内在函数和 SIMD 处理;因此,您所拥有的快速位操作将取决于您的工具。也许将 8 个 8 位值解压缩为 8 个 24 位值,在那里进行无掩码操作,然后提取中间 8 位是您特定硬件上最快的方法。