【问题标题】:stuck with minimax algorithm - what next? Haskell坚持极小极大算法——下一步是什么?哈斯克尔
【发布时间】:2020-02-16 05:03:00
【问题描述】:

我正在为 2 人棋盘游戏编写基本的 MiniMax 算法。到目前为止,我有一个评估板并返回分数的函数。我有一个函数可以返回所有可能的移动(以及这些移动的移动)等的玫瑰树......到给定的深度。我可以找到那棵树的叶子并根据我的启发式给它们一个值,我的问题是在那之后我该怎么办?

我是否以某种方式编辑叶子的父节点并根据子节点的值为父节点分配一个新值,然后继续直到到达根节点?

我是否打算从叶子向上创建一棵新树,选择最小/最大值直到我到达根节点?如果是这样,新树如何记住到达叶子所需的所有移动?

我只想使用来自标准库的导入(我不想下载包)。任何建议都会很棒,这几天一直在努力。 谢谢


我试图从我的代码中挑选出一些部分来举例说明,但只是有很多函数纠缠在一起。如果它有帮助的话,这里是主要功能的类型签名以及它们的作用的解释:

这个函数接受一个Int(代表树的Depth),一个Game(棋盘的当前状态),立即可能移动的列表,并返回一个带有每个可能移动的玫瑰树(并移动到那些移动)和与该移动相关的分数。如果玩家是黑暗的,它的分数是正的,如果玩家是黑暗的,它的分数是负的 - 玫瑰树中的每个深度都是下一个玩家移动。

roseTreeAtDepthN :: Int-> Game -> [Position] -> [Rose (Position,score)]

例如:treeAtDepthN 2 initialGame [(2,3),(3,2),(4,5),(5,4)] 返回:

[Rose ((2,3),4) [Rose ((2,2),-3) [],Rose ((2,4),-3) [],Rose ((4,2),-3) []],
 Rose ((3,2),4) [Rose ((2,2),-3) [],Rose ((2,4),-3) [],Rose ((4,2),-3) []],
 Rose ((4,5),4) [Rose ((3,5),-3) [],Rose ((5,3),-3) [],Rose ((5,5),-3) []],
 Rose ((5,4),4) [Rose ((3,5),-3) [],Rose ((5,3),-3) [],Rose ((5,5),-3) []]]

我有另一个函数可以让我得到一棵树的叶子。我使用在treeAtDepthN 中为每一步评估游戏状态的函数,但我意识到这可能不是必需的,只应在树的叶子上使用。我不确定这是否有帮助。


稍后编辑:

不确定我的极小极大算法接下来要做什么。我有一个将所有可能的移动打印到一定深度的函数,我有一个评估每个移动的启发式方法,我只是不确定如何将它变成一个返回最佳移动的函数。我只想使用 Haskell 库中给出的函数(不想下载任何包等)。

data Rose a = Rose a [Rose a]
    deriving Show

我想如果我画一张图来解释我所拥有的功能,我可能会更容易理解。我有两个我能想到的解决方案,图中概述了,我不确定我应该采用哪种方法,如果有的话。 :

我想我想要一个将图片顶部的 [Rose a] 转换为图片底部的玫瑰 a 的功能。

谢谢。

【问题讨论】:

  • 如果没有看到任何代码,很难提供很多指导。但从逻辑上讲,如果你已经完成了你所描述的所有设置,那么你已经完成了所有艰苦的工作——剩下的就是编写一个递归函数,给定一棵树,根据你的启发式计算最佳移动。跨度>
  • 请与示例数据和预期输出一起分享您的尝试。
  • @RobinZigmond 我编辑了帖子以包含一张照片。我希望它更容易理解。基本上需要一个功能,将照片顶部的 [Rose a ] 变成底部的 Rose a。

标签: haskell tree artificial-intelligence minimax


【解决方案1】:

嗯,您实际上并不需要使用更新的分数来构建树。您只需要计算最佳移动(最大化最小、最坏情况得分的移动)。

所以,从一些预备开始:

import Data.List
import Data.Ord

type Position = (Int,Int)
type Score = Int
data Rose a = Rose a [Rose a]

我们可以编写一个函数,它采用移动树列表并选择导致最小分数中的​​最大值的移动(又名Position):

maximin :: [Rose (Position, Score)] -> (Position, Score)
maximin = maximumBy (comparing snd) . map minscore

帮助器minscore 计算移动树的最低分数,假设最佳反击。

minscore :: Rose (Position, Score) -> (Position, Score)

如果我们在一片叶子上,我们对分数的最佳估计是对当前棋盘的直接启发式评估,所以我们只返回那个位置和分数:

minscore (Rose x []) = x

否则,我们使用maximin 的反面计算最佳反击得分,即minimax

minscore (Rose (pos,_) moves)
  = let (_,score) = minimax moves in (pos,score)

请注意,minscore 总是从树的根返回下一步移动 (pos),但分数将从根(对于叶子)或通过进一步的递归计算(对于节点)获取。

maximin及其镜像minimax的完整定义是:

maximin :: [Rose (Position, Score)] -> (Position, Score)
maximin = maximumBy (comparing snd) . map minscore
  where minscore (Rose x []) = x
        minscore (Rose (pos,_) moves)
          = let (_,score) = minimax moves in (pos,score)

minimax :: [Rose (Position, Score)] -> (Position, Score)
minimax = minimumBy (comparing snd) . map maxscore
  where maxscore (Rose x []) = x
        maxscore (Rose (pos,_) moves)
          = let (_,score) = maximin moves in (pos,score)

应用于您的图片示例:

example = maximin
  [Rose ((1,1),2) [Rose ((1,2),3) [], Rose ((1,3),-2) [], Rose ((1,4),4) []],
   Rose ((2,2),3) [Rose ((2,3),-7) [], Rose ((2,4),-1) []],
   Rose ((3,3),1) [Rose ((3,4),2) []]]

你得到:

> example
((3,3),2)

看起来像你想要的。

关于性能的几点说明:

  • minimax 算法实际上并不使用内部节点的启发式分数,只在叶子处使用,因此您最好处理 [Rose Position] 并仅在需要的地方计算启发式分数(当您检测到叶子时在minscoremaxscore)。
  • Alpha-beta pruning 是众所周知的极大极小算法优化,应该在任何严肃的实现中使用。

不管怎样,完整的代码是:

import Data.List
import Data.Ord

type Position = (Int,Int)
type Score = Int
data Rose a = Rose a [Rose a]

maximin :: [Rose (Position, Score)] -> (Position, Score)
maximin = maximumBy (comparing snd) . map minscore
  where minscore (Rose x []) = x
        minscore (Rose (pos,_) moves)
          = let (_,score) = minimax moves in (pos,score)

minimax :: [Rose (Position, Score)] -> (Position, Score)
minimax = minimumBy (comparing snd) . map maxscore
  where maxscore (Rose x []) = x
        maxscore (Rose (pos,_) moves)
          = let (_,score) = maximin moves in (pos,score)

example = maximin
  [Rose ((1,1),2) [Rose ((1,2),3) [], Rose ((1,3),-2) [], Rose ((1,4),4) []],
   Rose ((2,2),3) [Rose ((2,3),-7) [], Rose ((2,4),-1) []],
   Rose ((3,3),1) [Rose ((3,4),2) []]]

【讨论】:

  • 谢谢。我最终弄明白了,但这个实现更清洁、更高效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-24
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多