5.確率的L-system

次の2つの写真をみてください。

どちらも、きれいに枝分かれしているように見えます。しかし、左側に比べると、右側の方は枝の長さや比率にばらつきがあります。

「5.樹を描く」で描いたのは、左側のように規則的に成長した図でした。(それでも実際には少しばらつきがあります)

このように、ある規則にしたがっているために、先の方まで予測できるものは「決定論的(deterministic)」といいます。これに対して、ばらつきがありながら、それでも数学的に記述できる場合、「確率的(stochastic)」といいます。つまり、「ばらつき」を確率としてとらえるのです。

リンデンマイヤーの「The Algorithmic Beauty of Plants」には、「Stocastic L-system」として次のような例が載っています。

3つのジェネレータを用意し、それぞれ確率3分の1で置き換えを行なうのです。

確率3分の1で F→F[+F]F[−F]F

確率3分の1で F→F[+F]F

確率3分の1で F→F[−F]F

すると次のように、実行するたびに生成される図が違ってきます。(少しずらして3回実行した結果)

この節では、成長過程においていくつかのパターンを確率的に選択しながら成長していくシステムを作ります。

まず、「確率3分の1」をどのように発生させるかですが、このようなときは「乱数」を用います。CindyScriptでは、乱数を発生する関数がいくつか用意されています。ここでは randomint() という関数を用いるのがよいでしょう。

--------------------------------------------

p=randomint(3)

--------------------------------------------

とすると、0,1,2の3つの数がランダムに発生してpの値となります。3つの数字のどれかなので、それぞれの数になる確率が3分の1になるのです。この「乱数発生」についてのスクリプトの作り方は、「乱数の発生」というページに少し詳しく書きました。

さて、3つのジェネレータを用意しましょう。それにはリストを用います。

   generatorlist=[[["F","F[+F]F[-F]F"]],[["F","F[+F]F"]],[["F","F[-F]F"]]]; 

少しややこしいですが、括弧の数に注意してください。1つのジェネレータはリストで変換規則を記述したものです。

F→F[+F]F[−F]F

という変換規則は [["F","F[+F]F[-F]F"]] です。ジェネレータの変換規則は複数個をリストにして記述できますので、1つだけなら、1つだけの要素からなるリストということで、括弧は2つになるのです。これらのジェネレータを3つリストにしたのが上の generatorlist です。

さて、この中から、乱数でどれかを選びます。randomint(3) で0,1,2の乱数ができるので、これに1を足してpとします。

p=randomint(3)+1

一般化するには、length() 関数を用いて、リストの個数を数えます。

   len=length(generatorlist);

p=randomint(len)+1

リストのp番目を取り出すには、アンダーバーを使います。

s=replace(s,generatorlist_p);

とすれば、generatorlist の中からp番目の要素(変換規則)をとり出して、文字列sをその変換規則で置き換えます。

この作業をする関数を次のように定義して、Initializationスロットに追加します。

-----------------------------------------------------------------------------------------------------------------------

// initiator と generatorlist から乱数でコマンド列を作成する

makecomprob(n):=(

  workstr=initiator;

  len=length(generatorlist);

  repeat(n,

    p=randomint(len)+1;

    workstr=replace(workstr,generatorlist_p);

  );

);

-----------------------------------------------------------------------------------------------------------------------

こうしてできたコマンド列sを、tree( ) 関数で表示します。 

「5.樹を描く」で作ったスクリプトの Draw スロットの内容を書き換えて実行してみましょう。

一つ描いたあと少し移動するには、直接亀を少しだけ動かします。たとえば、

・最初に上を向く

・木を1本描く

・横に向きを戻して、少し進む

という動作をまとめて何回か繰り返します。次の図では6回繰り返しています。

ここまでは、リンデンマイヤーの本にしたがって、3つのジェネレータを3分の1の確率で選ぶことをやってみました。

この他に、次のようなことが考えられるでしょう。

・ジェネレータを増やす。選ばれる確率を変える。

・角度もいくつか用意して確率で選ぶ。

・枝の長さをいくつか用意して確率で選ぶ。

< 戻る >