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