この質問は、F#の構文上の質問というよりも、意味論的アルゴリズムのデータ構造に関する質問です。私はミニマックスアルゴリズムを持っています。ミニマックスアルゴリズムは、開始位置から次の最良の動きを返す必要があります。これを行うために、それはすべての次の動きを計算し、次に次の次の動きを決定された深さまで、またはそれ以上の動きがなくなるまで動かします。次のようなツリーを構築します。
P
/ \
a b
/ \
c d
ツリーを処理するための休眠データ構造体があります。
type TreeOfPosition =
| LeafP of Position * int
| BranchP of Position * TreeOfPosition list
上記の例のツリーではP
、a
はブランチと、b
はリーフです。以下のコードは私のミニマックスアルゴリズムです:c
d
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)))
そして、この変更により、良い葉の静的な値が上がります。最高の第2レベルノードを返す必要があります。誰かが助けてくれることを願っています!ペドロ・デュッソ
編集1
すべての回答者に感謝します、彼らは私を大いに助けてくれます。申し訳ありませんが、あまり指定していませんでした。部分的に行きましょう:
LeafP(position, 0)
1)ツリーを作成するときに、静的な値としてデフォルト値0を使用してリーフを設定したため、LeafPと一致しています。静的な値を上げて、リーフを削除し、(ブランチの前の)リーフを(最小または最大)静的な値で作成するときに、この方法で元のブランチリーフを評価できないようにすると思いました( 0の値)。
2)私の最大の問題は、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)
ペドロ・デュッソ