2013-05-29 103 views
8

我正在製作遊戲國際象棋,幾乎獲得了一切,但只有一件事:我需要做到這一點,以便玩家不可能將棋子移動到棋盤上。我在如何解決這個問題上遇到了麻煩。國際象棋:獲得所有合法國際象棋棋子

我現在所擁有的在僞碼以生成有效的動作是: 類getMoveLocations(I定義的位置是在國際象棋的那些方塊的一個): 如果該位置是在邊界內,並且片在該位置是並且模擬的移動不會導致棋盤被檢查,然後將該位置添加到棋子可以移動到的可能位置。

這個問題是我如何檢查一個棋盤是否「檢查」。在我的代碼中,它認爲一個棋盤將通過收集所有敵人的移動位置來進行「檢查」,並查看是否有任何敵方移動位置與國王的位置重疊。

不幸的是,這是無限循環開始的地方;爲了收集所有敵人的電影位置,每個敵人可能的移動位置需要確保其移動不會導致它被檢查。爲了確保敵人的位置都沒有受到檢查,它必須收集所有盟友的潛在移動位置等。等等。

我對如何獲得工作算法很着迷。雖然我的代碼「理論上」是合乎邏輯的,但它不能實現。我對A)更有效的方式來實現一種方法來檢查所有的法律動作,或B)一種方法來解決這個無限循環

+0

你可以運行遞歸部分只爲那些會創建一個檢查(以確保它們是有效的)而不是其他(它們無關緊要,如果它們是無效的)的移動。這應該防止無限遞歸。 – assylias

+0

你做了一個叫getMoveLocations的類嗎? – joshreesjones

+1

您正在尋找可能的舉動「如果我在這裏移動,並且對手在那裏移動,那麼如果我在對手移到這裏之後移動到那裏,我會進行檢查嗎?」?想象一下製作一個遊戲,你有一個彈跳在牆上的球,並且球可以被玩家控制,你不會將他的移動限制在N條路徑上,這不會導致與牆相撞(巨大的搜索),你會讓他向任何一個方向移動UNTILL他與牆壁發生碰撞。同樣,只檢查移動是否會讓你在移動時檢查,而不考慮一塊棋子的所有可能移動(巨大的搜索) – arynaq

回答

2

修改您的getMoveLocations程序接受一個標誌,指示是否擔心移動進入檢查。例如,如果一件東西被釘住了,它仍然可以移動以捕捉對方國王。如果該標誌設置爲忽略檢查風險,則跳過檢查測試將會中斷遞歸。

或者(等同)編寫一個單獨的方法來生成忽略移入檢查問題的移動。使用該程序作爲「讓棋盤進行檢查」測試的一部分。

+0

通過這樣做,移動被認爲是無效的,但實際上它有效的可能性還不存在嗎? – Mike

+0

@ user2430625 - 我不這麼認爲。如果由於你的移動,對手可以立即拿走你的國王(即使它移動了一個可以對對手進行檢查的棋子),那麼你不能做出這樣的舉動。你能否提供一個顯示其他情況的例子? –

+0

我不認爲這種方法適用於複雜的職位與許多固定件。您可以在固定件之間建立循環關係。 – Zong

1

如果移動允許敵方的棋子能夠對你的國王進行攻擊移動,那麼移動會使你的身體進入檢查狀態(因此不允許)。

請注意,將您的對手放在支票上是不同的 - 當您放置對手時,他們輪到迴應。如果你可以把自己置於檢查中,你將有0迴應的機會。他們能夠捕捉到你的國王,無論他們投入的位置多麼糟糕,或者即使他們會「被檢查」,他們總是會做出正確的舉動 - 他們贏了!那之後什麼都沒有了。

因此,看看是否會採取行動將自己放在檢查,看看是否有任何敵人的一塊可以使攻擊移動到你的國王。而已。你不是遞歸地解決未來的檢查或類似的事情 - 如果他們現在可以攻擊國王,那是無效的。

8

有一個更有效的方法來確定一邊是否在檢查:你只需從國王向外掃描,看看你是否找到可以攻擊它的碎片。例如,從國王的位置,檢查是否有任何敵方主教沿着對角線等。您根本不需要生成移動列表,因此遞歸是不必要的。這裏有一些僞代碼:

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

+0

他也必須特別處理castling。國王不得越過受到攻擊的空間,因此海報還需要檢查f1或f8是否爲King-cast castling,d1或d8是否爲Queen-cast castling。 –

+0

是的,而且還行。完全合法的生成非常複雜。如果在僞法律生成後評估檢查,所有這些都可以輕鬆處理,但速度會慢一些。 – Zong

+0

但是隻有在城堡裏,海報才能檢查2格;目的地和中間空間。 –

0

看來,一些海報不懂棋的發動機足夠,所以請嘗試爭辯前仔細閱讀和研究:

而不是檢查,看看他們是否能搬到那裏,檢查它們是否可以攻擊那裏。您可能會希望以後爲您的評估功能反正...

我不知道有多少個引擎這樣做,但我知道幹鱈魚確實(見src文件夾中的evaluate.cpp),所以我假設它在GOOD引擎中相當標準。如果無論如何都需要完成評估,那麼你最好在運動世代中使用它。

+0

如果你的算法接受這個答案的邏輯,這將是一個比所有敵人的有效動作更簡單和可能更便宜的評估。對於國王的移動來說,這可能是一個相當簡單的布爾操作:如果這個空間對ChessPiece.KING是有效的,並且不受敵人剩餘棋子的攻擊,那麼這是一個有效的舉動。如果ChessPiece.KING受到攻擊,並且沒有有效的移動,那麼遊戲就會以失敗告終。 – scottb

+0

能夠移動到那裏並且除了castling,enpassant和pawn advance之外還有能力攻擊的區別是什麼?這與OP已經做的幾乎完全一樣。 – Zong

+0

我從來沒有寫過國際象棋引擎,但我已經做了大量的研究,我認爲這是最好的方法。我主要關心的是,OP使用Java作爲國際象棋引擎,顯然他們不關心性能太多...... –