2016-12-10 8 views
0

私はこれまでC++でこれをしてきたので、Conwayの人生の練習をしようとしていますが、高さと幅を指定して2次元配列を生成する方法が不思議でした。与えられた人口密度に基づいて無作為に割り当てられたスポーンを持つOcaml、私は途中でmake_matrixを使用しようとしています。私がオンラインで見つけたすべてのチュートリアルでは、グラフィックや他のハードコーディングされた方法(ロゼッタコードなど)を使用していましたが、私はそれを避けていくつかのバリエーションを持つことができます。ありがとうございました。ゲームのOCaml 2D配列

これは私の現在のコードで、アンバウンド値を返しています。

print_string "Input width "; 
let num = read_int() in 
print_string "Input height"; 
let num2 = read_int() in 
    myArray = Array.make_matrix num num2 0; 

error: Unbound value myArray; 

答えて

1

あなたはここに複数の選択肢があります。

  1. ビッグ配列
  2. 配列

Bigarraysがそれらの値として数字のみを持つことができますが、彼らはのものとすることができるマッピングします任意のサイズと寸法。また、多次元データにアクセスするための素晴らしいインターフェースも備えています。配列は任意の型の値を持つことができ、配列の配列を作成して多次元空間をモデル化することができます。配列とbigarrayはどちらも必須のデータ構造なので、あなたのコードになります。そのため、永続的なマップを使用してコードを純粋に機能させることをお勧めします(OCamlで練習したい場合は、機能的な部分空間で練習する方がよい)。だから、地図

例は、の状態のための型を定義し、座標ましょう:

type state = Dead | Live 

type coord = {x : int; y : int} 

我々はマップを使用しますので、我々は未実装の状態を必要としません。非人口状態はマップされていません。

今、私たちはボードのデータ構造の実装を定義することができます。

module Board = Map.Make(struct 
    type t = coord 
    let compare = compare 
    end) 

使い方の例として、それぞれの人口隣接セルへのユーザ提供関数を適用しますfold_neighborsと呼ばれる高階関数を定義してみましょう。この一般的なイテレータ機能を使用して

let neighbors {x;y} = [ 
    x, y+1; 
    x+1,y+1; 
    x+1,y; 
    x+1,y-1; 
    x, y-1; 
    x-1,y-1; 
    x-1,y; 
    x-1,y+1; 
] |> List.map (fun (x,y) -> {x;y}) 

let fold_neighbors board cell ~f ~init = 
    neighbors cell |> 
    List.fold_left (fun acc n -> 
     try f acc (Board.find n board) 
     with Not_found -> acc) 
    init 

、我々はcount_live_neighborsのような特殊な機能を定義することができます。

let count_live_neighbors = 
    fold_neighbors ~init:0 ~f:(fun count nb -> match nb with 
     | Live -> count + 1 
     | Dead -> count) 

実装が無限ボードを前提とし、あなたはそれが有界作りたい場合は、あなたがfold_neighborsを適応させる必要がありますボードの外にいる人を除外する機能。

アレイの例

もう1つの方法は、通常のアレイを使用する方法です。我々は、300行400列のゼロで満たされたマトリックスを作成する

make_matrix 300 400 0 

例えば、所定の大きさの2次元配列を作成した値でそれを充填する便利make_matrix関数を使用することができます。

この例では、マトリックスに数値を入力するのではなく、状態を入力したいと考えています。3つの状態を表すことができる状態の型が必要ですが、前の例のstate型を再利用しますが、それをoption型にラップして、死んだり生きているセルも表現しますSome DeadまたはSome Live、および未実装1がちょうどNoneとなりますので、我々は我々が最初にそれを作成した後、ランダムに基づいてセルを選択するために命を与えることができ、当社のボードを初期化するには

Array.make_matrix width height None 

と空のボードを作成することができますように必要な人口密度。 0と1との間の浮動小数点数で密度を表現する。例えば、密度は0.1であり、約10%のセルが生存することを意味する。より機能的になるために、Array.mapを使用して配列を変換します。インプレース変更と明示的なループや反復がより速く、より慣用もちろんのこと、ちょうど実験のための、より機能的なアプローチを使用してみましょうになります。

let create_board width height density = 
    Array.make_matrix width height None |> 
    Array.map (Array.map (fun cell -> 
     if Random.float 1.0 > density then Some Live else None)) 

我々は作成されません場合は、我々は、よりきれいにこれを行うことができます最初の手の空のボードですが、初期化されたボードから始まります。このために、我々は、セル毎に異なる値を与えることができますArray.init機能を使用することができ、ここではより良いcreate_board機能の例です。

let create_board width height density = 
    Array.init height (fun _ -> 
     Array.init width (fun _ -> 
      if Random.float 1.0 > density then Some Live else None)) 

Array.init関数は、要素のインデックスを持つユーザーに提供関数を呼び出します。私たちの場合、生命の可能性は座標に依存しないので、ポジションを無視することができます。そのため、_を使用して、引数を使用しません。

+0

回答をいただきありがとうございます。私はその行列を使うことにしました。与えられた集団密度に基づいて生きている細胞と死んだ細胞のいずれかをマトリックスに埋め込む方法があるかどうか分かりますか?私はmake_matrixの幅の高さ密度を使用しています –

+0

さて、私は配列の例で答えを更新しました。ハッピーキャリング:) – ivg