我正在使用棋位图来表示棋盘并检查合法的移动。我遇到的问题是计算滑动棋子攻击中起始格和目标格之间的占用情况。我不想通过查找表来解决,所以我正试图弄清楚是否有可能在不使用查找表的情况下获得中间格子的掩码。 例如,在下面的棋盘中,c4 上有一个车:
8 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 4 0 0 R 0 0 0 0 0 3 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 a b c d e f g h
给定一个表示空格子(或被占用的格子,无论哪个更容易)的棋位图,以及一个伪有效的移动 Rf4 (车可以从 c4 移动到 f4),如何获得格子 d4-e4 的掩码(不包括起始格和目标格)?
我认为,一旦这一点明确了,垂直移动将很容易,并且可以通过使用旋转的棋位图来计算对角线移动。
编辑: 棋位图用 ulong/unsigned int64 表示,每 8 位代表棋盘的一行/列。
回答:
我在这里做一些假设:棋盘存储为一个 64 位数字,每 8 个字节的块表示一行。行中的每一位代表一列 (a..h)。您有基于零的坐标作为起始和结束位置。即:start = "C4" = [2,3]; end = "F4" = [5,3]
对于列递增的水平移动,您可以计算移动的距离:d = (F4-C4 = 3)
。 减 1 以排除目的地,然后 d-1 位的“尾迹” t 是 t = (1<<(d-1))-1
。 将尾迹移动到起始棋子相邻的位置以获得掩码 M:M = t<<(start.row*8 + start.column+1)
.
这相当于 M = ((1<<d)-2)<<(start.row*8 + start.column)
对于另一种方式的水平移动:
d = (C4-F4 = -3) t = (1<<(-d-1))-1 M = (t<<dest.column+1) //-或- M = ((1<<-d)-2)<<(dest.row*8 + dest.column)
对于垂直递增的移动:
d = (C7-C4 = 3) t=(1<<8) (d-1) 次: { t |= (t<<8)} M = t << (start.row*8 + start.column)
对于垂直递减的移动:
d = (C4-C7 = 3) t=(1<<8) (d-1) 次: { t |= (t<<8)} M = t << (dest.row*8 + start.column)
对于垂直移动,您可以通过存储最大“垂直尾迹”VT = 0x0101010101010101 = 72340172838076673
来替换对 d 的循环。然后屏蔽掉正确数量的位以进行实际移动。
这会将计算减少到 M = (VT & ((1<<(d*8)) - 2)) << (row*8+column)
。
您也可以对对角线移动做类似的事情。 从最大对角线轨迹 DT = 0x0102040810204080
开始,应用一个掩码将其减少到 d
设置的位,并根据哪个更靠近边缘,将其移动到开始或结束位置。 这将需要仔细测试以确保没有边缘情况会环绕到错误的行中。
编辑以排除起始和目标位置,并修复一些一次性错误