Arantium Maestum

プログラミング、囲碁、読書の話題

Quilでフラクタル Dragon

「関数型オブジェクト指向AIプログラミング」フラクタルscalaからclojureに書き直す続き。

ドラゴン曲線を描いてみる。

namespaceやらdefsketchやらはkochのものを流用して、図形のためのdragon関数とそれに引数入れて呼ぶdrawだけ再定義:

(defn dragon [n length angle switch]
  (if (= n 1)
    (forward length angle)
    (let [new-l (/ length (/ 2 (Math/sqrt 2)))
          a     (* Math/PI 0.25 switch)]
      (dragon (dec n) new-l (- angle a) 1)
      (dragon (dec n) new-l (+ angle a) -1))))

(defn draw []
  (q/translate 50 100)
  (dragon 10 100 0 1))

こんな感じ:

f:id:zehnpaard:20160517061940p:plain

これはこれでいいのだが、再帰深度を表すnを変えていくとどうなるかを一つの画像で比較してみたかったのでdraw関数をいじっていたら、dragonのこの書き方だと描き終わった時点でペン先が戻らないので再利用しにくいことがわかった。

なので再帰の部分を呼び出す前にpush-matrix/pop-matrixをする別関数を作って、その間で再帰させる。

(defn dragon-r [n length angle switch]
  (if (= n 1)
    (forward length angle)
    (let [new-l (/ length (/ 2 (Math/sqrt 2)))
          a     (* Math/PI 0.25 switch)]
      (dragon-r (dec n) new-l (- angle a) 1)
      (dragon-r (dec n) new-l (+ angle a) -1))))

(defn dragon [n length angle switch]
  (q/push-matrix)
  (dragon-r n length angle switch)
  (q/pop-matrix))

この再定義されたdragon関数を使ってnを1〜15の間で入力するとどうなるかを比べてみる。

(defn draw []
  (q/translate 10 20)
  (doseq [i (range 15)]
    (q/push-matrix)    
    (q/translate (* (mod i 5) 40) 
                 (* (quot i 5) 30))
    (dragon (inc i) 24 0 1)
    (q/pop-matrix)))

結果がこれ。(dragon n ...)が(dragon n-1 ...)を45°回転させたものと135°回転させたもの二つの組み合わせでできていることがわかる。

f:id:zehnpaard:20160517063703p:plain