有三個白子和三個黑子如下圖布置:
○ ○ ○ . ● ● ●
遊戲的目的是用最少的步數將上圖中白子和黑子的位置進行交換:
● ● ● . ○ ○ ○
遊戲的規則是:(1)一次只能移動乙個棋子; (2)棋子可以向空格中移動,也可以跳過乙個對方的棋子進入空格,但不能向後跳,也不能跳過兩個子。請用計算機實現上述遊戲。
*問題分析與演算法設計
計算機解決勝這類問題的關鍵是要找出問題的規律,或者說是要制定一套計算機行動的規則。分析本題,先用人來解決問題,可總結出以下規則:
(1) 黑子向左跳過白子落入空格,轉(5)
(2) 白子向右跳過黑子落入空格,轉(5)
(3) 黑子向左移動一格落入空格(但不應產生棋子阻塞現象),轉(5)
(4) 白子向右移動一格落入空格(但不應產生棋子阻塞現萌),轉(5)
(5) 判斷遊戲是否結束,若沒有結束,則轉(1)繼續。
所謂的「阻塞」現象就是:在移動棋子的過程中,兩個尚未到位的同色棋子連線在一起,使棋盤中的其它棋子無法繼續移動。例如按下列方法移動棋子:
0○ ○ ○ . ● ● ●
1 ○ ○ . ○ ● ● ●
2 △ ○ ○ ● ○ . ● ●
3○ ○ ● . ○ ● ●
4 兩個●連在一起產生阻塞
○ ○ ● ● ○ . ●
或4 兩個白連在一起產生阻塞
○ . ● ○ ○ ● ●
產生阻塞的現象的原因是在第2步(△狀態)時,棋子○不能向右移動,只能將●向左移動。
總結產生阻塞的原因,當棋盤出現「黑、白、空、黑」或「白、空、黑、白」狀態時,不能向左或向右移動中間的棋子,只移動兩邊的棋子。
按照上述規則,可以保證在移動棋子的過程中,不會出現棋子無法移動的現象,且可以用最少的步數完成白子和黑子的位置交換。
*程式說明與注釋
#include
int number;
void print(int a);
void change(int *n,int *m);
int main()
; /*初始化陣列1:白子 2:黑子 0:空格*/
int i,flag;
print(t);
while(t[0]+t[1]+t[2]!=6||t[4]+t[5]+t[6]!=3) /*判斷遊戲是否結束
若還沒有完成棋子的交換則繼續進行迴圈*/
for(i=0;flag&&i<5;i++) /*若黑子可以向左跳過白子,則黑子向左跳*/
if(t[i]==0&&t[i+1]==1&&t[i+2]==2)
for(i=0;flag&&i<6;i++) /*若向右移動白子不會產生阻塞,則白子向右移動*/
if(t[i]==1&&t[i+1]==0&&(i==0||t[i-1]!=t[i+2]))
for(i=0;flag&&i<6;i++) /*若向左移動黑子不會產生阻塞,則黑子向左移動*/
if(t[i]==0&&t[i+1]==2&&(i==5||t[i-1]!=t[i+2]))}}
void print(int a)
void change(int *n,int *m)
*問題的進一步討論
本題中的規則不僅適用於三個棋子的情況,而且可以推而廣之,適用於任意n個棋子的情況。讀者可以程式設計驗證,按照本規則得到的棋子移動步數是最少的。
事實上,制定規則是解決這類問題的關鍵。乙個遊戲程式「思考水平的高低,完全取決於使用規則的好壞。」
*思考題
有兩個白子和兩個黑子如下左圖布置:
○ . ○
. . .
● . ●
棋盤中的棋子按」馬步「規則行走,要求用最少的步數將圖中白子和黑子的位置進行交換,最終結果如下一幅圖所示。
● . ●
. . .
○ . ○