有一种更有效的方法来确定一方是否处于受控状态:您只需从国王向外扫描,看看是否找到可以攻击它的棋子。例如,从国王的位置,检查是否有敌方主教沿对角线等。您根本不需要生成移动列表,因此不需要递归。这是一些伪代码:
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,而是使用简单的数组表示。这使得实现合法移动生成(没有中间的伪合法移动)有点困难,因为它需要非常快速地生成攻击图来确定固定棋子。如果你有野心,这是一种可能。
作为补充说明,我对这里的其他答案有些失望。而且我什至不会向任何想要编写一个好的移动生成器的人推荐我自己的答案(它仅适用于那些不熟悉国际象棋编程的人)。这是一个经过彻底检查并具有众所周知的解决方案的主题,但正在引发原创想法。这当然没有错,但为什么要重新发明轮子,甚至更糟呢?研究完善的移动生成方法。