五子棋是一种受大众广泛喜爱的游戏,其规则简单,变化多端,非常富有趣味性和消遣性。这里设计和实现了一个人机对下的五子棋程序,采用了博弈树的方法,应用了剪枝和最大最小树原理进行搜索发现最好的下子位置。介绍五子棋程序的数据结构、评分规则、胜负判断方法和搜索算法过程。
一、相关的数据结构
关于盘面情况的表示,以链表形式表示当前盘面的情况,目的是可以允许用户进行悔棋、回退等操作。
- CList StepList;
-
-
- struct Step
- {
- int m;
- int n;
- char side;
- };
-
-
- char FiveArea[FIVE_MAX_LINE][FIVE_MAX_LINE];
-
-
-
-
-
- CList CountList;
-
- class CBoardSituation
- {
- CList StepList;
- char FiveArea[FIVE_MAX_LINE][FIVE_MAX_LINE];
- struct Step machineStep;
- double value;
- }
二、评分规则
对于下子的重要性评分,需要从六个位置来考虑当前棋局的情况,分别为:-,|,/,\,//,\\
实际上需要考虑在这六个位置上某一方所形成的子的布局的情况,对于在还没有子的地方落子以后的当前局面的评分,主要是为了说明在这个地方下子的重要性程度,设定了一个简单的规则来表示当前棋面对机器方的分数。
基本的规则如下:
- 判断是否能成5, 如果是机器方的话给予100000分,如果是人方的话给予-100000 分;
- 判断是否能成活4或者是双死4或者是死4活3,如果是机器方的话给予10000分,如果是人方的话给予-10000分;
- 判断是否已成双活3,如果是机器方的话给予5000分,如果是人方的话给予-5000 分;
- 判断是否成死3活3,如果是机器方的话给予1000分,如果是人方的话给予-1000 分;
- 判断是否能成死4,如果是机器方的话给予500分,如果是人方的话给予-500分;
- 判断是否能成单活3,如果是机器方的话给予200分,如果是人方的话给予-200分;
- 判断是否已成双活2,如果是机器方的话给予100分,如果是人方的话给予-100分;
- 判断是否能成死3,如果是机器方的话给予50分,如果是人方的话给予-50分;
- 判断是否能成双活2,如果是机器方的话给予10分,如果是人方的话给予-10分;
- 判断是否能成活2,如果是机器方的话给予5分,如果是人方的话给予-5分;
- 判断是否能成死2,如果是机器方的话给予3分,如果是人方的话给予-3分。
实际上对当前的局面按照上面的规则的顺序进行比较,如果满足某一条规则的话,就给该局面打分并保存,然后退出规则的匹配。注意这里的规则是根据一般的下棋规律的一个总结,在实际运行的时候,用户可以添加规则和对评分机制加以修正。
三、胜负判断
实际上,是根据当前最后一个落子的情况来判断胜负的。
实际上需要从四个位置判断,以该子为出发点的水平,竖直和两条分别为 45度角和135度角的线,目的是看在这四个方向是否最后落子的一方构成连续五个的棋子,如果是的话,就表示该盘棋局已经分出胜负。具体见下面的图示:
四、搜索算法实现描述
注意下面的核心的算法中的变量currentBoardSituation,表示当前机器最新的盘面情况, CountList表示第一层子节点可以选择的较好的盘面的集合。
核心的算法如下:
- void MainDealFunction()
- {
- value=-MAXINT;
- CalSeveralGoodPlace(currentBoardSituation,CountList);
-
-
-
-
-
- pos=CountList.GetHeadPosition();
- CBoardSituation* pBoard;
- for(i=0;ivalue=Search(pBoard,min,value,0)
- {
- Value=Select(value,pBoard->value,max);
-
- }
-
-
- for(i=0;ivalue)
-
- {
- currentBoardSituation=pBoard;
- PlayerMode=min;
- Break;
- }
- }
-
-
-
-
-
-
- double Search(CBoardSituation& board,int mode,double oldvalue,int depth)
- {
- CList m_DeepList;
- if(deptholdvalue==TRUE)
- {
- {
- if(mode==max)
- value=select(value,search(successorBoard,min,value,depth+1),max);
- else
- value=select(value,search(successorBoard,max,value,depth+1),min);
- }
- return value;
- }
- else
- {
- if (goal(board)!=0)
-
- return goal(board);
- else
- return evlation(board);
- }
- }
-
-
-
-
-
-
- double Select(double a,double b,int mode)
- {
- if((a>b && mode==max)||(a< b && mode==min))
- return a;
- else
- return b;
- }
五、小结
在Windows操作系统下,用VC++实现了这个人机对战的五子棋程序。
和国内许多只是采用规则或者只是采用简单递归而没有剪枝的那些程序相比,在智力上和时间有效性上都要好于这些程序。同时所讨论的方法和设计过程为用户设计其他的游戏(如象棋和围棋等)提供了一个参考。 |