这个问题更像是一个语义算法数据结构问题而不是F#语法问题。 我有一个Minimax算法。 minimax算法应从起始位置返回最佳下一步。要做到这一点,它下一步的微积分移动,然后下一个 - 下一步移动直到确定的深度或直到没有更多的移动。它构建了一个这样的树:
P
/ \
a b
/ \
c d
我有处理树的休闲数据结构:
type TreeOfPosition =
| LeafP of Position * int
| BranchP of Position * TreeOfPosition list
在上面的示例树中,P
和a
是分支,而b
,c
和d
是Leaf。下面的代码是我的minimax算法:
let evaluateTree ( tree : TreeOfPosition, player : int) =
let rec loop minOrmax node =
match node with
| LeafP(position, 0) ->
LeafP(position, evaluateLeaf(position))
| BranchP(position, children) ->
minimax.[minOrmax](List.map (loop (1 - minOrmax)) children)
loop player tree
此代码返回Leaf,例如c
。当我将递归调用更改为
| BranchP(position, children) ->
LeafP(position,
getStaticEvalFromNode(minimax.[minOrmax](
List.map (loop (1 - minOrmax)) children)))
这种修改使得好叶子的静态值上升。 我需要返回最好的第二级节点。 希望有人可以帮忙! 佩德罗杜索
编辑1
感谢所有答案的人,他们帮助了我很多。很抱歉没有指明这些东西。让我们进入部分:
1)我将我的LeafP与LeafP(position, 0)
匹配,因为当我创建树时,我将叶子设置为默认值0作为其静态值。当我上升静态值时,消除叶子并使用(最小或最大)静态值制作(分支前)叶子我认为这样我会阻止评估前分支叶子(因为它不会有0值)。
2)我最大的问题是让第二级(必须发挥的下一步)获得最佳位置。我这样解决了:
let evaluateTreeHOF ( tree, player : int) =
let rec loop minOrmax node =
match node with
| LeafP(position, 0) -> LeafP(position, evaluateLeaf(position))
| BranchP(position, children) -> LeafP(position,(children
|> List.map (loop (1 - minOrmax))
|> minimax.[minOrmax]
|> getStaticEvalFromNode))
match tree with
| BranchP(position, children) -> children |> List.map (loop (1 - player)) |> minimax.[player]
我没有传递整个树,而是仅传递起始节点的子节点,并过滤结果列表(具有静态值的前分支列表,其中当前级别的静态值最佳)再次。这样我就得到了我想要的节点。
我认为kvb的答案非常有趣,但对我来说有点复杂。我在其他方面进行了研究,但他们只是给了我静态的价值 - 我无法让它为我工作:(
非常感谢所有答案,所有这些都给了我很多启发。
以下是我的完整代码:(http://www.inf.ufrgs.br/~pmdusso/works/Functional_Implementation_Minimax_FSharp.htm)
Pedro Dusso
答案 0 :(得分:2)
我不太了解您的示例的某些方面(例如,为什么您只匹配其中包含0的叶子?),所以我将在下面做一些更改。首先,让我们稍微概括树类型,以便它可以在叶子和分支中存储任何类型的数据:
type Tree<'a,'b> =
| Leaf of 'a
| Branch of 'b * Tree<'a,'b> list
我们也使用专用的播放器类型,而不是使用0或1:
type Player = Black | White
最后,让我们概括一下最佳移动的评估,以便将叶评估函数作为参数传递:
let bestMove evalPos player tree =
// these replace your minimax function array
let agg1,agg2,aggBy =
match player with
| Black -> List.min, List.max, List.maxBy
| White -> List.max, List.min, List.minBy
// given a tree, this evaluates the score for that tree
let rec score agg1 agg2 = function
| Leaf(p) -> evalPos p
| Branch(_,l) -> agg1 (List.map (score agg2 agg1) l)
// now we use just need to pick the branch with the highest score
// (or lowest, depending on the player)
match tree with
| Leaf(_) -> failwith "Cannot make any moves from a Leaf!"
| Branch(_,l) -> aggBy (score agg1 agg2) l
答案 1 :(得分:1)
我认为你可以使用相互递归的函数:
let maxTree t =
match t with
| child -> xxx
| subtrees s ->
s |> Seq.map minTree |> Seq.max
and minTree t =
match t with
| child -> xxx
| subtrees s ->
s |> Seq.map maxTree |> Seq.min
答案 2 :(得分:0)
F#.NET Journal文章 Games programming: tic-tac-toe (2009年12月31日)中描述了此问题的解决方案,并使用以下模式:
type t = Leaf | Branch of t seq
let aux k = function
| Leaf -> []
| Branch s -> k s
let rec maxTree t = aux (Seq.map minTree >> Seq.max) t
and minTree t = aux (Seq.map maxTree >> Seq.min) t
另请参阅playable demo。