有一個更有效的方法來確定一邊是否在檢查:你只需從國王向外掃描,看看你是否找到可以攻擊它的碎片。例如,從國王的位置,檢查是否有任何敵方主教沿着對角線等。您根本不需要生成移動列表,因此遞歸是不必要的。這裏有一些僞代碼:
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,而是用一個簡單的數組表示。這使得實施合法移動生成(沒有中間僞法律移動)有點困難,因爲它需要非常快地生成攻擊地圖來確定固定的棋子。如果你雄心勃勃,這是一種可能性。
作爲補充說明,我對這裏的其他答案有些失望。我甚至不會向任何想要寫出好動作生成器的人推薦自己的答案(它只針對那些不熟悉國際象棋程序設計的人)。這是一個經過徹底檢查並具有衆所周知的解決方案的主題,但卻引發了獨創性的想法。當然,這沒有什麼不對,但爲什麼重新發明車輪,更糟?看看well established methods of move generation。
你可以運行遞歸部分只爲那些會創建一個檢查(以確保它們是有效的)而不是其他(它們無關緊要,如果它們是無效的)的移動。這應該防止無限遞歸。 – assylias
你做了一個叫getMoveLocations的類嗎? – joshreesjones
您正在尋找可能的舉動「如果我在這裏移動,並且對手在那裏移動,那麼如果我在對手移到這裏之後移動到那裏,我會進行檢查嗎?」?想象一下製作一個遊戲,你有一個彈跳在牆上的球,並且球可以被玩家控制,你不會將他的移動限制在N條路徑上,這不會導致與牆相撞(巨大的搜索),你會讓他向任何一個方向移動UNTILL他與牆壁發生碰撞。同樣,只檢查移動是否會讓你在移動時檢查,而不考慮一塊棋子的所有可能移動(巨大的搜索) – arynaq