2012-11-10 3 views
6

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

これまでのところ、私は1次元のリストを考えました。リストの問題は、どの要素が各行/列/対角線に属するのか把握するのが難しく、次にList.mapで検索することが難しいことです。

私はArray.make 4 (Array.make 4 Empty);;を使用することを考えました。これは行になると絶対に完璧です。簡単にそれらを取得し、それにパターンマッチを行います。しかし、個々の列と対角線にパターンマッチングを行うのは雑用です。

私ができることを望むのは、ゲームボードを取り、すべての行/列/対角線を含むリストのリストを返す機能です。私は、例えば、match (rows,columns,diagonals) with (Empty, Empty, Empty, Empty) -> somethingのようにしたいと思います。

+4

あなたは優雅さや生のスピードのために行くされていますか?生の速度であれば、ゲームボード全体が32ビットに収まるように思えます。 OCamlを学びたいなら、優雅さはおそらくもっと良いでしょう。すべての言語で同様の扱いをします。 –

答えて

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セットがあります左上から右下に向かうものと、右から左に向かうものとの2つの方向(右上から左下):

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 

+0

徹底的な説明。これは、コードがどのように見えるかと非常によく似ていますが、私は思考をコードに入れることができませんでした。 私は、列に沿ってパターンマッチングを行うことができないことを少し残念ですが、あなたはそれをすべて取ることができないと思います。 ありがとう! – user1815201

2

長さが固定されているので、リストよりも配列が優先されます。メモリが少なく、読み書きが高速です。

私は対角線を取得するための関数を書く必要がありますが、単純なパターンマッチングはありません。 「対角線上で何らかの操作を行う」と書くと、のように、要素を格納する長さ4の配列をとる関数fが考えられます。 たぶんfは、位置としてpの位置と、位置の内側にあるインデックスの配列を引数として取ることができます。 f p [|x1,y1; x2,y2; x3,y3; x4,y4|]は、p.(x1).(y1) ... p.(x4).(y4)の四角形を抽出します。次にxyのものを渡して、fを行/列/対角線で操作させます。

コードが機能していて、最適化に回っている場合は、ビットベクトルを確認することをお勧めします。 あなたのツリーに多数の位置が格納されている場合は、キャッシュヒットと高速実行。あなたはイベントを1つのintで自分自身でエンコードしたいかもしれませんが、これはややこしい作業ですが、早すぎるとしたくない場合もあります。

+0

pは座標をとり、値を返す関数なのですか? 長さが固定されていると、配列がリストに優先されるのはなぜですか? – user1815201

+0

(私は配列対リストに関する答えを更新しました)。 'f'(' p'ではなく)は、座標をとり、 "値"を返す関数です。指定された座標の四角形がすべて空の場合は 'true'を返します。 'f'は与えられた座標で四角形の内容をルックアップする必要があるため、' p'を引数として受け取る必要があります。 したがって 'f'は' position - >(int * int)array - > bool'型です。 – jrouquie

1

タイルを対応する座標でインデックスするのはどうですか?だから、あなたの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-dリスト内のタイルのインデックス)でインデックスすることもできますが、フィルタ関数では何らかの計算が必要です(指定されたインデックス、次にそれが所望の行/列/対角線に属するか否かを決定する)。

関連する問題