今天在看《精通Windows Sockets 网络开发——基于Visual C++》(孙海民 编著,人民邮电出版社出版)这本书的时候,有一个网络五子棋游戏的实例,个人觉得除了服务器和客户端通信、管理用户列表之外,在每一步中判断黑方和白方哪一方获胜是这个游戏程序的关键。所以将源代码贴在这里,供大家学习参考:
说明:这个程序不能直接运行,只是说明判断胜负的算法。
#include <iostream> #include <math.h> #define MAX 30 //五子棋棋盘大小是30×30的正方形,每个单元格是边长为1的正方形 using namespace std; int color[MAX][MAX];//存储棋子的颜色 bool IsWin(int x,int y) { int xMin = max(0,x - 4);//水平位置最小值 int xMax = min(x + 4,MAX - 1);//水平位置最大值 int yMin = max(0,y - 4);//垂直位置最小值 int yMax = min(y + 4,MAX - 1);//垂直位置最大值 int i,j,p,q; int sum; //初始化棋子颜色 for(i = 0;i < MAX;i++) for(j = 0;j < MAX;j++) color[i][j] = 0; //在水平方向遍历,看是否有连续5颗相同颜色的棋子 for(i = xMin;i <= xMax - 4;i++) { sum = 0; for(j = i;j < i + 5;j++) { if(color[j][y] == color[x][y]) sum++; else break; } if(sum == 5) return true; } //在垂直方向遍历,看是否有连续5颗相同颜色的棋子 for(i = yMin;i <= yMax - 4;i++) { sum = 0; for(j = i;j < i + 5;j++) { if(color[x][i] == color[x][y]) sum++; else break; } if(sum == 5) return true; } //左上角位置,从(x,y)开始沿左上方寻找,找到一个满足条件的最大正方形,则从正方形的左上顶点开始沿对角线遍历 for(i = x,j = y;i > xMin && j > yMin;i--,j--); //从左上角向右下角遍历,看是否有连续5颗相同颜色的棋子 for(;i <= xMax - 4 && j <= yMax - 4;i++,j++) { sum = 0; for(p = i,q = j;p < i + 5;p++,q++) { if (color[p][q] == color[x][y]) sum++; else break; } if(sum == 5) return true; } //左下角位置,从(x,y)开始沿左下方寻找,找到一个满足条件的最大正方形,则从正方形的左下顶点开始沿对角线遍历 for(i = x,j = y;i > xMin && j < yMax;i--,j++); //从左下角向右上角遍历,看是否有连续5颗相同颜色的棋子 for(;i <= xMax - 4 && j >= yMin + 4;i++,j--) { sum = 0; for(p = i,q = j;p < i + 5;p++,q--) { if (color[p][q] == color[x][y]) sum++; else break; } if(sum == 5) return true; } return false; }
后来发现这样不对,比如 xMin = yMin = 0但(x , y) = (5 , 3)时,要从(2 ,0)开始向右下方遍历,而不是从(0 ,0)开始。所以要用 for(i = x,j = y;i > xMin && j > yMin;i--,j--)循环从(x,y)开始沿左上方寻找,找到一个满足条件的最大正方形,则从正方形的左上顶点 (2 ,0)开始沿对角线遍历。
此外,我觉得这个算法还可以优化。例如:当前在(5 , 3)位置放了一颗黑色的棋子,第一次遍历的路径为 :A(2, 0)(黑色)——B(3 ,1)(黑色)——C(4,2)(白色),到C点时内层循环退出,继续从B3 ,1)开始遍历,其实因为C(4,2)是白色,所以内层循环没必要再遍历检查A到C之间的点,直接从下一个点D(5,3)开始遍历。