我正在为一个2人棋盘游戏编写一个基本的MiniMax算法。到目前为止,我有一个函数,它评估一个板并返回一个分数。我有一个函数,它将所有可能的移动(以及这些移动的移动)等的玫瑰树返回到给定的深度。我可以找到那棵树的叶子,并根据我的启发给它们一个值,我的问题是,在那之后我该怎么办?
我是否以某种方式编辑叶子的父节点,并根据子节点的值给父节点分配一个新值,然后继续下去,直到到达根节点?
我是否要从叶子向上创建一棵新树,选择最小值/最大值直到到达根节点?如果是这样,新树如何记住到达叶子所需的所有动作?
我只想使用标准库的导入(我不想下载包)。任何建议都很好,已经挣扎了几天了。谢谢
我试图挑选代码的某些部分来举例,但有很多函数纠缠在一起。如果它有帮助,这里是主要函数的类型签名和它们的作用的解释:
此函数接受Int
(表示树的深度
>)、
(棋盘的当前状态)、立即可能的移动列表,并返回玫瑰树,其中包含每个可能的移动(以及移动到这些移动)以及与该移动相关的分数。如果玩家是黑暗的,则其得分为正,如果玩家是暗的,则得分为负-玫瑰树中的每个深度都是玩家的下一步。
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]转换为图片底部的Rose a。
谢谢
嗯,你实际上不需要建立一个更新分数的树。你只需要计算最好的移动(最大化最小的,最坏情况的分数)。
所以,从一些初步的开始:
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
帮助程序min斯克尔
计算移动树的最小分数,假设最佳反击。
minscore :: Rose (Position, Score) -> (Position, Score)
如果我们在一片叶子上,我们对分数的最佳估计是对当前板的直接启发式评估,所以我们只需返回该位置和分数:
minscore (Rose x []) = x
否则,我们使用最大值的反作用(即最小最大值
)从最佳反击中计算分数:
minscore (Rose (pos,_) moves)
= let (_,score) = minimax moves in (pos,score)
请注意,< code>minscore总是返回从树根开始的下一步棋(< code>pos),但是分数将从树根(对于树叶)或通过进一步的递归计算(对于节点)获得。
最大值
及其镜像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)
这看起来像你想要的。
关于性能的几点说明:
总之,完整的代码是:
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) []]]
给定一个
克鲁斯卡尔算法 克鲁斯卡尔算法(kruskal)跟普里姆算法一样,目的都是求无向图的最小生成树。普里姆算法核心在于一个顶点接一个顶点的找出最短路径,克鲁斯卡算法在于将每一条边进行升序排序,然后通过边进行筛选从而组成最小生成树。 实现步骤 核心思想在于按权值从小到大排序选择n-1条边,并保证选择边不会构成回路。用到核心的数据结构并查集来判断是否构成回路。 将所有的边按权值大小升序排列 创建一个数组s
很抱歉打扰你,但我无法找到一个有效的解决我的问题的方法。我想做一个MongoDB查询,让我得到与SQL查询相同的结果:
我一直想知道为什么STL优先级队列默认使用最大堆而不是最小堆。我想到的两个明显的用例是寻路(Dijkstra)和构建霍夫曼代码。这两种算法都需要首先拉取最小元素。由于排序(std::sort)默认使用升序,我想知道priority_queue背后的设计原因是什么,因为我非常喜欢默认的最小堆。
这个问题可能是封闭的,因为它听起来很模糊,但我真的问这个,因为我不知道或者我的数学背景不够。 我试图实现一个挑战,其中一部分挑战要求我计算矩阵的最小值和最大值。我对矩阵的实现及其操作没有任何问题,但是什么是矩阵的最小值和最大值?考虑到3x3矩阵是9个数中最小的数,最大的是最大的还是其他什么?
Haskell(使用编译器)比您预期的要快得多。如果使用得当,它可以接近低级语言。(Haskellers最喜欢做的一件事是尝试将C语言的5%以内(甚至超过它,但这意味着您使用的是一个低效的C程序,因为GHC将Haskell编译为C)。)我的问题是,为什么?