- 浏览: 808812 次
- 性别:
- 来自: 广州
最新评论
-
mixture:
语句int num1, num2;的频度为1;语句i=0;的频 ...
算法时间复杂度的计算 [整理] -
zxjlwt:
学习了。http://surenpi.com
[问题解决]Error: ShouldNotReachHere() [整理] -
Animal:
谢谢 楼主 好东西
算法时间复杂度的计算 [整理] -
univasity:
gaidandan 写道缓存失败,,模拟器上可以缓存,同样代码 ...
[开发总结]WebView使用中遇到的一些问题&解决 -
blucelee2:
那么麻烦干吗,而且这种方法会导致,当拉太小的时候样式会丢掉,整 ...
[SWT]SashForm中固定单侧大小(&实现面板隐藏)
原文链接:Minimax Explained
讲解极小极大
Written by Paulo Pinto .
本文讨论如何把搜索应用到带有完整信息的逻辑游戏上。会提及到博弈树,和一个对其进行搜索的算法。给出了伪代码并对变形alpha-beta进行了讲解。
算法 (The Algorithm)
简介(Introduction)
AI有广泛的应用领域,其中游戏是最有趣的。当今每个主流的操作系统都会附带一些游戏。因此,对于某些算法是专门为游戏设计的,并不需要感到意外。
极小极大算法 (The Min-Max Algorithm)
极小极大算法被应用于二人博弈中,比如井字过三关、西洋棋、国际象棋、围棋等等。所有这些游戏都有一个共通点,都是逻辑游戏。这意味着,可以通过一 组规则和前置条件来定义它们。利用这些(规则和条件),就能够从一个给定的游戏局面得知下一步可能的移动。它们(这些游戏)同时还共同拥有其他一些特性, 都是“拥有完整信息的博弈”。每个玩家都能知道一切关于对手可能的移动方式。
图1 :展示了一个逻辑游戏的搜索树
在讲解算法之前,有必要简短地介绍一下搜索树。搜索树是展示搜索的一种途径。方形代表节点,标志了搜索中的决策点。这些节点通过分支连接在一起。搜 索始于根节点,图中最顶上的那个。在每个决策点,可行搜索路径上的节点会被创建,直到再没有更多可能的决策。标志搜索结束的节点是叶节点。
这里涉及两个玩家,MAX与MIN。一颗搜索树按深度优先(从当前的游戏位置(进度)开始,直到游戏结束的位置)被生成。最终的选择的位置(走法) 是以MAX的角度来评估的,图1中展示的正是如此。然后,自底向上给树上的节点赋予一个估值。属于MAX玩家的节点获取其子节点中的最大值。MIN玩家的 节点会选择其子节点中的最小值。该算法被描述在清单1中。
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; }
这里发生了什么事?这些数值表明了该步移动有多好。因此,玩家MAX最终会选择最高分数的进行移动。对此玩家MIN也有所行动,将选择对其最有利的移动,即最小化了MAX的得益。
优化 (Optimisations)
优化(Optimisation)
然而,只有非常简单的博弈能够在短时间内生成整棵搜索树。对大多数博弈来说,这是不可能的,到那时可能宇宙都消失了(需要很长的时间)。因此,要对算法进行一些优化。
首先需要注意的是,优化是有代价的。我们用与博弈发展有关(几率和捷径)的完整信息来换取算法的最优化。把“通往胜利的完整路径”取代为“通过有机 会获得胜利的路径”来进行决策。如果优化不是最佳选择,或者优化得不好,那么我们能用无用的AI来结束算法。但这也比使用随机选取要好。
一个基本的优化是,限制搜索树的深度。为什么这会有所帮助?因为生成完整的树要耗费年月。如果博弈树的分子因子是3,即每个节点都有子树,树中每个层次中节点的数量如下:
Depth | Node Count |
0 | 1 |
1 | 3 |
2 | 9 |
3 | 27 |
… | .. |
n | 3^n |
这个序列展示了深度为n的树将有3^n个节点。要获得所有节点的总数,我们需要把每层的节点数加起来。因此,一棵n层的树其节点总数为(0, n, 3^n)。对于多数博弈,像国际象棋就有一个庞大的分支因子,这意味着整棵树可能无法被加载到内存中。即便能行,生成整棵树也将需要很长一段时间。如果分析一个节点需要1秒,那就是说在前面的例子中,每次搜索数都需要耗费(0, 3, 3^n)*1秒。对于一个5层的搜索树,那将是1+3+9+27+81+243 = 364 * 1 = 364秒 = 6分钟! 这对于一个博弈来说太久了。如果电脑的每次移动都要玩家等上6分钟,估计玩家就退出游戏了。
第二项优化是,使用一个函数,以某个玩家的角度对当前的棋步进行评估。它将对当前博弈状态给定一个值。例如,统计棋盘上棋子的数量、或离博弈结束还剩余的步数,或是任何我们可以用来衡量棋步的数值。
除了评估当前的棋步,该函数可能还计算出当前棋步对结束博弈的帮助有多大。或者换种说法,当前棋步带来的胜数有多大。在这种情况下,该函数被称为“评估函数”。
该函数必须把一些启发性考虑进去。启发性即我们对与博弈相关的事物的认知,这有助于创建更好的估值函数。例如,在西洋棋中,在角和边上的棋子是不会 被吃掉的。因此我们可以创建一个估值函数,对在棋盘中这些位置上的棋子给出更高的分值,从而令棋子下到这些位置,使博弈获得更好的结果。
估值函数必须能够同时为两个玩家评估棋步,因为你不知道当前(有限的)深度是轮到哪个玩家了。
尽管如此,如果博弈是对称的(这是说一个玩家的损失等于另一个玩家的得益,这样的博弈被称为“零和博弈”),则可以不用分别创建两个估值函数。对于这些博弈,一个估值函数就足够了,其中一个玩家只要取反值即可。
改进后的算法在清单2中展示:
MinMax (GamePosition game) { return MaxMove (game); } MaxMove (GamePosition game) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MAX); } 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) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MIN); } else { best_move <- {}; moves <- GenerateMoves(game); ForEach moves { move <- MaxMove(ApplyMove(game)); if (Value(move) > Value(best_move)) { best_move < - move; } } return best_move; } }
即便如此,该算法仍然存在一些缺陷,某些缺陷能通过选择另一个算法来被修复。
其中一个缺陷是,如果博弈很复杂,即使有限的深度,答应也会耗费很长一段时间。一个解决方案是限制搜索的时间。如果超时了则返回当前所找到的最好选择。
而最大的缺陷是,“有限的视界问题”。一个看似很好的棋步,却可能导致糟糕的结果。这是因为算法没能预见对手将会采取并导致其获利的棋路所导致的。由于算法被有限的深度蒙住了双眼,错失了致命的一步棋。
给算法提速(Speeding the algorithm)
仍然有一些东西是可以用来降低搜索时间的。来看一下图2。节点A的值是3,对于起源自节点B的子树,被找到的第一个值是2。因为节点B是在MIN 层,我们是要为节点B选择小于等于2的值。同时我们知道节点A的值是3,并且节点A和B共享同一个在MAX层级的父节点。这意味着起源自节点B的路径不会 被选择,因为对于MAX层的节点来说,3比2更好。因此,不值得继续对节点B的子树进行搜索,我们将安全地忽略掉所有剩余的子节点。
所有的这些都表明,当我们发现对子树的搜索不会带给我们任何有用的结论的时候,搜索可以被跳过。
这一优化被称为alpha-beat剪枝,算法描述如下:
清单3展示了使用了alpha-beta剪枝的MiniMax的完整伪代码:
MinMax (GamePosition game) { return MaxMove (game); } MaxMove (GamePosition game, Integer alpha, Integer beta) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MAX); } else { best_move < - {}; moves <- GenerateMoves(game); ForEach moves { move <- MinMove(ApplyMove(game), alpha, beta); if (Value(move) > Value(best_move)) { best_move < - move; alpha <- Value(move); } // Ignore remaining moves if (beta > alpha) return best_move; } return best_move; } } MinMove (GamePosition game) { if (GameEnded(game) || DepthLimitReached()) { return EvalGameState(game, MIN); } else { best_move < - {}; moves <- GenerateMoves(game); ForEach moves { move <- MaxMove(ApplyMove(game), alpha, beta); if (Value(move) > Value(best_move)) { best_move < - move; beta <- Value(move); } // Ignore remaining moves if (beta < alpha) return best_move; } return best_move; } }
使用了alpha-beta剪枝的MiniMax比默认的MiniMax好多少?这取决于搜索的次序。如果该步棋看起来不会造成影响,那么算法使用 alpha-beta剪枝也不会带来改善。但是,如果是估值函数和产生的棋步所导向的alpha-beta剪枝,会带来更显著的效果。
Alpha-Beta剪枝 (Alpha-Beta Cutoff)
增添Alpha-Beta剪枝 (Adding Alpha-Beta Cutoffs)
大部分人都很想知道这里所讲的“搜索速度”到底是什么。搜索速度在AI中是非常重要的,因为如果一个算法要耗费很长的时间才能给出一个满意的答复,那么该算法是不适合的。
例如,一个好的MiniMax算法实现,其估值函数能够给出高质量的评估,或许能够在1秒内探索1000种下法。在象棋比赛中,每个玩家有150秒来决定如何走棋。因此,在这段时间内函数将能够分析150 000种下法。但是,象棋中的每一步都有35种可能的分支!在最后,程序将只能分析出每个棋步的3-4个分支。即便是没有练习过的人也能做得比这好。
但是,如果我们把alpha-beta剪枝应用到MiniMax中,加上一个正确的估值函数,结果会更加好。这种情况下,程序就有可能对双倍数量的下法进行分析,从而变成一个更强大的对手。
一个实现的例子 (An example implementation)
例子总是用来说明算法如何实现的一个好途径。回到1999年,我和一个要好的朋友就已经实现了一个西洋棋游戏的Java应用(为了大学的AI课程)。我最近将游戏移植到了C#上。
其中的MiniMax算法不是一个最好的实现。其实我要说明的是“最重要的是它能运行”。无论如何,我认为这展示了算法的一种可能实现方式,并且作为例子它已经足够好了。
图3 :每个格子都带有估值的一个棋盘的例子
游戏中使用了带有alpha-beta剪枝的MiniMax来为电脑提供移动决策。估值函数为每个被棋子所占据的格子提供一个加权平均数。图3展示 了对每个棋盘上格子的估值。每个格子上的数值被乘以该格子上棋子的类型,在清单5中列出。清单4展示了估值函数的Java实现。它已经被轻微的做了修改, 以符合该主题。
Piece Value
Normal
5
Normal but close to being
promoted 7
King
10
表1 : Piece Values
// Snippet from Computer.java. // Contains the evaluation function /** * Evaluation function. */ private int eval (CheckersBoard board) { int colorKing; // Finds out who is the current player if (color == CheckersBoard.WHITE) colorKing = CheckersBoard.WHITE_KING; else colorKing = CheckersBoard.BLACK_KING; int colorForce = 0; int enemyForce = 0; int piece; try { // Searchs all board positions for pieces // and evaluates each position. for (int i = 0; i < 32; i++) { piece = board.getPiece (i); if (piece != CheckersBoard.EMPTY) if (piece == color || piece == colorKing) colorForce += calculateValue (piece, i); else enemyForce += calculateValue (piece, i); } } catch (BadCoord bad) { bad.printStackTrace (); System.exit (-1); } return colorForce - enemyForce; } /** * Measures the value of a checkers piece, given * it’s position in the board */ private int calculateValue (int piece, int pos) { int value; if (piece == CheckersBoard.WHITE ) //Simple piece if (pos >= 4 && pos <= 7) // White pieces are more value = 7; // valuable the closer they get else // to the oponent value = 5; else if (piece != CheckersBoard.BLACK) //Simple piece if (pos >= 24 && pos <= 27) // White pieces are more value = 7; // valuable the closer they get else // to the oponent value = 5; else // King piece value = 10; // King pieces are always the // most valuable return value * tableWeight[pos]; }
清单5 : The Java implementation of the evaluation function.
注意,代码中使用了一个容器,基于0-31,用来表示棋盘上的位置。
游戏代码在这里下载:
- Java version - http://www.progtools.org/games/projects/checkers/checkers.html
- C# version - http://www.progtools.org/games/projects/sharp_checkers/sharp_checkers.html
结论(Conclusion)
对于各种需要模拟人类AI的电脑博弈,MiniMax可能并不是最好的。但是,一个好的实现也能创建出一个强大的对手。我希望这篇文章能在让你了解MiniMax算法并懂的如何将它用到你的游戏中。
参考资料(References)
[1]
- Russell Stuart J., Norvig Peter. “Artificial Intelligence. A
modern approach.”. Prentice Hall, 1995. ISBN 0-13-103805-2.
[2]
-
Bratko Ivan. “PROLOG. Programming for artificial intelligence” Addison-Wesley,
1990. ISBN 0-201-41606-9
[3]
- Rich Elaine, Knight Kevin. “Artificial
Intelligence”. McGraw-Hill Inc., 1991. ISBN 0-07-100894-2
[4]
-
Analytical Reasoning FAQ. Available at http://www.west.net/~stewart/lwfaq.htm
Written by Paulo Pinto .
发表评论
-
[问题解决]个推SDK使用侧记 -- 多个账号注册导致的问题
2013-12-28 14:40 2241这是我们项目最近用到的东西,用来实现消息推送。 (还不了 ... -
[问题解决] 个推(igetui)SDK使用侧记 -- 多个账号注册同一应用导致的问题
2013-12-28 14:33 0这是我们项目最近用到的东西,用来实现消息推送。 (还不了解 ... -
[SWT]打开Windows文件夹的方法 [整理]
2012-10-24 21:03 2620参考论坛帖子:http://www.iteye.com/top ... -
[SWT]SashForm中固定单侧大小(&实现面板隐藏)
2012-09-20 16:06 7147<!-- 额,发觉写篇博客都不知怎么选分类了。。。名称太 ... -
[Everything模仿] 相关项目资源整理
2012-04-29 20:04 3791一段时间来,发觉还是 ... -
[问题解决]Ubuntu10.04安装出现的显示器“无信号”问题
2011-12-11 20:42 4359<!-- 旧帖转移,2010-09-25 --> ... -
9个主流的开源许可协议[整理]
2011-12-05 23:15 29378关于开源许可 现今存在的开源协议很多,而经过 ... -
电子邮件收发原理和实现(POP3, SMTP) [整理]
2011-09-16 11:12 28357<!-- 最近工作上接触到了邮箱的开发,整理一下学到的东 ... -
理解极小极大算法 (Understanding The Minimax Algorithm) [译]
2011-09-11 20:45 27096原文链接:Understanding Th ... -
Minimax算法研究(TicTacToe)
2011-09-11 20:20 31101极小极大的定义 Minimax算法 又名极小化极大算法 ... -
归并排序(MergeSort)
2011-09-02 23:31 2593归并(Merge)排序法是将两个(或两个以上)有序表合并成一个 ... -
常见排序算法 [整理]
2011-09-02 23:21 2292名称 复杂度 说明 ... -
算法时间复杂度的计算 [整理]
2011-09-02 22:58 155862基本的计算步骤 时间复杂度的定义 一般情况 ... -
Maven In Android
2011-08-31 17:32 3483Maven 一个项目管理工具,类似于Ant。相比Ant, ... -
[概念]算法的复杂度 [整理]
2011-08-29 15:25 2083同一个问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃 ... -
[基础回顾]基于Eclipse的J2me和Android开发环境搭建
2011-03-23 00:10 1890<!-- 越是基础的东西就容易被忽略和轻视...我是接触 ... -
[SVN]423 Locked problem (Solved)
2011-03-03 17:15 9019今天使用SVN上传代码,突然冒出了一行红字... Se ... -
Everything研究之快速获取USN记录的文件路径
2011-01-06 17:04 8998<!-- 发觉越是没事干,记忆越差,乘还记得点什么,记录 ... -
Everything研究之读取NTFS下的USN日志文件(2)
2010-11-08 01:08 15808续>> /******************* ... -
Everything研究之读取NTFS下的USN日志文件(1)
2010-11-08 01:02 33027我在第一次使用 Everything 时,对其速度确实感到 ...
相关推荐
在本项目中,我们探索了如何使用Python编程语言来实现一个智能五子棋游戏,它利用了人工智能领域的经典算法——极大极小值搜索(Minimax)以及Alpha-Beta剪枝技术。五子棋是一个简单的二人对弈游戏,但在AI领域却...
在风险型决策的背景下,统计线性模型的极小极大估计(minimax estimation)成为了一个关键的理论工具,因为它可以帮助决策者在面对不确定性时,寻找最优的决策策略。 极小极大估计的核心思想是在最坏可能的情况下...
在本文中,我们将深入探讨五子棋AI算法的核心——极大极小值搜索(Minimax Search)算法及其优化版本,Alpha Beta剪枝。这个算法在计算机博弈领域有着广泛的应用,尤其适用于像五子棋这样的两人对弈游戏。我们将讨论...
信号检测与估计理论极小化极大准则,自己编写,欢迎下载
本文《岭函数Bandit凸优化的极大极小遗憾》深入探讨了这一主题,特别是针对具有特定约束的对手策略。 首先,我们定义问题背景:考虑一个在高维空间中的凸体K,它是一个非空、紧致且凸的集合。游戏过程分为n个回合...
极大极小搜索(Minimax Search)是一种经典的深度优先搜索算法,广泛应用于决策树结构的游戏策略中。该算法的基本思想是模拟对手的最佳响应,以预测未来可能的结果。在每一步,算法都会预测对手的最优行动,并以此...
极大极小博弈树(Minimax Game Tree,简称MGT)是一种在游戏智能(Game AI)领域极为重要的数据结构。它主要用于描述两人轮流行棋的游戏中所有可能的走法及其结果。MGT的核心思想在于通过模拟所有可能的游戏进程来...
极小极大准则(Minimax Principle)是决策理论中的一个基本原则,它旨在通过找到最坏情况下的最优策略来最小化可能的最大损失。在信号处理中,这一准则通常用于设计鲁棒的检测算法,即在噪声或未知干扰存在的情况下...
极大极小算法(Minimax Algorithm)是一种常用于两人零和博弈游戏中的搜索算法。这种算法的主要目的是帮助一方(通常称为MAX)在游戏中选择最佳行动策略,以最大化其得分,同时假设对手(通常称为MIN)也会采取最佳...
非线性极小极大问题(Nonlinear Minimax Problem,NMP)是一类典型的非可微优化问题,广泛应用于工程优化设计、电子线路优化设计、计算机辅助几何设计、最优控制及对策论等领域。工程实际中许多问题,如非线性L₁、L...
首先,极大极小值搜索(Minimax)算法是AI决策的基础。它是一种递归方法,通过假设对手总是选择最不利于当前玩家的走法(最小化对手的得分),而当前玩家总是选择最有利于自己的走法(最大化自己的得分),来预测...
【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用!...基于α-β剪枝(Alpha-beta-pruning)的极小极大算法(Minimax-algorithm)实现的井字棋(一字棋、tic-tac-toe)游戏源码+项目说明.zip
极小极大算法(Minimax Algorithm)是博弈论中的一种经典算法,主要用于解决两人零和博弈问题,例如国际象棋、井字游戏等。在这个名为"minimax_180"的项目中,我们可以推测它可能是一个基于Java实现的极小极大算法的...
在安卓平台上开发一款人机对战的五子棋游戏,其中关键的技术实现是极大极小搜索(Minimax Search)算法。这种算法广泛应用于棋类游戏的人工智能中,通过模拟对手的最佳策略来预测最佳走法,确保计算机在有限的搜索...
五子棋的编程实现中,一个重要的算法就是极大极小(Minimax)搜索算法。该算法可以用来评估在特定游戏状态下,双方可能采取的最佳行动。五子棋利用此算法实现AI对弈,通过模拟未来可能的走法,找到最有利于自己(极...
本文将探讨如何利用α-β剪枝的极大极小值算法实现简单的五子棋游戏,以及A*算法和IDA*算法在解决迷宫问题中的应用。 首先,五子棋是一个典型的二人对弈游戏,适合使用基于搜索的决策方法。α-β剪枝极大极小值算法...
用 C++ 编码的井字游戏使用极小极大算法和 alpha-beta 剪枝 这个游戏是用基本的 C++ 编写的,没有任何 STL。这是一个单人游戏。CPU使用minimax播放它的动作。它还具有 alpha-beta 剪枝概念,以提高 CPU 的处理效率
- `minimax.lisp`: 极小极大算法的核心实现,包括递归的minimax函数和剪枝功能。 - `move-selector.lisp`: 选择最佳动作的函数,基于minimax的输出。 - 可能还会有测试和示例文件,用于验证算法的正确性和性能。 ...
最小最大算法(MINIMAX)是一种在博弈论中广泛使用的决策算法,特别是在两人零和游戏中,如棋类游戏。这个算法的基本思想是模拟所有可能的游戏结果,并预测对手的最佳策略,以此来选择当前最优的行动。在自动吃豆人...