吴昊品游戏核心算法 Round 5 —— 五子棋(无禁手)后台的判胜负AI(bfs+queue容器)(HDOJ 2699)...

五子棋的历史

 

 

连子棋类游戏起源很早,在四千年前的两河文明就有古西亚连棋。

五子棋则咸信是流传于古中国的传统棋种之一,至今仍在民间广泛流传,规则相当简单。或许因没有形成一套独立完整的棋种理论及文化内涵,更无制定公平完善的规则来解决黑白平衡问题,一直没有得到发展,所以没有像围棋象棋等传统棋类流传广泛,导致缺少可考古的棋具,也没像直棋方棋等乡土棋类记载在地方县志、古人笔记等文献。

五子棋在传入日本后,被日本人发扬光大,自1899年日本棋士黒岩涙香证明了原始规则的五子棋先下必胜后,五子棋迈入一条不断改良的道路,经过数十年的修改、验证、再修改,最终发展出加入禁手的五子棋,并经过公开征名,称为连珠(RENJU),因此规则在日本成型,又称为日式规则或连珠规则。原始规则在中国依然有人在玩,也被称为无禁规则、自由规则,有软件可验证黑手必胜(这个稍后再证明)。

连珠规则禁止先下的黑棋下出双活三、双四、长连(超过五子以上的连线)下出则判败,此举限制黑棋的取胜方式,白棋则增加逼迫黑子下出禁手来取胜的手 段,使黑棋的优势稍稍减少。不过禁手也许对初学者来说是一种障碍,但下久后会发现,禁手使得双方棋手必需更加精准的掌握棋子的落点,增加了连珠的技术性、 复杂性及趣味性。

又过了几十年,人们发现单单加入禁手,尚无法完全平衡黑棋一子之先的优势,因此在国际比赛使用的“RIF规则”,在连珠规则的基础上,又加入了三手交换及五手两打,算第一个可以真正合乎公平竞技的职业规则。

  Problem——该问题,是用一串二维数组装载的字符串,用.表示空,用W表示白棋,用B表示黑棋,来判断目前的局面中的当前走棋的一方是否赢了整盘棋。

  Solve:

 /*
   该程序可以判定当前的一方是否获胜,如果暂时没有获胜或者已经告负,本
   程序会有相应的输出。
   AI的策略基本上和连连看的相似,也用的是queue容器+BFS
   (1)判断当前局势,利用目前棋盘上黑子和白子的数量进行比较
   (2)五子连环必须是恰好有五个子,也就是说,沿端点方向上的点应该是空格的
   (3)表面上是八个方向,实际上考虑到对称性,四个方向即可
   (4)在for循环的条件判断上加上flag,找到一例,即可退出循环
 */
 

  1 #include<iostream>
  2  #include<queue> // STL里面的queue容器
  3    using  namespace std;
  4  
  5   struct Node  // 每个点有一个坐标,最大连通数以及方向
  6   {
  7     char x,y,time,dirc;
  8     bool no_stone;       
  9  };
 10  
 11   char map[ 15][ 15],c; // 定义一个二维数组,表示棋盘,c表示现在轮到谁
 12   
 13   int dir[ 4][ 2]={{ 0, 1},{ 1, 0},{ 1,- 1},{ 1, 1}}; // 四个方向
 14   
 15    // BFS搜索,和之前的连连看类似
 16    bool bfs( int x, int y)
 17  {
 18    queue<Node> Q;
 19    Node first,next;
 20     int i;   
 21    first.x=x;
 22    first.y=y;
 23    first.no_stone= false;
 24    first.time= 1;
 25    first.dirc=- 1;
 26    Q.push(first);
 27    
 28     while(!Q.empty())
 29    {
 30      first=Q.front();
 31      Q.pop();
 32       // 从第一个点开始,保证有且仅有五个是连在一起的,用no_stone标识没有多连
 33        if(first.time== 5&&first.no_stone)
 34      {
 35         return  true;                                 
 36      }             
 37       for(i= 0;i< 4;i++)
 38      {
 39         // 初始方向不确定
 40          if(first.dirc==- 1||first.dirc==i)
 41        {
 42          next.x=first.x+dir[i][ 0];
 43          next.y=first.y+dir[i][ 1];
 44           if(next.x>= 0&&next.x< 15&&next.y>= 0&&next.y< 15)
 45          {
 46            next.dirc=i;
 47            next.time=first.time+ 1;
 48             // 唯独不标识对手的棋子,自己的棋子和空棋子用no_stone区分
 49              if(map[next.x][next.y]==c)                              
 50            {
 51              next.no_stone=first.no_stone;
 52              Q.push(next);                                                        
 53            }              
 54             else  if(map[next.x][next.y]== ' . '&&!first.no_stone)
 55            {
 56              next.no_stone= true;
 57              Q.push(next);     
 58            }  
 59          }                                 
 60        }                
 61      }     
 62    }  
 63     return  false;
 64  }
 65  
 66   int main()
 67  {
 68     int T;
 69    scanf( " %d ",&T);
 70     while(T--)
 71    {
 72       int i,j;
 73       int white_num= 0,black_num= 0;
 74      getchar();  // 读入一个回车键
 75        for(i= 0;i< 15;i++)
 76      {
 77        gets(map[i]);                 
 78      }          
 79       for(i= 0;i< 15;i++)
 80      {
 81         for(j= 0;j< 15;j++)
 82        {
 83           if(map[i][j]== ' W ')
 84          {
 85            white_num++;                  
 86          }             
 87           else  if(map[i][j]== ' B ')
 88          {
 89            black_num++;     
 90          }     
 91        }                
 92      }
 93       // 记录黑白棋子的数量,主要是判断当前下棋方是黑还是白
 94        if(black_num>white_num)
 95      {
 96        c= ' W ';                       
 97      }
 98       else
 99      {
100        c= ' B ';    
101      }
102       bool flag= true;
103       // 只要找到一个“五子连”就可以了
104        for(i= 0;i< 15&&flag;i++)
105      {
106         for(j= 0;j< 15&&flag;j++)
107        {
108           if(map[i][j]==c)
109          {
110            flag=!bfs(i,j);                
111          }                       
112        }                       
113      }
114       if(flag) printf( " NO\n ");
115       else printf( " YES\n ");
116    }
117     return  0;    
118  }

 

 

转载于:https://www.cnblogs.com/tuanzang/archive/2013/02/27/2935770.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值