Algorithm 如何在这个F#minimax中返回最佳的第一级?

Algorithm 如何在这个F#minimax中返回最佳的第一级?,algorithm,data-structures,f#,minimax,Algorithm,Data Structures,F#,Minimax,这个问题更多的是一个语义算法数据结构问题,而不是一个F#语法问题。 我有一个极大极小算法。极小极大算法应该从起始位置返回最佳下一步。要做到这一点,它计算所有下一步动作,然后下一步动作直到确定深度或直到没有更多动作。它构建了一棵树,如下所示: P / \ a b / \ c d 我有空闲数据结构来处理树: type TreeOfPosition = | LeafP of Position * int | BranchP of Po

这个问题更多的是一个语义算法数据结构问题,而不是一个F#语法问题。 我有一个极大极小算法。极小极大算法应该从起始位置返回最佳下一步。要做到这一点,它计算所有下一步动作,然后下一步动作直到确定深度或直到没有更多动作。它构建了一棵树,如下所示:

     P  
   /  \  
 a      b  
/ \  
c d
我有空闲数据结构来处理树:

type TreeOfPosition =
    | LeafP   of Position * int
    | BranchP of Position * TreeOfPosition list
在上面的示例树中,
p
a
是分支,
b
c
d
是叶子。下面的代码是我的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
这段代码返回给我一片叶子,例如,
c
。当我将递归调用更改为

| BranchP(position, children)  -> 
    LeafP(position, 
          getStaticEvalFromNode(minimax.[minOrmax](
                       List.map (loop (1 - minOrmax)) children)))
这种修改使得一片好叶子的静态值上升。 我需要返回最好的二级节点。 希望有人能帮忙! 佩德罗杜索

编辑1

谢谢大家的回答,他们帮了我很多。对不起,我没有详细说明事情。让我们分几个部分:

1) 我正在匹配我的LeafP,比如
LeafP(位置,0)
,因为当我创建树时,我将leafs设置为默认值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的答案很有趣,但对我来说有点复杂。其他我未研究过的,但他们只是给了我静态值——我无法让他们为我工作:(

非常感谢所有的答案,它们都给了我很多启发

这是我的完整代码:()


Pedro Dusso

我认为您可以使用相互递归的函数:

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

我不太了解您的示例的某些方面(例如,为什么只匹配0的叶子?),因此我将在下面做一些更改。首先,让我们概括一下树类型,以便它可以在叶子和分支中存储任何类型的数据:

type Tree<'a,'b> = 
| Leaf of 'a 
| Branch of 'b * Tree<'a,'b> list
最后,让我们稍微概括一下最佳移动的计算,以便将叶计算函数作为参数传入:

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 

该问题的解决方案在《F#.NET杂志》的文章(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

另请参见。

您能再详细说明一下您的问题吗?我不明白您代码中的子树和子树是什么。叶和分支是什么?我这样问是因为子树是来自超级节点的子树…我不明白您的意思。我们只能阅读订阅F#.NET杂志的这篇文章:(Jon,我测试了你的解决方案。它是有效的,但这样它会返回叶子节点的静态值,我正在搜索整个节点来播放它。可能需要做一些修改。这里的所有答案都启发了我编写自己的解决方案,我将添加到编辑它的问题中。
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