【问题标题】:How to return the best first level in this F# minimax?如何在这个 F# minimax 中返回最好的第一级?
【发布时间】:2010-06-24 23:58:04
【问题描述】:

这个问题更像是一个语义-算法-数据结构问题,而不是一个 F# 句法问题。 我有一个 Minimax 算法。极小极大算法应该从起始位置返回最佳下一步移动。为此,它计算所有下一步移动,然后计算下一个下一步移动,直到确定的深度或直到没有更多移动。它会像这样构建一棵树:

     P  
   /  \  
 a      b  
/ \  
c d

我有闲置的数据结构来处理树:

type TreeOfPosition =
    | LeafP   of Position * int
    | BranchP of Position * TreeOfPosition list

在上面的示例树中,Pa 是分支,bcd 是叶子。下面的代码是我的极小极大算法:

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(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)

佩德罗·杜索

【问题讨论】:

  • 您能否详细说明您的问题?

标签: algorithm data-structures f# minimax


【解决方案1】:

我不太了解您样本的某些方面(例如,为什么您只匹配其中包含 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 

【讨论】:

    【解决方案2】:

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

    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
    

    【讨论】:

    • 我不明白您的代码中的子树和子树是什么。叶子和树枝是什么?我问这个是因为子树是来自上节点的子树......我没有明白你的意思。
    【解决方案3】:

    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

    【讨论】:

    • 只有订阅 The F#.NET Journal 才能阅读这篇论文? :(
    • 乔恩,我测试了你的解决方案。它可以工作,但是这样它会返回叶节点的静态值,我正在搜索整个节点来播放它。也许有一些修改。这里的所有答案都启发了我编写自己的解决方案,我将把它添加到我的问题中进行编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多