1.     问题定义

一字棋游戏,包括两个选手。用户可以在一个3*3的棋盘上任意的选择空闲的位置拜访棋子,最早在水平方向上,或者垂直方向上或者对角线方向上形成三子一线者获胜。棋盘如图1所示。这里我们实现的是用户和计算机进行对弈。本程序要实现的是让计算机可以自动的根据当前棋局计算下一步对自己最有利的走步,尽可能的朝着可以让计算机获胜的方向走步。需要采用极大极小搜索算法。

图1.一字棋棋盘

2.     技术现状

目前一字棋作为各个高校的人工智能教学的典型范例,在技术方面一般都采用极大极小搜索算法,理论层面比较成熟,有很多资料可以参考。大部分教学资料的一字棋都采用C++语言编写,因为本人对C++语言不是很熟悉,更不熟悉C++语言的界面操作,所以在这里的所有实现都通过C#来实现。在刘峡壁老师编著的《人工智能导论——方法与系统》[1]一书中,对一字棋算法的极大极小搜索有着比较详细的介绍,本系统的实现,主要参照了刘峡壁老师一书中对一字棋算法的介绍。

3.     本文采用方法

3.1  极大极小搜索

在本博弈算法中,采用极大极小搜索[2]方法搜索计算机的下一步走步方法,每一次走步的时候以计算机当前所面对的棋局状态作为根顶点,生成一棵有限深度的博弈子树,然后从该博弈子树的叶结点向上回溯,确定在根顶点处的当前最好的策略,找到一条当前最好行动的边。在生成博弈子树的过程中,计算机己方对应的走步状态的节点称为MAX节点,对应的对手走步的节点成为MIN节点。

设计的棋局状态的估价函数为,当前棋盘下,在整个棋盘中己方可以三子一线的个数减去对方可以三字一线的个数。假设当前状态下己方三字一线的个数为E(MAX),对方的三字一线的个数为E(MIN),则当前棋局的估价函数为: e= E(MAX)- E(MIN)。对于MAX节点,MAX具有主动权,可以从中选择对自己最好的走步,既估值最大的走步。因此MAX顶点的子节点之间是“或”的关系,MAX顶点的倒退值应该取其子节点估值的极大值;MIN顶点,主动权掌握在MIN手中,为了取胜,MAX需要做最坏的打算,应该考虑到MIN会选择对自己最好的,从而对MAX最差的走步,既估值最小的走步,因此MIN顶点的子节点之间是“与”的关系,MIN顶点的倒推值应该取子节点的最小值。

关于当前棋局的估值计算,请参考图2。图2是一个棋局状态,通过统计其中的不同棋子可以实现的三点一线的个数来计算当前棋局的估值。从图2中可以看出,叉子的棋子当前可以三子一线的个数为3,分别为横行第三行,竖列第一列,还有次对角线。圆圈棋子的当前可以三点一线的个数为2,分别为横行第一行,竖列第三列。然后可以得知,对于计算机(计算机持有叉子棋子),当前棋局的估值为3-2=1。

图2. 一个棋局状态

一个一字棋的走步搜索过程如图3所示。

图3. 一字棋搜索过程

3.2  α-β剪枝

在极大极小搜索过程中,首先生成博弈子树,然后计算各个顶点的估值,这一过程中,生成子树和计算顶点的估值是彼此分离的,在本程序中,构造博弈子树采用递归的方法构造,在递归退出的过程中,由子节点的估值计算返回节点的估值。但是极大极小搜索仍然会搜索很多不必要的分支,为了减少搜索的次数,本系统实现了α-β剪枝[3]

根据倒推结果,在非叶子节点的向下分支中,剪掉那些目前尚未扩展,但是无论其是否扩展都不会改变非叶子节点倒推值的分支。为了判断分支的扩展是否会影响非叶子节点的倒推结果,需要计算MAX顶点的倒退值的最小辩解,称为α值,以及MIN节点倒推值的最大边界,称为β值。由于MAX顶点的倒推值总是其子节点的最大值,因此如果MAX子节点的估值已经确定小于MAX顶点的α值,则无论该子节点下的为扩展分支情况如何,都不会影响MAX顶点的估值。这样就不必搜索这个子节点一下的所有分支。同理,如果MIN节点的子节点的估值已经确定大于β值,则不必再搜索该顶点下的为扩展分析,可以进行剪枝。

一个α-β剪枝的示例请看图4。

图4.α-β剪枝

在图4中,建立的搜索子树的起始点为S0,从S0开始搜索所有的可以的走步。S0为MAX节点,然后对应的下一层为MIN节点,然后MAX节点与MIN节点相互交错。在最后一层为MAX节点,每个节点的估值已经写在这个节点的下面。F节点为MIN节点,F节点的估值应该去子节点的最小值,F的子节点中最小值为K的估值4,所以F的估值为4。这样C节点为MAX节点,应该取子节点估值的最大值。G节点取子节点的最小值,G节点的子节点N的估值为1,所以不论G的其他的子节点的估值为何,G节点的估值都会小于等于1,这样,C节点取子节点估值的最大值,已经知道了G节点的估值肯定小于等于1,所以无论G节点的其他分支如何扩展,都不会影响C节点的现在的估值。所以这样就可以省去了G节点的其他的分支的扩展。其他的节点的剪枝同样的道理。

3.3  进化算法

由于一直没有想出如何用适合进化算法计算表示棋盘状态的数据结构,所以在采用进化算法[4-6]计算走步的时候,仍然采用了上面设计的棋盘状态表示。进化算法简单的采用了选择突变两个操作,没有选择交叉操作的原因也是因为没有合理的数据结构进行交叉运算。首先在当前的棋局状态下随机的生成一些走步,然后对这些走步以一定的概率进行突变,最后进行估值,选择估值最好的走步。

4.     实验结果

4.1  没有剪枝的实验结果

在没有剪枝的计算机搜索走步的过程中,根据搜索的深度,需要搜索的走步的数量非常多。第一次计算机搜索了400步,第二次计算机搜索了156步,第三次走步计算机搜索了40步。一个典型的走步过程如图5-7所示。从图7中可以看到计算机获胜。

图5. 下棋过程1

图6. 下棋过程2

图7. 下棋过程3

4.2  α-β剪枝搜索结果

带有α-β剪枝的搜索结果中,可以明显的看到搜索的次数很显著的减少了。图8-11展示了一个带有剪枝过程的搜索结果。在图11中可以看到计算机获胜。然而存在的问题是,添加α-β剪枝算法的极大极小搜索的效果不如上面直接的极大极小算法效果好,因为有一些棋局找到的不是最好的走步,这个应该和剪枝算法没有什么关系,而是程序写的不合理。

图10. 带有剪枝的搜索3

图11. 带有剪枝的搜索4

4.3  进化算法搜索

由于一直没有想出如何用适合进化算法计算表示棋盘状态的数据结构,所以在采用进化算法计算走步的时候,仍然采用了上面设计的棋盘状态表示。进化算法简单的采用了选择突变两个操作,没有选择交叉操作的原因也是因为没有合理的数据结构进行交叉运算。首先在当前的棋局状态下随机的生成一些走步,然后对这些走步以一定的概率进行突变,最后进行估值,选择估值最好的走步。

因为本程序中并没有写出进化算法的精华,也没有实现真正的进化算法,所以进化算法的效果非常的差。图12-14展示了进化算法的搜索。从这些图中可以看出,进化算法的搜索,往往不能找到最优解。

图12. 进化算法1

5.     结论

通过以上实验结果,可以看出,极大极小搜索可以找到当前状态下的最优解之一,如果最优解同时有多个,则简单的选择第一个最优解。然而在极大极小的搜索过程中,可能会搜索很多无效的分支,这样就可以通过α-β剪枝方法剪去不必要的搜索分支,加快搜索速度。在本程序中,剪枝后与不剪枝的搜索速度没有什么差别,因为本程序中搜索的深度只有3层,而且棋盘非常小。如果是正规的五子棋盘或者象棋棋盘,那么剪枝就是非常有必要的了。否则搜索一个合适的走步的时间复杂度会非常高,而且也会带来空间的消耗,剪枝的时候,就减少了不必要分支的搜索,同时也就不用为这些不去搜索的分支建立搜索树中的节点,加快了搜索速度。进化算法本来可以进行搜索的优化,但是因为一直没有找到合理的用于进化算法的数据表现形式,所以这里的进化算法并没有展示出进化算的精髓,没有完全的体现进化算法的真正意义。

源程序下载地址:http://download.csdn.net/detail/weixingstudio/4040936

一字棋游戏设计-极大极小搜索相关推荐

  1. Python基础编程案例:简单的井字棋游戏设计与制作

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 前言 python井字棋游戏虽然看上去非常简陋,但是却非常值得学习. 先看怎么玩 ...

  2. C++实现的基于α-β剪枝算法的井字棋游戏

    "井字棋"游戏(又叫"三子棋"),是一款十分经典的益智小游戏,操作简单,娱乐性强.两个玩家,一个打圈(O),一个打叉(X),轮流在3乘3的格上打自己的符号,最先 ...

  3. [文档和源码分享]C++实现的基于α-β剪枝算法的井字棋游戏

    "井字棋"游戏(又叫"三子棋"),是一款十分经典的益智小游戏,操作简单,娱乐性强.两个玩家,一个打圈(O),一个打叉(X),轮流在3乘3的格上打自己的符号,最先 ...

  4. c语言编简单博弈小游戏,[2018年最新整理]实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏.doc...

    [2018年最新整理]实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏 实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏 一.实验目的与要求 (1)了解极大极小算法的原理和使用方法,并 ...

  5. c语言井字棋程序设计报告,井字棋游戏(课程设计)总结报告.doc

    井字棋游戏(课程设计)总结报告 C语言贪吃蛇游戏设计总结报告 PAGE PAGE 5 丽水学院 计算机信息学院 <C语言课程设计(短一)> 指 导 书 二 ○ 一一 年 三 附件二 封面格 ...

  6. 利用α-β搜索的博弈树算法编写一字棋游戏 python

    游戏规则 "一字棋"游戏(又叫"三子棋"或"井字棋"),是一款十分经典的益智小游戏."井字棋"的棋盘很简单,是一个 3× ...

  7. 用C语言实现简单的一字棋游戏

    问题分析设计目录 棋盘显示和标记以及棋盘的设计 搜索树叶子节点设计 搜索树设计 节点静态估值计算 完整代码 总结 棋盘显示和标记以及棋盘的设计 用int一维数组表示一字棋的棋盘位置,0~8,数组位置i ...

  8. 采用α-β算法实现井字棋游戏

    题目描述 (1)图形化界面. (2)随机选取先手后手. (3)可以人-计算机或计算机-计算机 界面效果 算法 基本思想 Max-Min算法: 采用Max-Min算法进行对抗搜索,Max和Min双方均要 ...

  9. java版井字棋的设计与实现_JAVA版井字棋的设计与实现.doc

    JAVA版井字棋的设计与实现.doc 优秀论文,值得下载 优秀论文精选 JAVA版井字棋的设计不实现 仇宾 摘要井字棋是大家所熟知的一个小游戏,虽然简单,但其中包含了一些编程的基本 技巧和基本算法,本 ...

最新文章

  1. JavaScript原型链的理解
  2. VTK:可视化算法之ClipSphereCylinder
  3. Spring 核心容器类BeanDefinition
  4. Android AutoCompleteTextView控件实现类似百度搜索提示,限制输入数字长度
  5. 关于STM32的两个小问题的总结
  6. el-table文字超出隐藏;el-table表格文字一行展示,超出隐藏,多余的内容会在 hover时显示 ;
  7. 视觉SLAM笔记(8) 齐次坐标
  8. 不能正常判断按键函数中的Flag
  9. mysql study_MySQL Study之--MySQL体系结构深入解析
  10. idea的tomcat改端口号_Tomcat修改端口
  11. Java实现12306登录和查票
  12. 大数据新闻推送你怎么看_如何看待大数据精准推送,使人的视界越来越窄?
  13. matlab 输出两列,Matlab绘制两列正弦波的叠加
  14. 2022年江苏省高职单招(数学)考试冲刺试题及答案
  15. Bugku - 秋名山老司机
  16. 【5月比赛合集】80场可报名的数据挖掘大奖赛,任君挑选!
  17. ubuntu 8000端口被占用
  18. ZOJ Problem Set - 4043 Virtual Singers(2018acm 青岛赛区热身赛)
  19. PCPNET与POINTNET的比较
  20. 正则表达式校验身份证号带出出生日期,年龄,性别

热门文章

  1. HashMap 底层源码细致分析
  2. 如何使用pgrep匹配
  3. QT开发实践之简单的图像视频处理软件
  4. 百岁山的故事背后--笛卡尔
  5. Cocos 荣耀讲师线下聚(mian)会(ji)!
  6. deepin系统挂载新硬盘|超3T硬盘挂载|纯干货
  7. Python turtle 绘制正方体
  8. win7下安装SDK
  9. Call to a member function num_rows() on boolean in ...
  10. 网页大作业——个人网页