基于剪枝的对抗性搜索的井字棋
来源:互联网 发布:软件下载app 编辑:程序博客网 时间:2024/06/16 14:10
基于剪枝对抗搜索的井子棋报告
1.问题
井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋比较类似,由于棋盘一般不画边框,格线排成井字故得名。只要一方的三个棋子连城一条线,就算胜出。
玩过这个游戏的人大都会发现,如果两个玩家都作出最好的选择,这个游戏是一定会平局的。所以,井字棋最常使用是作为儿童游戏。虽然这个游戏看上去很简单,但是它的整个过程却复杂得多。从理论上讲,“井字棋”一共可能有19683种现象和362880种过程。(如果不把追求获胜的判定算进去的话)当获胜导致游戏结束时,就只剩下255168种可能过程。假设其中X都是先手:那么其中131184次将为X获胜,46080次为平局,77904次为O获胜。而当无视O和X的序列并消除所有对称的情况,就只剩下138种可能的结果了,其中91次是由X获胜,44次是由O获胜,只有3个独特的情况下才产生平局。
所以对于下棋着两方都是人的时候比较简单,但如果要让电脑实现一方就需要一个比较优良的算法。
2.原理
本文就选择使用基于剪枝的对抗搜索技术,如下图:
图 1
我们用min代表先手方。算法的原理是把下棋的所有可能建成一棵多叉树,就像图1所示。我们遍历这棵多叉树,首先计算叶子节点的启发值,再回溯计算各个节点的启发值。
对于叶子节点启发值的计算我们采用这种方法,用棋盘空的地方全部填成x所获胜的数目减去棋盘空的地方全部填成o所获胜的数目。对于其他非叶子节点的启发值用下面的函数来求。
最后根据启发值,max选启发值最大的落子方式,min选择启发值最小的落子方式。其中用到了两种剪枝的技巧。
首先是对称剪枝,如下图:
图2
其实x走这几个位置都是一样的,因为它是对称的,我们用1,2,3,4,5,6,7,8 ,9分别代表落子的可能。
1
2
3
4
5
6
7
8
9
表1
用A代表上下对称,用B代表左右对称,用C代表\对称,用D代表/对称。如果是A的情况可能走棋的位置有{1,2,3,4,5,6}并且是在这些位置没有棋子的前提下。同理得到下表:
A
1,2,3,4,5,6
B
1,2,4,5,7,8
C
1,2,3,5,6,9
D
1,2,3,4,5,7
AB
1,2,4,5
CD
1,2,3,5
ABCD
1,2,5
表2
然后在树的深度遍历的过程中也用到了αβ剪枝原理如下:
对于max层的结点a来说,如果已经得到了a的一个子节点a1的启发值(min层),再去搜索a其它子节点ai(min层),如果ai的某一个子节点(max层)启发值小于a1的启发值就把ai剪枝。
3.算法流程
注:电脑作为后手。
1> 玩家a下一子;
2> 电脑计算a是否获胜,获胜则结束不获胜继续;
3> 电脑判断是否需要防守(就是a有没有已经两子连成一线),若需要防守就在防守位置落子然后判断电脑是否获胜,获胜结束否则跳转1>,如果不需防守就继续;
4> 根据已走的信息建立一棵搜索树(要用到对称剪枝),然后深度遍历这棵树并计算各个节点的启发值(要用到αβ剪枝)。选择启发值最大的位置落子,
判断电脑是否获胜,若获胜则结束,否则跳转1>;
4.算法实现说明
在程序的编写过程中发现,难点是在树的创建上,要考虑到一个节点的子节点是不确定个数的,还有节点只需要确定的深度,以及之前所说的对称剪枝。
首先定义一个长度为9的全局数组来记录双方走棋的过程及当前的状态,我们参考表1,比如1,5,6,7.就是指先手下1的位置,电脑下5的位置,然后先手下6的位置,电脑下7的位置,目前下了四步棋。
对于建图的时候,把每个节点定义成如下的数据结构。
typedef struct node
{
int step[10]; //保存下棋过程的信息
struct node *next[10]; //指向节点的指针
int qifazhi; //此节点的启发值
int stepzhi; //此节点最后选择下的位置
} node,*nodet;
节点指针选了10个,其中next[0]是没有意义的,然后next[1]——next[9]对应1——9的位置。当然创建搜索树的时候不会用到所有的next[i],用不到的就赋NULL;
建图用的是递归方法,伪代码如下;
creat(nodet &a,int *step,int p)
{
If p<=0 //p的作用是为了控制创建搜索树的深度
退出
p=p-1;
a=newnode;
给a->step[i]赋值
for(i=0;i<10;i++)
a->next[i]=NULL;
for(i=1;i<=9;i++)
{
参考表1与数组step;(用对成剪枝)
If i这一点可以落子
{ step[k]=i;
creat(a->next[i],step,p);}
}
}
5.结果展示
因为这个问题不复杂,并且计算机计算能力强大,最多下成平局,先手不会获胜。
- 基于剪枝的对抗性搜索的井字棋
- 搜索时的剪枝
- 搜索算法的剪枝优化
- 朴素搜索dfs, 简单的剪枝搜索
- 基于Caffe的CNN剪枝
- 基于Caffe的CNN剪枝
- 基于Caffe的CNN剪枝
- [SCU 4497] GooZy的游戏时间 (基于搜索时间的剪枝)
- 基于剪枝搜索的分治算法(原理)--找到第k个顺序统计量
- 谈搜索算法的剪枝优化(转载)
- 搜索的优化算法——剪枝
- 谈搜索算法的剪枝优化
- 搜索的优化算法——剪枝
- 浅谈"对抗搜索"的alpha-beta 剪枝
- Shredding Company(简单的搜索剪枝)
- caioj.1041 简单的搜索剪枝
- 输入法之模型剪枝一(基于熵的剪枝)
- 基于深度优先搜索的回溯算法(递归剪枝及奇偶性剪枝好题!):HDOJ 1010 - Tempter of the Bone
- myeclipse关联SDK源码
- solr与.net系列课程(七)solr主从复制
- pdf文件如何免费转换成txt文件
- POJ 1269 Intersecting Lines 判断直线相交
- memcpy memset memmove 区别(部分转载)
- 基于剪枝的对抗性搜索的井字棋
- SJTU OJ 1006 求和游戏
- Android音乐播放-MediaPlayer
- ViewPager+Fragment不预加载页面
- ActiveReports 报表应用教程 (1)---Hello ActiveReports
- 安装git之后,桌面图标出现很多的蓝色问号
- left outer join 的where语句写法
- pdf文件如何免费转换成txt文件
- vs下安排自己的C++项目目录