C趣味程序百例(28)黑白子交換

字號(hào):

87.黑白子交換
     有三個(gè)白子和三個(gè)黑子如下圖布置:
    ○ ○ ○ . ● ● ●
     游戲的目的是用最少的步數(shù)將上圖中白子和黑子的位置進(jìn)行交換:
    ● ● ● . ○ ○ ○
     游戲的規(guī)則是:(1)一次只能移動(dòng)一個(gè)棋子; (2)棋子可以向空格中移動(dòng),也可以跳過一個(gè)對(duì)方的棋子進(jìn)入空格,但不能向后跳,也不能跳過兩個(gè)子。請(qǐng)用計(jì)算機(jī)實(shí)現(xiàn)上述游戲。
    *問題分析與算法設(shè)計(jì)
     計(jì)算機(jī)解決勝這類問題的關(guān)鍵是要找出問題的規(guī)律,或者說是要制定一套計(jì)算機(jī)行動(dòng)的規(guī)則。分析本題,先用人來解決問題,可總結(jié)出以下規(guī)則:
     (1) 黑子向左跳過白子落入空格,轉(zhuǎn)(5)
     (2) 白子向右跳過黑子落入空格,轉(zhuǎn)(5)
     (3) 黑子向左移動(dòng)一格落入空格(但不應(yīng)產(chǎn)生棋子阻塞現(xiàn)象),轉(zhuǎn)(5)
     (4) 白子向右移動(dòng)一格落入空格(但不應(yīng)產(chǎn)生棋子阻塞現(xiàn)萌),轉(zhuǎn)(5)
     (5) 判斷游戲是否結(jié)束,若沒有結(jié)束,則轉(zhuǎn)(1)繼續(xù)。
     所謂的“阻塞”現(xiàn)象就是:在移動(dòng)棋子的過程中,兩個(gè)尚未到位的同色棋子連接在一起,使棋盤中的其它棋子無法繼續(xù)移動(dòng)。例如按下列方法移動(dòng)棋子:
     0
    ○ ○ ○ . ● ● ●
     1 ○ ○ . ○ ● ● ●
     2 △ ○ ○ ● ○ . ● ●
     3
    ○ ○ ● . ○ ● ●
     4 兩個(gè)●連在一起產(chǎn)生阻塞
    ○ ○ ● ● ○ . ●
     或4 兩個(gè)白連在一起產(chǎn)生阻塞
    ○ . ● ○ ○ ● ●
     產(chǎn)生阻塞的現(xiàn)象的原因是在第2步(△狀態(tài))時(shí),棋子○不能向右移動(dòng),只能將●向左移動(dòng)。
     總結(jié)產(chǎn)生阻塞的原因,當(dāng)棋盤出現(xiàn)“黑、白、空、黑”或“白、空、黑、白”狀態(tài)時(shí),不能向左或向右移動(dòng)中間的棋子,只移動(dòng)兩邊的棋子。
     按照上述規(guī)則,可以保證在移動(dòng)棋子的過程中,不會(huì)出現(xiàn)棋子無法移動(dòng)的現(xiàn)象,且可以用最少的步數(shù)完成白子和黑子的位置交換。
    *程序與程序注釋
    #include
    int number;
    void print(int a[]);
    void change(int *n,int *m);
    void main()
    {
     int t[7]={1,1,1,0,2,2,2}; /*初始化數(shù)組1:白子 2:黑子 0:空格*/
     int i,flag;
     print(t);
     while(t[0]+t[1]+t[2]!=6||t[4]+t[5]+t[6]!=3) /*判斷游戲是否結(jié)束
     若還沒有完成棋子的交換則繼續(xù)進(jìn)行循環(huán)*/
     {
     flag=1; /*flag 為棋子移動(dòng)一步的標(biāo)記1:尚未移動(dòng)棋子 0:已經(jīng)移動(dòng)棋子*/
     for(i=0;flag&&i<5;i++) /*若白子可以向右跳過黑子,則白子向右跳*/
     if(t[i]==1&&t[i+1]==2&&t[i+2]==0)
     {change(&t[i],&t[i+2]); print(t); flag=0;}
     for(i=0;flag&&i<5;i++) /*若黑子可以向左跳過白子,則黑子向左跳*/
     if(t[i]==0&&t[i+1]==1&&t[i+2]==2)
     {change(&t[i],&t[i+2]); print(t); flag=0;}
     for(i=0;flag&&i<6;i++) /*若向右移動(dòng)白子不會(huì)產(chǎn)生阻塞,則白子向右移動(dòng)*/
     if(t[i]==1&&t[i+1]==0&&(i==0||t[i-1]!=t[i+2]))
     {change(&t[i],&t[i+1]); print(t);flag=0;}
     for(i=0;flag&&i<6;i++) /*若向左移動(dòng)黑子不會(huì)產(chǎn)生阻塞,則黑子向左移動(dòng)*/
     if(t[i]==0&&t[i+1]==2&&(i==5||t[i-1]!=t[i+2]))
     { change(&t[i],&t[i+1]); print(t);flag=0;}
     }
    }
    void print(int a[])
    {
     int i;
     printf("No. %2d:.............................\n",number++);
     printf(" ");
     for(i=0;i<=6;i++)
     printf(" | %c",a[i]==1?'*':(a[i]==2?'@':' '));
     printf(" |\n .............................\n\n");
    }
    void change(int *n,int *m)
    {
     int term;
     term=*n; *n=*m; *m=term;
    }