五子棋的历史
连子棋类游戏起源很早,在四千年前的两河文明就有古西亚连棋。
五子棋则咸信是流传于古中国的传统棋种之一,至今仍在民间广泛流传,规则相当简单。或许因没有形成一套独立完整的棋种理论及文化内涵,更无制定公平完善的规则来解决黑白平衡问题,一直没有得到发展,所以没有像围棋、象棋等传统棋类流传广泛,导致缺少可考古的棋具,也没像直棋、方棋等乡土棋类记载在地方县志、古人笔记等文献。
五子棋在传入日本后,被日本人发扬光大,自1899年日本棋士黒岩涙香证明了原始规则的五子棋先下必胜后,五子棋迈入一条不断改良的道路,经过数十年的修改、验证、再修改,最终发展出加入禁手的五子棋,并经过公开征名,称为连珠(RENJU),因此规则在日本成型,又称为日式规则或连珠规则。原始规则在中国依然有人在玩,也被称为无禁规则、自由规则,有软件可验证黑手必胜(这个稍后再证明)。
连珠规则禁止先下的黑棋下出双活三、双四、长连(超过五子以上的连线)下出则判败,此举限制黑棋的取胜方式,白棋则增加逼迫黑子下出禁手来取胜的手 段,使黑棋的优势稍稍减少。不过禁手也许对初学者来说是一种障碍,但下久后会发现,禁手使得双方棋手必需更加精准的掌握棋子的落点,增加了连珠的技术性、 复杂性及趣味性。
又过了几十年,人们发现单单加入禁手,尚无法完全平衡黑棋一子之先的优势,因此在国际比赛使用的“RIF规则”,在连珠规则的基础上,又加入了三手交换及五手两打,算第一个可以真正合乎公平竞技的职业规则。
Problem——该问题,是用一串二维数组装载的字符串,用.表示空,用W表示白棋,用B表示黑棋,来判断目前的局面中的当前走棋的一方是否赢了整盘棋。
Solve:
/*
该程序可以判定当前的一方是否获胜,如果暂时没有获胜或者已经告负,本
程序会有相应的输出。
AI的策略基本上和连连看的相似,也用的是queue容器+BFS
(1)判断当前局势,利用目前棋盘上黑子和白子的数量进行比较
(2)五子连环必须是恰好有五个子,也就是说,沿端点方向上的点应该是空格的
(3)表面上是八个方向,实际上考虑到对称性,四个方向即可
(4)在for循环的条件判断上加上flag,找到一例,即可退出循环
*/
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 }