最近想做一个象棋游戏,但是AI把我难住了。这是这几天的成果:

象棋程序通过使用“搜索”函数来寻找着法。搜索函数获得棋局信息,然后寻找对于程序一方来说最好的着法。

一,最小-最大搜索Minimax Search

首先:最小与最大是相对的,且只针对一方,AI中即为有利于AI 
象棋AI中的最小最大搜索:  简单来讲就是该AI走了,穷举这个过程中对于AI来说的最佳(最大)走法对于我来说最差(最小)的走法。
而这个走法就是我们所要找的AI的最佳走法。

这个过程就跟你与别人下象棋时猜测对方走法然后下棋一样,只不过,电脑可以多想几步,这里的步数就是下面的搜索深度

举个例子:假设搜索深度为4. 那么AI走一步(他认为最佳,记为步数1,搜索深度4)时,会先考虑如果他走这一步1,那我肯定会走相对于这一步来讲
最差的一步2(搜索深度3),然后ai再假设出根据步数2来讲的最佳步数3(搜索深度2),继续考虑我根据步数3走的最差步数4(搜索深度1)
接下,搜索深度为0,给出此时的局面评价函数
             

他们之间彼此递归的调用,所以说这种搜索思路是相对的

这里只是浅显的讲下最小最大搜索的原理,还不能实现具体的AI功能

下面是实现代码

int Max(int depth) {
 int best = -INFINITY;
 if (depth <= 0) {
  return Evaluate();
 }
 GenerateLegalMoves();       //产生所有合理走法
 while (MovesLeft()) { 
  MakeNextMove();             //走这一步时          
  val = Min(depth - 1);       //接受一个相对最小值
  UnmakeMove();
  if (val > best) {
   best = val;
  }
 }
 return best;                 //返回一个相对最大的评价(AI 认为的最佳着法)
}
 
int Min(int depth) {
 int best = INFINITY; // 注意这里不同于“最大”算法
 if (depth <= 0) {
  return Evaluate();
 }
 GenerateLegalMoves();
 while (MovesLeft()) {
  MakeNextMove();
  val = Max(depth - 1);   //接受一个相对最大值
  UnmakeMove();
  if (val < best) {  // 注意这里不同于“最大”算法
   best = val;
  }
 }
 return best;            //返回一个相对最小的评价 (对方,人认为的最差走法)
}
 
  上面的代码可以这样调用:
 
val = MinMax(5);
 
  这样可以返回当前局面的评价,它是向前看5步的结果。 相关解释看注释就好

上面这种算法代码长,而且只是利于一方来推测(即对一方来说最佳最差走法),下面将介绍一种优化过的算法

--------------------------------------------------------------------------华丽丽的分割线
二,负值最大函数  Negamax Search

int NegaMax(int depth) {
 int best = -INFINITY;
 if (depth <= 0) {
  return Evaluate();
 }
 GenerateLegalMoves();
 while (MovesLeft()) {
  MakeNextMove();
  val = -NegaMax(depth - 1); // 注意这里有个负号。
  UnmakeMove();
  if (val > best) {            //始终最优值
   best = val;
  }
 }
 return best;
}

从这个函数可以看出,这个函数求得始终是当前节点的最优值(即始终求对当前节点的最佳走法),只是当变换节点(即由AI变换到人时),对函数结果取负值,变成人的最佳着法对于AI的评价,这样就省去了求min函数的步骤,减少了代码量

———————————————————————————————————————华丽丽的分割线

三,Alpha-Beta搜索

最小最大运行时要检查整个博弈树,然后尽可能选择最好的线路,但因为分枝因子太大导致效率非常低,无法做到很深的搜索。
Alpha-Beta搜索好处在于裁剪了不必要的分枝因子

举个例子(口袋的例子):
比如你的死敌面前有很多口袋,他和你打赌赌输了,因此他必须从中给你一样东西,而挑选规则却非常奇怪:
  每个口袋里有几件物品,你能取其中的一件,你来挑这件物品所在的口袋,而他来挑这个口袋里的物品。你要赶紧挑出口袋并离开,因为你不愿意一直做在那里翻口袋而让你的死敌盯着你。
  假设你一次只能找一只口袋,在找口袋时一次只能从里面摸出一样东西。

分析:你很容易将最小最大原理运用到这个问题上——你挑出最好的口袋,你死敌从里面挑出最差的物品。所以你的目标是——
挑出在诸多最糟糕物品中最好的物品所在的口袋

假设口袋内物品请况
我们从第一个口袋开始,看每一件物品,并对口袋作出评价。比方说口袋里有一只花生黄油三明治和一辆新汽车的钥匙。你知道三明治更糟,因此如果你挑了这只口袋就会得到三明治。
事实上只要我们假设对手也会跟我们一样正确评价物品,那么口袋里的汽车钥匙就是无关紧要的了。
现在你开始翻第二个口袋,这次你采取的方案就和最小-最大方案不同了。你每次看一件物品,并跟你能得到的最好的那件物品(三明治)去比较。只要物品比三明治更好,那么你就按照最小-最大方案来办——
去找最糟的,或许最糟的要比三明治更好,那么你就可以挑这个口袋,它比装有三明治的那个口袋好。
  比方这个口袋里的第一件物品是一张20美元的钞票,它比三明治好。如果包里其他东西都没比这个更糟了,那么如果你选了这个口袋,它就是对手必须给你的物品,这个口袋就成了你的选择。
    这个口袋里的下一件物品是六合装的流行唱片。你认为它比三明治好,但比20美元差,那么这个口袋仍旧可以选择。再下一件物品是一条烂鱼,这回比三明治差了。于是你就说“不谢了”,把口袋放回去,不再考虑它了。
  无论口袋里还有什么东西,或许还有另一辆汽车的钥匙,也没有用了,因为你会得到那条烂鱼。或许还有比烂鱼更糟的东西(那么你看着办吧)。无论如何烂鱼已经够糟的了,而你知道挑那个有三明治的口袋肯定会更好。

物品情况如图所示


排序后如图所示

节点2中最小值200,节点3中150<200.而节点1下第一个子节点只有170,小于200,而第二个子节点比170还要小,所以就不用再拿他跟200比较,剪裁,节点4类似,第一个子节点50,后面的就都不用再看了。这里只有alpha剪枝。

  对于一个MIN节点(第二层),若能估计出其倒推值的上确界Beta(170和50),并且这个Beta值不大于MIN的父节点(MAX节点)的估计倒推值的下确界Alpha(200),即Alpha≥Beta,则就不必再扩展该MIN节点的其余子节点(画x的子节点)了,因为这些节点的估值对MIN父节点的倒推值已无任何影响了,这一过程称为Alpha剪枝。

当然还有beta剪枝:

对于一个MAX节点,若能估计出其倒推值的下确界Alpha,并且这个Alpha值不小于MAX的父节点(MIN节点)的估计倒推值的上确界Beta,即Alpha≥Beta,则就不必再扩展该MAX节点的其余子节点了,因为这些节点的估值对MAX父节点的倒推值已无任何影响了。这一过程称为Beta剪枝。

一个MAX节点的Alpha值等于其后继节点当前最大的最终倒推值,一个MIN节点的Beta值等于其后继节点当前最小的最终倒推值

 

算法
搜索中传递两个值,第一个值是Alpha,即搜索到的最好值,体现在if (val > alpha) {alpha = val;}
第二个值是beta,即对于对手来说最坏的值,如果某个着法的结果大于或等于Beta,那么整个结点就作废了

体现在:if (val >= beta) {return beta;}
   
  

代码:
int AlphaBeta(int depth,int alpha,int beta) {
 if (depth == 0) {
  return Evaluate();
 }
 GenerateLegalMoves();
 while (MovesLeft()) {
  MakeNextMove();
  val = -AlphaBeta(depth - 1,-beta, -alpha);      //Alpha和Beta是不断互换的。当函数递归时,Alpha和Beta不但取负                                                //   数而且位置交换了
  UnmakeMove();
  if (val >= beta) {
   return beta;
  }
  if (val > alpha) {
   alpha = val;
  }
 }
 return alpha;
}
把醒目的部分去掉,剩下的就是最小-最大函数。
这个函数需要传递的参数有:需要搜索的深度,负无穷大即Alpha,以及正无穷大即Beta:

可能的弱点:

这个算法严重依赖于着法的寻找顺序。如果你总是先去搜索最坏的着法,那么Beta截断就不会发生,因此该算法就如同最小-最大一样,效率非常低。该算法最终会找遍整个博弈树,就像最小-最大算法一样。 

所以,生成全部着法后,排序很重要~ ~ ~

 

结语:

算法原理方面就到此为止了,比较浅显,大神勿喷~

象棋AI算法(一)的更多相关文章

  1. 象棋AI算法(二)

    原文大神是用html5+js写的关于象棋AI的博客,里面重点讲了棋子的着法,自己设计的评估函数和简单的Minmax理论,没有具体的讲搜索算法,本文是对原文的学习和分析补充 一,棋子的着法com.byl ...

  2. [转]象棋AI算法(二)

    本文转自:http://blog.csdn.net/u012723995/article/details/47143569 参考文献:http://bbs.blueidea.com/thread-30 ...

  3. [转]象棋AI算法(一)

    本文转自:http://blog.csdn.net/u012723995/article/details/47133693 参考文献:http://www.xqbase.com/computer/se ...

  4. 【中国象棋人机对战】引入了AI算法,学习低代码和高代码如何混编并互相调用

    以低代码和高代码(原生JS代码)混编的方式引入了AI算法,学习如何使用表达式调用原生代码的.整个过程在众触低代码应用平台进行,适合高阶学员. AI智能级别演示 AI算法分三个等级,体现出来的智能水平不 ...

  5. 浅析初等贪吃蛇AI算法

    作为小学期程序设计训练大作业的一部分,也是自己之前思考过的一个问题,终于利用小学期完成了贪吃蛇AI的一次尝试,下作一总结. 背景介绍: 首先,我针对贪吃蛇AI这一关键词在百度和google上尽心了检索 ...

  6. H5版俄罗斯方块(3)---游戏的AI算法

    前言: 算是"long long ago"的事了, 某著名互联网公司在我校举行了一次"lengend code"的比赛, 其中有一题就是"智能俄罗斯方 ...

  7. AI佳作解读系列(二)——目标检测AI算法集杂谈:R-CNN,faster R-CNN,yolo,SSD,yoloV2,yoloV3

    1 引言 深度学习目前已经应用到了各个领域,应用场景大体分为三类:物体识别,目标检测,自然语言处理.本文着重与分析目标检测领域的深度学习方法,对其中的经典模型框架进行深入分析. 目标检测可以理解为是物 ...

  8. 聊聊找AI算法岗工作

    https://blog.csdn.net/weixin_42137700/article/details/81628028 首先,本文不是为了增加大家的焦虑感,而是站在一名学生的角度聊聊找AI算法岗 ...

  9. 游戏人工智能 读书笔记 (四) AI算法简介——Ad-Hoc 行为编程

    本文内容包含以下章节: Chapter 2 AI Methods Chapter 2.1 General Notes 本书英文版: Artificial Intelligence and Games ...

随机推荐

  1. 一名十年Java程序员回忆阿里面试经历——揭开阿里面试的“遮羞布”

    阿里面试经历 去阿里面试可以说非常非常的偶然和戏剧性,因为本人根本没投简历,以至于阿里hr给我电话的时候我一度认为是诈骗电话.因为深圳这家公司不错我还想在这里干个两年左右再考虑考虑. 这个时候的本人已 ...

  2. proc介绍及问题分析

    文件系统 基本介绍 proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文件系统的方式为访问系统内核数据的操作提供接口.用户和应用程序可以通过proc得到系统的信息,并可以改变内 ...

  3. Loj 504 ZQC的手办

    Loj 504 ZQC的手办 用线段树维护,每个节点存储区间内最小值 \(val\) 以及最小值出现的一个位置 \(pos\) . 对操作 \(1\) ,只需打标记即可,因为我们不维护其他的信息(如区 ...

  4. 关于Mybatis将查询结果中添加常量列并返回

    引言 在使用mybatis的时候,查询一个集合返回给前台页面,在有的时候,我们会添加一个常量字段到对象或者集合中,来标识这个对象属于的类型等等情况,当前台进行再次请求的时候携带此变量进行请求. 但是: ...

  5. iOS获取图片格式

    我们系统使用的一般文件格式有png.jpg.jpeg.GIF.TIFF 等格式: 图片是我们开发过程中最常见的东西,一般每个公司都会有自己的文件服务器,客户端人员都会从文件服务器中获取相关的图片信息: ...

  6. Jitsi 开源视频会议远程桌面共享&&文档共享工具

    1. 特点 主要功能特点: 支持网络视频会议,使用SFU模式实现视频路由器功能. 支持SIP帐号注册电话呼叫. 支持安卓苹果终端. 支持文档共享功能,即时消息功能. 支持中文界面. 支持会议邀请,密码 ...

  7. Android中关于JNI 的学习(五)在C文件里使用LogCat

    Log是开发过程中.对于我们调试程序非常重要的一个工具,有非常多时候,我们正是通过Log才干够看清楚程序是不是真的依照我们想像中的模式在跑,从而定位到问题所在的地方.而在Android开发中,毫无疑问 ...

  8. JavaFX 之窗口拖动(三)

    一.问题场景 在上一篇中,我们将窗口的默认标题栏隐藏从而导致鼠标点击窗体无法进行拖动. 二.解决思路 给组件添加鼠标按下事件监听器和鼠标拖动事件监听器. 三.代码实现 /** * 程序入口 * @au ...

  9. RK3288 增加双屏异显 eDP+LVDS

    CPU:RK3288 系统:Android 5.1 下面是官方文档中的信息. 1.rk3288 支持的显示接口可以任意组合. 2.双屏异显时,一个显示接口当主屏,另一个当副屏:主副屏由板级 dts 文 ...

  10. 如何安装nginx第三方模块

    nginx文件非常小但是性能非常的高效,这方面完胜apache,nginx文件小的一个原因之一是nginx自带的功能相对较少,好在nginx允许第三方模块,第三方模块使得nginx越发的强大. 在安装 ...