【问题标题】:Getting occupancy bit masks for bitboards获取位板的占用位掩码
【发布时间】:2011-06-24 06:11:37
【问题描述】:

我正在玩比特板来代表棋盘并检查合法的移动。我坚持的事情是计算滑动块攻击中源方格和目标方格​​之间的占用率。 我不想通过查找来做到这一点,所以我想弄清楚是否有可能在无需查找的情况下为中间的方块获取掩码。例如,在下面的棋盘中,c4 上有一个 Rook:


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(Rook 可以从 c4 移动到 f4),如何获得方格 d4-e4 的掩码(不包括源和目标方块)?

我认为,一旦这一点很清楚,垂直移动就会很容易,并且可以使用旋转的位板来计算对角线移动。

编辑:位板用 ulong/unsigned int64 表示,每包 8 位代表实际板的一个等级/行。

【问题讨论】:

  • 如果您仍然要使用位板,请不要浪费时间重复生成它们。在棋盘上选择两条线的方法只有 1953 种。您可以轻松地将它们存储在数组中。
  • @ThomasAhle 在尝试制作国际象棋引擎后放弃了数组

标签: artificial-intelligence bit-manipulation chess


【解决方案1】:

我将在这里做一些假设:板存储为 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)
 //-or-
 M = ((1<<-d)-2)<<(dest.row*8 + dest.column)

对于垂直增加的移动:

 d = (C7-C4 = 3)
 t=(1<<8)
 (d-1) times: { t |= (t<<8)}
 M = t << (start.row*8 + start.column)

对于垂直下降的移动:

 d = (C4-C7 = 3)
 t=(1<<8)
 (d-1) times: { t |= (t<<8)}
 M = t << (dest.row*8 + start.column)

对于垂直移动,您可以通过存储最大“垂直轨迹”VT = 0x0101010101010101 = 72340172838076673 来替换 d 上的循环。然后为实际移动屏蔽正确的位数。

这将计算减少到M = (VT &amp; ((1&lt;&lt;(d*8)) - 2)) &lt;&lt; (row*8+column)。

你也许可以对对角线移动做类似的事情。从最大对角轨迹 DT = 0x0102040810204080 开始,应用掩码将其减少到 d 设置位,然后移动到开始或结束位置,具体取决于哪个更靠近边缘。这需要仔细测试以确保没有边缘情况缠绕到错误的行中。

已编辑以排除源和目标,并修复一次性错误

【讨论】:

  • 感谢您的回答!我今晚会试试这个并发布结果。
  • 一个问题:为什么要这样?这仅适用于人类玩家的动作吗?对于 AI 走法,先计算非阻挡走法,然后选择最佳走法似乎更容易,而不是从所有可能的走法中挑选出一个走法,然后测试它是否被阻挡。
  • 我这样做是为了验证游戏中编写的动作。在某些符号中,您必须找出移动到目的地的棋子的源方格。例如,在某些表示法中,您可能只得到 Rf4 表示车从 c4 移动到 f4。如果你有超过 1 个车,你将不得不使用验证来找出哪一个可以移动到 f4。无论如何,通过对您的公式进行一些小的调整,我得到了给定 2 之间的正方形的正确位掩码。将很快进行基准测试并发布结果。谢谢!
  • 在水平移动中,你可能是指M = (t&lt;&lt;dest.row* + dest.column),它对我有用,就像你对垂直移动所做的那样
【解决方案2】:

没有进行一些预先计算并为棋子移动生成所有可能的掩码(绝对有可能),我希望在运行时构建掩码很可能会像简单的 '查找每个方格的方法。

【讨论】:

  • 这就是为什么问题是是否可以在给定两个正方形的情况下动态计算掩码,假设一个方向(东/西)
  • 这绝对是可能的 - 但很可能不会比替代的、更简单的方法便宜。
  • 预先计算所有可能性肯定更便宜。
  • @sehe:不,我自己并没有对此进行分析,但计算机国际象棋社区中的每个人都是这样做的。
  • 我知道你在夸大其词。这可能超过了一半,所以我让它保持不变。对我来说,我找到了一种似乎对我更有效的方法——尽管我必须说它涉及修改过的棋盘(想想 8x8x8)并且仍然预先计算可移动表。只是不是位板的形式
【解决方案3】:

获取方向(dx,dy)/dx的单位向量

在这种情况下,(1,0)

然后使用该向量重复增加当前位置,直到到达目的地。正在进行增量/分配相应的矩阵单元。

【讨论】:

  • 似乎不会比从 EmptySquares 位板上逐位查找更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-10
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
  • 2019-11-19
相关资源
最近更新 更多