6

私はOCamlにかなり慣れていないので、フォーインアラインに似たゲームを実装したいと思っています。私が必要としているのは、ゲームの状態を維持するためのデータ構造です。ゲームボードは4x4の正方形で、合計16個のタイルがあります。私は、列全体、行、または対角線のすべての要素を簡単かつ迅速に取得(または何らかの操作を実行)できるようにするOCamlでのこの表現を探しています。このゲームでミニマックス検索を行うので、速度が重要です。

これまで、1次元のリストについて検討してきました。リストの問題は、どの要素が各行/列/対角線に属しているかを把握し、List.mapたとえばでそれらを取得するのが難しいことです。

I thought about using Array.make 4 (Array.make 4 Empty);;. This is absolutely perfect when it comes to rows. Its easy to get them and do a pattern match on it. But it is a chore to do pattern matching on individual columns and diagonals.

What I would like to be able to do is have a function that takes a game board and returns a list of lists containing all the rows/columns/diagonals. I would then like to do, for example, match (rows,columns,diagonals) with (Empty, Empty, Empty, Empty) -> something.

4

3 に答える 3

2

長さは固定されているため、リストよりも配列を優先します。使用するメモリが少なく、読み取りと書き込みが高速です。

対角線を取得する関数を作成する必要があるのではないかと思います。単純なパターンマッチングはありません。「[対角線]で何らかの操作を行う」と書くときf、たとえば、要素を格納する長さ4の配列をとる関数について考えていると思います[|Empty;Empty;Empty;Empty|]。代わりfに、位置を引数として取ることができ、p位置内のインデックスの配列: f p [|x1,y1; x2,y2; x3,y3; x4,y4|]は正方形を抽出しp.(x1).(y1) ... p.(x4).(y4)ます。次に、異なるx'とy'を渡しfて、行/列/対角線を操作します。

コードが機能し、最適化に移ったら、ビットベクトルを確認することをお勧めします。minmax検索のツリーに多くの位置が格納されている場合、メモリフットプリントを減らすと、キャッシュヒットが増え、実行が速くなります。 。自分で1つのintに位置をエンコードしたい場合もありますが、これはトリッキーな作業であり、早すぎたくない場合があります。

于 2012-11-10T22:24:42.937 に答える
1

対応する座標でタイルをインデックス化するのはどうですか? したがって、一次元リストの要素は次の形式になります。

(int * int * ref tile)

次に、次のように行/列/対角線をフィルタリングできます。

行 n: (前提条件: 0 <= n、u、v <= 3)

List.filter tiles (fun x -> match x with (u, v, _) -> u = n);;

列 n: (前提条件: 0 <= n、u、v <= 3)

List.filter tiles (fun x -> match x with (u, v, _) -> v = n);;

対角 1: (前提条件: 0 <= u、v <= 3)

List.filter tiles (fun x -> match x with (u, v, _) -> u = v);;

対角線 2: (前提条件: 0 <= u、v <= 3)

List.filter tiles (fun x -> match x with (u, v, _) -> u + v = 3);;

1 つの整数 (1 次元リスト内のタイルのインデックス) だけでタイルにインデックスを付けることも可能ですが、フィルター関数でいくつかの計算が必要になります (インデックスを指定して、座標を計算し、目的の行/列/対角線に属します)。

于 2012-11-11T11:36:49.337 に答える
1

マッチングがうまくいかないこともあります。ここでは、可能な限り関数を使用するようにしてください。そうすれば、セルを最初に行または最初に列にすることはそれほど複雑ではなく、インデックスの順序を逆にすることで、ある表現から別の表現に移動することもできます。

次のタイプを使用する場合:

type color = Red | Yellow;;
type cell  = Empty | Color of color;;
type board = Array.make 4 (Array.make 4 Empty);;

最初に列を決定すると、次の関数が行または列を取得します。

let column (b: board) i j = b.(i).(j)
let row (b: board) i j = b.(j).(i)

対角線には 2 つのセットがあり、1 つは左上から右下に向かい、もう 1 つは反対方向 (右上から左下) に向かいます。

let ldiag (b: board) i j = b.((i + j) mod 4).(j)
let rdiag (b: board) i j = b.((i - j + 4) mod 4).(j)

次に、行、列、または対角線をチェックすることは、その行の 4 つのセルをチェックするだけの問題だと思います。

let check predicate linef k = predicate (linef b k 0) && 
                               predicate (linef b k 1) && 
                               predicate (linef b k 2) && 
                               predicate (linef b k 3)

たとえば、赤の対角線があるかどうかを確認します。

let has_line linef b color = 
    let cmp x = x = color in
    let check k = check cmp linef b k in
    check 0 || check 1 || check 2 || check 3

let has_ldiag b color = has_line ldiag b color
let has_rdiag b color = has_line rdiag b color

let has_red_diagonal b = has_ldiag b Red | has_rdiag b Red

等。

于 2012-11-12T00:34:26.043 に答える