11

我正在制作游戏象棋,并且几乎得到了一切,但只有一件事:我需要做到这一点,以便玩家无法将棋子移动到检查中。我在如何解决这个问题上遇到了麻烦。

我现在在伪代码中生成有效移动的内容是:类 getMoveLocations(我将一个位置定义为国际象棋中的那些方块之一):如果这个位置在边界内,并且这个位置的棋子是敌人的棋子,并且模拟移动不会导致棋盘被检查,然后将此位置添加到棋子可以移动到的可能位置。

问题在于我如何检查棋盘是否“处于检查状态”。在我的代码中,它通过收集所有敌人的移动位置并查看这些敌人的移动位置是否与国王的位置重叠,认为棋盘处于“检查”状态。

不幸的是,这是无限循环开始的地方。为了收集所有敌人的电影位置,每个敌人的可能移动位置都需要确保其移动不会导致它被检查。为了确保不检查敌人的位置,它必须收集所有盟友的潜在移动位置等。

我对如何获得有效的算法感到困惑。尽管我的代码“理论上”具有逻辑意义,但它无法实现。我对 A) 一种更有效的方法来检查所有合法动作,或 B) 一种修复这个无限循环的方法很感兴趣

4

5 回答 5

9

有一种更有效的方法来确定一方是否处于受控状态:您只需从国王向外扫描,看看是否找到可以攻击它的棋子。例如,从国王的位置,检查是否有敌方主教沿对角线等。您根本不需要生成移动列表,因此不需要递归。这是一些伪代码:

function leftInCheck(board, sideToCheck) {

   // one of the four rays for bishop/queen attacks
   d := 0
   while (king rank + d, king file + d) is on the board
      piece := board[king rank + d][king file + d]
      if piece is an enemy bishop or queen
         return true
      if piece is not an empty square   // a piece blocks any potential
         break                          // attack behind it so we can stop
      d := d + 1

   // do this for all the other forms of attack
   ...

   return false
}

如您所见,有一些代码重复,但您可以缩短它。我保持原样,所以很容易理解。您可以通过像现在一样生成伪合法的移动来生成合法的移动,制作每一个,并省略那些让您检查上述子程序的移动。这自然具有过客的额外优势。这是一些伪代码:

function legalMoves(board, sideToMove) {
   moveList := empty
   for each move in pseudoLegalMoves()
      make(move)
      if not leftInCheck(board, sideToMove)
         moveList.add(move)
      unmake(move) // you may not need this
   return moveList
}

对于易位,您仍然需要检查国王和车之间的方格是否受到攻击。幸运的是,这很容易,因为您可以扩展上面的子程序以处理除国王以外的方格。

我假设您没有使用位板或 0x88,而是使用简单的数组表示。这使得实现合法移动生成(没有中间的伪合法移动)有点困难,因为它需要非常快速地生成攻击图来确定固定棋子。如果你有野心,这是一种可能。

作为补充说明,我对这里的其他答案有些失望。而且我什至不会向任何想要编写一个好的移动生成器的人推荐我自己的答案(它仅适用于那些不熟悉国际象棋编程的人)。这是一个经过彻底检查并具有众所周知的解决方案的主题,但正在引发原创想法。这当然没有错,但为什么要重新发明轮子,甚至更糟呢?研究完善的移动生成方法

于 2013-05-29T01:24:10.543 回答
2

如果移动允许敌方棋子能够对你的国王进行攻击移动,则移动会阻止你的一方(因此是不允许的)。

请注意,阻止自己与阻止对手是不同的——当你阻止对手时,他们有机会做出回应。如果您可以控制自己,那么您将有 0 机会做出回应。他们将能够俘获您的国王,并且无论他们处于多么糟糕的位置,或者即使他们会“受到控制”,这始终是正确的举动 - 他们已经赢了!之后什么都没有了。

因此,要查看移动是否会阻止自己,请查看是否有任何敌方棋子可以攻击您的国王。而已。您不会递归地解决未来的检查或类似的问题-如果他们现在可以攻击国王,那将是无效的。

于 2013-05-29T01:19:57.980 回答
2

修改您的getMoveLocations过程以接受指示是否担心进入检查的标志。例如,如果一个棋子被固定,它仍然可以移动以捕获对方的国王。如果标志设置为忽略检查风险,则跳过检查测试将中断递归。

或者(并且等效地)编写一个单独的方法来生成忽略移动到检查问题的移动。将该程序用作“使电路板处于检查状态”测试的一部分。

于 2013-05-29T01:10:33.947 回答
1

看来有些发帖者对国际象棋引擎的理解不够充分,因此请在尝试争论之前仔细阅读和研究:

与其检查他们是否可以移动到那里,不如检查他们是否可以在那里攻击。无论如何,您稍后可能会想要它作为您的评估功能......

我不知道有多少引擎会这样做,但我知道 Stockfish 会这样做(请参阅 src 文件夹中的评估.cpp),所以我认为它在 GOOD 引擎中是相当标准的。如果无论如何都需要进行评估,您不妨在运动生成中使用它。

于 2013-05-29T02:38:38.287 回答
0
于 2019-10-25T17:04:40.070 回答