Tic Tac Toe:了解Minimax算法

第一次发布于2013年12月13日,最后更新于1年前
追求软件兴趣。

注意!这篇文章也被翻译成日文和葡萄牙文。我非常感谢与我联系的读者,并翻译了这篇文章。

我最近建立了一个无与伦比的tic tac脚趾游戏。这是一个有趣和非常谦卑的项目,教我一吨。如果你想完全接受教育,请在这里拍摄tic tac toe游戏。

为了使游戏无与伦比,有必要创建一个算法,可以计算可用于计算机播放器的所有可能的动作,并使用一些度量来确定最佳的移动。经过广泛的研究,很明显Minimax算法是正确的工作。

花了一点时间真正从根本上了解算法并在我的游戏中实现。我发现了许多代码示例和解释,但没有一个真正像我一样走过一个简单的过程。我希望这篇文章能帮助你们欣赏这种算法的优雅。

描述Tic Tac Toe的完美游戏

首先,我们先来定义一个完美的tic tac脚趾游戏的意义:

如果我玩得很好,每次玩,我都会赢得比赛,否则我会画这个游戏。此外,如果我对另一个完美的球员,我会总是画游戏。

我们如何定量地描述这些情况?让我们分配一个分数到“终点游戏条件:”

  • 我赢了,饿了!我得到10分!
  • 我输了,狗屎 我输10分(因为其他玩家得10分)
  • 我画,无论如何。我得到零点,没有人得到任何积分。

所以现在我们有一个情况,我们可以确定任何游戏结束状态的可能得分。

看一个简单的例子

要应用这个,我们来看一个比赛结束的一个例子,我轮到哪里。我是X.我的目标明显是最大化我的最终比赛得分。

如果这个图像的顶部代表了我轮到的游戏状态,那么我有一些选择可以做,有三个地方可以玩,其中一个明显地导致我赢得了10分。如果我不这样做,O可以很容易地赢。而且我不希望O赢,所以我的目标是作为第一名球员,应该是选择最大的得分。

但是关于O呢?

我们对O有什么了解?那么我们应该假设O也在玩这个游戏,但是相对于我们来说,第一个玩家,O想要显然想要选择这个动作,这给我们带来了最差的分数,它想要选择一个最小化我们的动作终极得分。从O的角度来看待事情,从上面的其他两个游戏状态开始,我们不立即赢得:

选择是清楚的,O会选择任何得分为-10的动作。

描述Minimax

Minimax算法的关键是来自两个玩家之间的距离,其中“转弯”的玩家希望以最高分数来选取动作。反过来,每个可用移动的分数由相对的玩家决定哪个可用移动具有最小分数来确定。对手球员的分数再次由转牌球员试图最大限度地提高得分,从而一直下移到移动树到结束状态。

假设X是“转牌者”的算法描述如下:

  • 如果游戏结束,请从X的角度返回分数。
  • 否则得到一个新的游戏状态列表为每一个可能的举动
  • 创建一个分数列表
  • 对于这些状态中的每一个,将该状态的最小值结果添加到分数列表
  • 如果是X的转弯,则从得分列表中返回最大分数
  • 如果是转弯,则从得分列表中返回最小分数

你会注意到这个算法是递归的,它在玩家之间来回翻转,直到找到最后的分数。

让我们用完整的移动树来浏览算法的执行,并显示为什么在算法上,即时获胜的举动将被挑选:

  • X在状态1中转弯.X生成状态2,3和4,并在这些状态下调用最小值。
  • 由于游戏处于结束状态,状态2将+10的分数推至状态1的得分列表。
  • 状态3和状态4不处于结束状态,所以3生成状态5和6,并在其上调用最小值,而状态4生成状态7和8,并在其上调用最小值。
  • 状态5将10分的成绩推到了状态3的得分列表上,而同样的状态是将状态7推到了状态4的得分列表上。
  • 状态6和8生成唯一可用的移动,它们是终端状态,因此它们都将状态3和4的移动列表中的+10分数相加。
  • 因为在状态3和状态4都是O转,O将寻求最小分数,并且在-10和+10之间进行选择,状态3和4都将产生-10。
  • 最后,状态2,3和4的得分列表分别填入+10,-10和-10,而追求最大分数的状态1将选择得分+10,状态2的获胜移动。

这当然是很多的,这就是为什么我们有一台电脑执行这个算法。

Minimax的编码版本

希望现在你对粗略的算法如何决定最佳的移动方式有一个粗略的感觉。我们来看看我的算法实现来巩固理解:

这是游戏得分的功能:

# @player is the turn taking player
def score(game)if game.win?(@player)return 10elsif game.win?(@opponent)return -10elsereturn 0end
end

足够简单,如果当前玩家赢得游戏,则返回+10,如果其他玩家获胜,则返回0,平局为0。你会注意到玩家谁不重要。X或O是无关紧要的,只有谁转过来才是。

现在实际的最小值算法; 请注意,在此实现中,choice或者move简单地是板上的行/列地址,例如[0,2]是3x3板上的右上角。

def minimax(game)return score(game) if game.over?scores = [] # an array of scoresmoves = []  # an array of moves
# Populate the scores array, recursing as neededgame.get_available_moves.each do |move|possible_game = game.get_new_state(move)scores.push minimax(possible_game)moves.push moveend
# Do the min or the max calculationif game.active_turn == @player# This is the max calculationmax_score_index = scores.each_with_index.max[1]@choice = moves[max_score_index]return scores[max_score_index]else# This is the min calculationmin_score_index = scores.each_with_index.min[1]@choice = moves[min_score_index]return scores[min_score_index]end
end

当这个算法在PerfectPlayer类中运行时,最佳移动的最终选择存储在@choice变量中,然后用于返回当前玩家移动的新游戏状态。

完美但致命的玩家

实现上述算法可以让你达到一个点,你的tic tac脚趾游戏不能被击败。但是,在测试时发现的有趣的细微差别在于,完美的玩家必须始终是完美的。换句话说,在完美的玩家最终会失去或画出的情况下,下一步的决定是相当的宿命论。该算法基本上说:“嘿,我会失去反正,所以如果我在现在的下一个或者六个动作中输了,真的没关系。”

我发现这是通过一个明显的索引板,或一个“错误”在它的算法,并要求下一个最好的举动。我会期望完美的球员至少打架,阻止我的直接胜利。但是,它没有:

看看这里发生了什么,看看可能的移动树(注意,为了清楚起见,我已经删除了一些可能的状态):

  • 给予板状态1,两个玩家都玩得很好,而O是电脑玩家。O选择状态5中的移动,然后当X在状态9中获胜时立即失去。
  • 但是如果O阻挡了X在第三的胜利,X将明显地阻止O的潜在胜利,如状态7所示。
  • 这为X所示的X取得了一定的胜利,所以无论在状态7中选择哪个动作,X都将最终获胜。

作为这些情景的结果,以及我们正在遍历每个空白空间的事实,从左到右,从上到下,所有的移动是相等的,也就是导致O的输入,最后一个移动将被选择为在状态5中显示,因为它是状态1中可用移动的最后一个。移动的数组是:[左上角,右上角,中间左侧,中间中心]。

什么是gosh-darn,tic tac脚趾大师要做什么?

打好战斗深度

这种算法的关键改进是,无论董事会安排如何,完美的玩家都将完美地发挥其作用,就是考虑到“深度”或转弯,直到游戏结束为止。基本上,完美的玩家应该玩得很好,但是尽可能延长游戏。

为了达到这个目的,我们将从最终的比赛得分减去深度,即轮到次数或递归,得分越多,得分越高。从上面更新我们的代码,我们有一些如下所示:

def score(game, depth)if game.win?(@player)return 10 - depthelsif game.win?(@opponent)return depth - 10elsereturn 0end
end

def minimax(game, depth)return score(game) if game.over?depth += 1scores = [] # an array of scoresmoves = []  # an array of moves
# Populate the scores array, recursing as neededgame.get_available_moves.each do |move|possible_game = game.get_new_state(move)scores.push minimax(possible_game, depth)moves.push moveend
# Do the min or the max calculationif game.active_turn == @player# This is the max calculationmax_score_index = scores.each_with_index.max[1]@choice = moves[max_score_index]return scores[max_score_index]else# This is the min calculationmin_score_index = scores.each_with_index.min[1]@choice = moves[min_score_index]return scores[min_score_index]end
end

所以每当我们调用最小值时,深度会增加1,最终计算结束游戏状态时,分数会根据深度进行调整。我们来看看我们的移动树中的外观:

这次深度(左侧显示为黑色)导致每个结束状态的分数不同,并且由于最小值的0级部分将尝试最大化可用分数(因为O是转牌球员),所以-6得分将被选中,因为它大于其他状态,得分为-8。所以即使面对一定的死亡,我们的信任,完美的球员现在将选择阻止的举动,而不是承诺荣誉死亡。

结论是

我希望所有这些讨论有助于您进一步了解最小化算法,也许如何在一个tic tac脚趾游戏中占主导地位。如果您有其他问题或任何令人困惑的事情,请留下一些意见,我会尝试改进文章。我的tic tac脚趾游戏的所有源代码可以在github上找到。

如果您喜欢阅读本文或了解的内容,请考虑通过Facebook,Twitter或Google Plus进行分享。谢谢!

了解Minimax算法相关推荐

  1. minimax算法及α-β剪枝算法

    minimax算法通常用于二人博弈游戏中,如井字棋,chomp游戏等.我对这个算法的理解是这样的:(以人和电脑下棋为例) 电脑要确定哪一步下棋使得优势最大,假设棋盘大小为nxm,不 考虑其他因素,那么 ...

  2. 详解Minimax算法与α-β剪枝

    在局面确定的双人对弈里,常采用博弈树搜索.我方追求更大的赢面,而对方会设法降低我方的赢面.由于局面确定,因此可以对赢面进行评估.我方往较大赢面的方向走,同时考虑对方的走法.由于对方的走法不确定,就假设 ...

  3. 【人工智能导论】吃豆人游戏(上):对抗搜索与Minimax算法

    吃豆人实验(The Pac-Man Project)简介 The Pac-Man projects were developed for UC Berkeley's introductory arti ...

  4. 博弈树搜索技术(Minimax算法,ɑ-β 算法)

    博弈树搜索技术(Minimax算法,ɑ-β 算法) 一. 算法的理解 Minimax算法 概括:算法可以概括为--己方利益最大化,对方利益最小化". 即一方要在可选的选项中选择将其优势最大 ...

  5. 基于C++的不围棋NOGO代码-PKU计算概论A大作业-MCTS算法Minimax算法

    关于评论区提出的问题,我补充一下,这篇代码是pku同学<计算概论A2020>的大作业,代码是需要提交在botzone上的,文章中有些代码是与botzone的交互,具体交互过程与规则见维基百 ...

  6. c语言博弈算法,C ++中博弈论中的Minimax算法(Alpha-Beta修剪)

    描述 Aplha-Beta修剪是minimax算法中使用的一种优化技术.该算法的思想是切断游戏树的分支,由于已经存在更好的动作,因此无需进行评估. 该算法引入了两个新领域-Alpha-这是最大化玩家可 ...

  7. 带有 JavaScript 的井字游戏:带有 Minimax 算法的 AI 玩家

    Tic-Tac-Toe with JavaScript: AI Player with Minimax Algorithm | Ali Alaa - Front-end Web Developerht ...

  8. MiniMax算法实现井字棋

    使用MiniMax算法实现井字棋,下面是问题的记录 源代码地址:gitee仓库地址 python中列表的浅复制和深复制 在函数传递中,如果实参传递可变数据类型(list.set.dict)实际上传递的 ...

  9. python五子棋算法_python使用minimax算法实现五子棋

    这是一个命令行环境的五子棋程序.使用了minimax算法. 除了百度各个棋型的打分方式,所有代码皆为本人所撸.本程序结构与之前的井字棋.黑白棋一模一样. 有一点小问题,没时间弄了,就这样吧. 一.效果 ...

  10. java井字棋ai_简单的井字棋 AI DEMO | Minimax 算法

    在"类与对象"实训课上,有一道附加题让我们用 OOP 做一个的井字棋模拟程序,要求中电脑是随机落子的,这样显然不是很优雅.回忆起以前学的对抗搜索(这里叫 MaxMin 算法),我继 ...

最新文章

  1. 关于Java中的JDBC使用和数据库(SQL Server)连接之后的一些操作
  2. 搜索引擎惩罚的五种最大原因
  3. 命令执行——系统命令执行(三)
  4. P3357 最长k可重线段集问题(网络流/串联/拆点)
  5. Java可移动性不强_java地位无可撼动的原因
  6. Python list合并(列表合并),dict合并(字典合并)
  7. sqllite查询数据量_详解SQLite中的查询规划器
  8. 第6章 见缝插圆(《C和C++游戏趣味编程》配套教学视频)
  9. php pod模式,k8s pod的4种网络模式最佳实战(externalIPs )
  10. React Component Lifecycle(生命周期)
  11. QT_布局管理器 网格布局管理器 QGridLayout 超简单
  12. Python使用matplotlib绘制龟兔赛跑中兔子和乌龟的行走轨迹
  13. 一次完整的http请求过程是怎样的?
  14. ★RFC标准库_目录链接
  15. 如何查看计算机关机事件,深度技术win7系统如何查看电脑的开关机时间【图文】...
  16. 【SDOI2015】星际战争(网络流)
  17. win10任务栏图标空白透明问题解决
  18. html5 3d 签到墙,签到小程序/微信签到/扫码签到/3D签到墙
  19. long journey android,人类一败涂地感染模式mod
  20. 短信验证码(俗称接码平台)分享定义是什么

热门文章

  1. async function
  2. bom_clear.php,金蝶KIS专业版常用SQL语句
  3. 转载 DM9000的调试
  4. 坦白说查看教程 Python
  5. QQ互联开发者信息认证
  6. 将PDF文件进行文件的编辑需要利用什么软件
  7. Kafka集群搭建配置
  8. linux复制文件命令
  9. python可以用于工业机器人编程_工业机器人四种编程技术
  10. Nessus安装教程