五子棋

image

  我是在大一的時候才接觸到五子棋的,在這之前,小時候玩過一個叫五雷炮的遊戲,是用象棋棋盤和棋子代替的,規則大同小異。經過十年寒窗苦讀,其實,我也就高中三年苦過,小學初中都是玩過來的,當然,由於沒有什麼學習天分,這樣做的結果是上了一個民辦高中還要交7千元的代培費,所以,小朋友千萬不要模仿。好在高考分數也上了一本分數線,這纔有了大學前幾年的悠哉日子。和很多剛上大學的人一樣,我的心態就是好好輕鬆兩年,我有一個志同道合的室友小華,在大一那年裏,我們除了一起吃喝玩樂外,在寢室裏,最多就是一起玩五子棋。

   真正讓五子棋和編程發生一點聯繫的是大二的時候,那時候意外的發現我的大一物理老師開始給我們上visual c++,這無異於逃學威龍裏的周星星在第三集時發現他的記性不好的生物老師居然成了一位法醫。由於之前只上過vb,c和sdk編程全部沒上過,從對MFC排斥到上手花了一段時間,也就是這門課上到一半的時候,老師給我們佈置了一些作業,其中一個題目是做一個五子棋的遊戲。在當時,算是高難度的東西,我花了一點時間弄出來,老師走訪寢室查看作業的時候正好查到,當時的效果無疑是轟動的,一下子名聲大噪,呵呵,不由得想起圍城裏,方鴻漸初回國媒體前呼後擁的情景,這是在小地方的好處。

   這裏,不想去涉及MFC的東西。當時的編程主要是去判斷落子的位置,然後判斷落子後,是否獲勝這一思路,當時,渾然沒有去判斷禁手這一情形,這放到今天當然是不行了。下面就關於落子後,是否取勝,有禁手的思路展開一下。

image

如上圖所示,對於黑29棋子而言,落子時,需要考查有***線條標誌的幾個方向上的棋子分佈,看是否成五子,在成五子的情況下,禁手全部失效,若沒有則要考查是否禁手。所以思路也很簡單,分別對上述方面進行掃描,記錄下三連珠,四連珠的情況,並記錄下最大連珠。對於黑棋而言,若未存在五子連珠,則判斷是否存在禁手。對於白棋而言,本身不受禁手約束,只要判斷最大連珠超過5即獲勝。值得注意的是三三禁手需要考慮活三和活四的情況,對於假禁手要會區分。

 

核心代碼

/*在(i,j)處放置bw標誌的棋,判斷是否獲勝,禁手等情況*/

/*在(i,j)處放置bw標誌的棋,判斷是否獲勝,禁手等情況*/
void scan(int i,int j,int bw)
{
    int k,z, x,y,dir_x,dir_y,idx;
    int space_skip[2],temp[2];
    int three_count = 0,four_count =0,max_concount = 0;
    set_chess(i,j,bw);
    for(k=0;k<4;k++)  // //對四個方向進行掃描,取得連珠情況
    {    
        for(z=0;z<2;z++)     //單條線又可以分爲兩個方向
        {
            x = i;
            y = j;
            dir_x = scan_l[k][0]*scan_d[z];
            dir_y = scan_l[k][1]*scan_d[z];
            space_skip[z] = 0;    //掃描線上遇到空點個數
            temp[z] = 0;         //掃描線上遇到空點後記錄的連珠個數
            while(i>=0&&i<TABLE_SIZE&&j>=0&&j<TABLE_SIZE)
            {
                idx =x*TABLE_SIZE+y;
                if(space_skip[z]==1)
                {
                    if(five_table[idx]==bw)
                    {
                        temp[z]++;
                    }
                    else //空點或者非目標點,搜索結束
                    {
                        if(five_table[idx]==EMPTY_NODE)  space_skip[z]++;
                        break;
                    }               
                }
                else    //當前點的連珠數       
                {
                    if(five_table[idx]==bw)
                    {
                        line[k].max_concount++;
                    }
                    else if(five_table[idx]==EMPTY_NODE)
                    {
                        space_skip[z]++;
                    }   
                    else
                    {
                        break;
                    }
                }
                x+=dir_x;
                y+=dir_y;
            }
        }
        line[k].max_concount--;
        if(space_skip[0]>0&&space_skip[1]>0&&temp[0]==0&&temp[1]==0)
        {       
            setline(&line[k],line[k].max_concount,2);
        }
        for(z =0;z<2;z++)
        {
            if(temp[z]!=0)  //一邊被另一方的棋子堵住
            {
                setline(&line[k],line[k].max_concount+temp[z],space_skip[z]);
            }
        }
        three_count+=line[k].three_count;
        four_count+=line[k].four_count;
        if(line[k].max_concount>max_concount) max_concount = line[k].max_concount;
    }
    printf("三連珠個數 :%d   \n",three_count);
    printf("四連珠個數 :%d   \n",four_count);
    printf("最大連珠 :%d   \n",max_concount);

    if(bw==BLACK_CHESS)
    {

      if(max_concount==5) printf("黑方獲勝  \n");
      else
      {
          if(three_count>=2) printf("三三禁手  \n");
          if(four_count>=2) printf("四四禁手  \n");
          if(max_concount>5) printf("長連禁手  \n");
      }

    }
    else
    {
        if(max_concount>=5)
        {
            printf("白方獲勝 \n");
        }
    }
}

爲了方便解釋問題,這裏設置棋盤爲10X10大小

棋盤座標爲左上角(0,0)-右下角(9,9),通過落子(i,j)檢驗一下判別規則是否有效

 

image

分別對以上幾個黃點進行測試,測試點由▲標記

 

黑棋 測試點 (3,2)

image

黑棋 測試點(0,5)

image

黑棋測試 (0,3)

image 

白棋 測試(5,3)

image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章