天天看點

FireMonkey3D之中國象棋程式(二)制定規則

聲明:本程式設計參考象棋巫師源碼(開發工具dephi 11,建議用delphi 10.3以上版本)。

  本章目标:

實作中國象棋規則

  上一章我們設計了圖形界面,可以開始輪流走棋了。但是,由于沒有按中國象棋的規則進行限制,所有的棋子都可以在棋盤上随意走動,這章我們開始制定行棋規則。

  2.1 記錄局面

  在制定規則之前,我們要先考慮把目前局面記錄下來,這樣棋子移動後才能知道移動後的局面。棋盤是10×9的格子組成,我們就用二維數組來記錄局面變化情況,同時用一個一維數組記錄每個棋子的位置:

在startUp函數裡,我們将chessbd 初始化,同時記錄初始棋局,代碼較前章稍作修改,已标記:

 

   移動棋子之後,chessbd将發生變化,我們定義function TPieceMove.MovePiece(s,d:TPoint):Byte;這個函數記錄移動後的變化:

2.2、制定規則

  現在可以制定規則,限制棋子移動的範圍。中國象棋走棋規則:車炮走直線,炮打隔山子,馬跳日、象飛田,士走斜線,兵有進無退。重要的設計思路:

  根據src源點、dest目标點的縱橫坐标差的絕對值判斷棋子的移動軌迹是否合理。

兵(卒):有進無退,過河平移,每次一格。僞代碼 :

    if  縱坐标絕對內插補點+橫坐标絕對內插補點<>1 then 傳回假;if 未過河 and 橫坐标絕對內插補點=1 then 傳回假。

馬:跳日字,且馬眼無子。僞代碼 :if  縱坐标絕對內插補點*橫坐标絕對內插補點<>2 then 傳回假; if 别腿 then 傳回假。如何判斷别腿?下圖講解: 

FireMonkey3D之中國象棋程式(二)制定規則

 從圖解中不難看出,馬橫跳時,馬眼的橫坐标是(源點橫坐标+目标點橫坐标)/2,縱坐标與源點相同;豎跳時,馬眼的縱坐标是(源點縱坐标+目标點縱坐标)/2,橫坐标與源點相同。僞代碼:

    if 橫跳 and 馬眼無棋 then 傳回真;if 豎跳 and 馬眼無棋 then 傳回真。

象(相):走田字,象眼的位置簡單得多,坐标【(源點橫坐标+目标點橫坐标)/2,(源點縱坐标+目标點縱坐标)/2)】,與馬的判斷相同。僞代碼:

         if 已過河  or 縱坐标絕對內插補點<>2 or  橫坐标絕對內插補點<>2  then 傳回假;if 象眼無棋 then 傳回真。 

士(仕): 走斜線,且不能出宮。僞代碼:if 在宮裡 and 縱坐标絕對內插補點*橫坐标絕對內插補點=1 then 傳回真。

帥(将):不出宮,每次一格。僞代碼:if 在宮裡 and 縱坐标絕對內插補點+橫坐标絕對內插補點=1 then 傳回真。以上幾種棋判斷走法很簡單,就不發代碼了,文章最後有完整源碼。

車炮:走直線。雖說直線容易判斷,但是走棋判斷就稍複雜些。我們從源點搜尋到目标點,看中間有無棋子擋住,如此判斷。代碼如下: 

  2.3 是否将軍 

   中國象棋裡能将軍的棋子也就4種:兵(卒)、馬、炮、車,是以我們判斷是否将軍時,隻要判斷對方的這4種棋子是否将軍即可。這裡我們要為兵(卒)、馬、帥(将)定義步長,以便判斷。所謂步長,就是指兵、馬、帥走一步能到的位置,以原點坐标(0,0)為起點,确定以上棋子能走到位置,兵、帥的走法一緻,步長也一樣;馬八個方向都可以走,還得定義馬眼的位置;這裡把士、相的步長也一并定義了,後面有用 。車炮步長不定,是以不能定義。代碼如下:

  定義步長之後,我們就可以根據步長來判斷帥(将)周邊是否有以上4種有攻擊力的棋子(注意:将帥面對面也是被認為是一種被将軍!):

  以上代碼也不複雜,不再另外講解。中國象棋裡我們要考慮,如果走棋之後,走棋方處于将軍的狀态,就不能走這步棋,是以得撤回這步走棋:

  2.4 是否赢棋

  判斷是否赢棋,就是某一方被将軍後,無法解将,或是某一方子被剃光頭。以此來确定赢棋,設計思路:被将軍的一方生成所有的走法,逐一嘗試這些走法看是否能解将。紅黑雙方各有16個棋,除去已經被吃掉的棋,逐一生成走法即可,直接上代碼(看注釋):

  剩下的工作就是逐一走這些走,判斷是否仍處于将軍狀态,再撤銷這些走法(為什麼用IsMate?純粹是與象棋巫師一緻,實在不明白為什麼這樣的函數名,我最初用的GameOver):

  2.5  響應規則

  在csBoard事件裡添加canMove、MovePiece、IsChecked,IsMate等規則函數即可,見源碼。

下一章将開始AI算法。

本章節源碼百度雲盤:

連結:中國象棋程式設計(二)制定規則

提取碼:1234