博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
棋类游戏走步计算AI
阅读量:2436 次
发布时间:2019-05-10

本文共 3974 字,大约阅读时间需要 13 分钟。

如果棋类游戏中一方有利,就是另一方不利,这时称为零和博弈。这种类型的博弈,可以使用minimax算法,下面简单介绍一下:

我们知道,如果不出差错,一般我们轮流下棋时,都是坚持这样的原则:如果是自己下,坚持走计算好的最好的棋步;到对手时,他也一定是这样,根据零和博弈原理也就是对手走对我们最坏的棋步。如果对盘面的评估值越大越对我们有利时,我们追求的就是最大化盘面评估值(max),对手追求的是让我们的盘面评估值最小化(min)。
                     (4)
     最大化     /  /
                  [2]  (4)
     最小化       / /
                   (4)   (5)
     最大化    //      //
                [3] [4] [2] [5]
说明:上面图中,"()"中的内容由"[]"内的内容按照最大或最小原则得当。
再看看我们走棋时过程实际也是要在一个这样的树中寻找一个最好的棋步。一般来说,一个棋局不可能完全遍历,可以设置一个最大搜索深度,在到达最大深度节点时给出评估值,然后利用最大最小原则来一步一步得到顶层评估值。下面是一个例子:
MinMax (GamePosition game)
{
  return MaxMove (game);
}
MaxMove (GamePosition game)
{
 if (GameEnded(game))
 {
     return EvalGameState(game);
 }
 else
 {
     best_move <- {};
     moves <- GenerateMoves(game);
     ForEach moves
  {
      move <- MinMove(ApplyMove(game));
      if (Value(move) > Value(best_move))
    {
          best_move <- move;
   }
     }
     return best_move;
 }
}
MinMove (GamePosition game)
{
   best_move <- {};
   moves <- GenerateMoves(game);
   ForEach moves
  {
   move <- MaxMove(ApplyMove(game));
   if (Value(move) > Value(best_move))
    {
          best_move <- move;
      }
 }
 return best_move;
}
同样,如果我们求最小的值加上负号,那么就能将最小原则统一到最大原则(变成求最大)。如下:
                     (-4)
     最大化     /  /
                  [2]  (4)
     最大化       / /
                   (-4)   (-5)
     最大化    //      //
                [3] [4] [2] [5]
这样一来,最小最大算法可以简化为负最大算法(negaMax)。下面是例子: 

Int NegaMax(局面 p, int depth)
{
  int bestvalue = -INF, value;
  if(Game over)
    return Evaluation(p);
  if(depth<=0) //叶子节点
    return Evaluation(p);
  for each(可能的走法 m)
  {
    Move(m); //局面p随之改变
    value = -NegaMax(p, depth-1);//搜索子节点
    UnMove(m); //恢复局面p
    bestvalue = Max(bestvalue,value);
  } //end for each
  return bestvalue;
} // end function
后来人们发现,上面的算法效率太低。1958年有人发明了alpha-beta剪枝算法,这样一来可以去除大量不必要的搜索,大大提高了效率。
其主要思想是:
(1)alpha剪枝:当我们知道对于某一层要选出最大值传给上层,当前层最大值为alpha,如果发现后面有小于这个alpha的值时就不需要再搜索那个节点和其子节点,因为它的评估值一定不会大于alpha。如下图:
                     (8)
     最大化     /  /(剪枝)
                  [8]  (5)
     最小化       / /
                   (4)   (5)
     最大化    //      //
                [3] [4] [2] [5]
说明:alpha=8,由发现其下一个兄弟节点第一个有值叶子值为3,可以不用搜索整个兄弟节点和子节点(剪枝)。
(2)类似有beta剪枝。
                     (8)
     最大化     /  /(剪枝)
                  [8]  (5)
     最小化       / /
                   (4)   (5)
     最大化    //      //
                [3] [4] [2] [5]
说明:alpha=8,由发现其下一个兄弟节点第一个有值叶子值为3,可以不用搜索整个兄弟节点和子节点(剪枝)。
(2)类似有beta剪枝。
如果利用负最大算法,可以得到如下算法:
long NegaAlphaBeta(局面 p, int depth, long alpha, long beta)
   int value;
   if(Game over)
    return Evaluation(p);
   if( depth <= 0 ) 
    return Evaluation(p);
  for(每一个合法的走法 m)
  { 
    Move(m); //局面p随之改变 
     value = - NegaAlphaBeta(p, depth-1, -beta, -alpha);  
    UnMove(m);
    if(value >= alpha)
    {
       //取最大值 
      alpha = value; 
      if(alpha >= beta)
        break;//剪枝  
      }
  }
  return alpha;
}
当然,还有许多方法来提高效率,如:
PVS
历史启发
杀手启发
SSS *
MTD(f)
等等,这里不详细论述。
大家可以去百度和Google上搜索,会发现不少好的资料。
参考资料:
南开大学软件学院《棋类游戏(人机博弈)的一般算法》课件
百度搜索: (有很多中文好东东)
游戏编程精粹1
                     (8)
     最大化     /  /(剪枝)
                  [8]  (5)
     最小化       / /
                   (4)   (5)
     最大化    //      //
                [3] [4] [2] [5]
说明:alpha=8,由发现其下一个兄弟节点第一个有值叶子值为3,可以不用搜索整个兄弟节点和子节点(剪枝)。
(2)类似有beta剪枝。
如果利用负最大算法,可以得到如下算法:
long NegaAlphaBeta(局面 p, int depth, long alpha, long beta)
   int value;
   if(Game over)
    return Evaluation(p);
   if( depth <= 0 ) 
    return Evaluation(p);
  for(每一个合法的走法 m)
  { 
    Move(m); //局面p随之改变 
     value = - NegaAlphaBeta(p, depth-1, -beta, -alpha);  
    UnMove(m);
    if(value >= alpha)
    {
       //取最大值 
      alpha = value; 
      if(alpha >= beta)
        break;//剪枝  
      }
  }
  return alpha;
}
当然,还有许多方法来提高效率,如:
PVS
历史启发
杀手启发
SSS *
MTD(f)
等等,这里不详细论述。
大家可以去百度和Google上搜索,会发现不少好的资料。
参考资料:
南开大学软件学院《棋类游戏(人机博弈)的一般算法》课件
百度搜索: (有很多中文好东东)
游戏编程精粹1
                     (8)
     最大化     /  /(剪枝)
                  [8]  (5)
     最小化       / /
                   (4)   (5)
     最大化    //      //
                [3] [4] [2] [5]
说明:alpha=8,由发现其下一个兄弟节点第一个有值叶子值为3,可以不用搜索整个兄弟节点和子节点(剪枝)。
(2)类似有beta剪枝。
如果利用负最大算法,可以得到如下算法:
long NegaAlphaBeta(局面 p, int depth, long alpha, long beta)
   int value;
   if(Game over)
    return Evaluation(p);
   if( depth <= 0 ) 
    return Evaluation(p);
  for(每一个合法的走法 m)
  { 
    Move(m); //局面p随之改变 
     value = - NegaAlphaBeta(p, depth-1, -beta, -alpha);  
    UnMove(m);
    if(value >= alpha)
    {
       //取最大值 
      alpha = value; 
      if(alpha >= beta)
        break;//剪枝  
      }
  }
  return alpha;
}
当然,还有许多方法来提高效率,如:
PVS
历史启发
杀手启发
SSS *
MTD(f)
等等,这里不详细论述。
大家可以去百度和Google上搜索,会发现不少好的资料。
参考资料:
南开大学软件学院《棋类游戏(人机博弈)的一般算法》课件
百度搜索: (有很多中文好东东)
游戏编程精粹1

转载地址:http://uewqb.baihongyu.com/

你可能感兴趣的文章
Php 3.x与4.x中关于对象编程的不兼容问题 (转)
查看>>
Cg FAQ (转)
查看>>
在access中增加农历支持模块. (转)
查看>>
增加一个判断内存变量存在的函数 (转)
查看>>
ASP文件上传神功 第二重(招势图加内功心法) (转)
查看>>
JSR227:J2EE数据绑定及数据访问标准 (转)
查看>>
Sun ONE Studio 4 Mobile Edition开发MIDlet入门 (转)
查看>>
Jbuilder8开发J2ee学习笔记(2) (转)
查看>>
Makefile编写小说(一) (转)
查看>>
NeHe的opengl教程delphi版(3)----着色 (转)
查看>>
ORACLE SQL性能优化系列 (二) (转)
查看>>
控件treeview的使用 (转)
查看>>
运用VC或Java对Office进行编程操作 (转)
查看>>
Linux Shell 裡一些很少用到卻很有用的指令 (转)
查看>>
第10章 模型管理视图 (转)
查看>>
第7章 活 动 视 图 (转)
查看>>
“管家婆”软件用于维修管理 (转)
查看>>
第13章 术 语 大 全 (8) (转)
查看>>
第13章 术 语 大 全 (9) (转)
查看>>
人月神话读书笔记(二) (转)
查看>>