有一种更有效的方法来确定一个方向是否被将军:你只需从国王的位置向外扫描并查看是否有可以攻击它的棋子。例如,从国王的位置开始,检查是否有任何敌方象在对角线上等。您根本不需要生成移动列表,因此递归也不必要。以下是一些伪代码:
function leftInCheck(board, sideToCheck) {
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
break
d := d + 1
...
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,而是使用简单的数组表示。这使得实现合法移动生成(没有中间的伪合法移动)有点困难,因为它需要非常快速地生成攻击映射以确定被牵制的棋子。如果你有雄心壮志,这是一个可能性。
另外,我对这里的其他答案有些失望。我甚至不会向任何想要编写良好的移动生成器的人推荐我的答案(它只适用于那些不熟悉国际象棋编程的人)。这是一个已经被深入研究并且有着众所周知解决方案的主题,但是却在引发原创思路。当然,这并没有什么问题,但是为什么要重复发明轮子呢?最好研究一下
已经确立的移动生成方法。