PythonでL-Systemsを作る(2) 置き換えシステム
置き換えシステム
L-Systemsはフラクタルと密接な関係がある。フラクタルでは、「自分の一部が全体と相似である」自己相似形という特徴を持っている。代表的なのがコッホ曲線やシェルピンスキー曲線などだ。まずはコッホ曲線の中でも有名な雲形曲線を見てみよう。
1本の線分を三等分し,中央で正三角形状に折り曲げる。はじめの線分をイニシエータ,折り曲げた折れ線をジェネレータと呼び,イニシエータの線分をジェネレータで置き換える。できた図形の各線分を再びジェネレータで置き換えると次のようになる。
さらに置き換えを続けると次のようになっていく。
これがコッホ曲線(雲形曲線)だ。
タートルの「前進」をFで,左に回転を+で,右に回転を-で表す。今,回転角を60°とする。
イニシエータは前進だけなので F で表される。
ジェネレータは,前進・左に60°回転・前進・右に120°回転(60°を2回)・前進・左に60°回転・前進 だから F+F--F+F で表される。
イニシエータの F をジェネレータで置き換えると F+F--F+F になり,そのFをさらにジェネレータで置き換えると F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F となる。タートルの進む距離は,置き換えるたびに,たとえば3分の1にする。
F F+F--F+F ↑
F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F
このように次々に置き換えたものをタートルへの命令とすれば,雲形の図形ができていく。
イニシエータを正三角形にすると,次のようになっていく。これはコッホの雪片曲線という。
置き換えシステムを作る
Pythonの文字列処理には,replace(str1,str2) というメソッドがある。文字列の中の str1 を str2 で置き換える。 もう一つ,translate(str.maketrans(dict)) というメソッドがある。前者では文字列の置換を1種類だけ行う。後者は,1文字だけの置換を複数行える。今はどちらでもよいが,あとのこと(L-Systemsの設計)を考え,translate() を使って,イニシエータとジェネレータからコマンド列を作る。
コッホ曲線では「 F を F+F--F+F で置き換える」なので,これを辞書型で表すと {"F":"F+F--F+F"} となる
initiator = "F"
generator = {"F":"F+F--F+F"}
com をコマンド列として,置き換えシステムを作ろう。はじめは com はイニシエータそのものだ。repeat は置き換えを繰り返す回数。
initiator = "F"
generator = {"F":"F+F--F+F"}
repeat = 1
com = initiator
for i in range(repeat):
com = com.translate(str.maketrans(generator))
このあとに print(com) を書いて確かめてみると
repeat = 1 のとき F+F--F+F
repeat = 2 のとき F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F
repeat = 3 のとき F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F+F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F+F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F
となっていく。
コマンド列を解釈してタートルを動かす
ひとまず,3つの文字に対応すればよい。1歩の長さは distance で表す。
def turtle(command):
if command == "F":
kame.forward(distance)
if command == "+":
kame.left(angle)
if command == "-":
kame.right(angle)
実際に亀が進む距離は,はじめは400で,繰り返しを1回行うごとに3分の1ずつにしよう。
以上をすべて書くと次のようになる。
import turtle as kame
# 亀を命令に従って動かす
def turtle(command):
if command == "F":
kame.forward(distance)
if command == "+":
kame.left(angle)
if command == "-":
kame.right(angle)
angle = 60
initiator = "F"
generator = {"F":"F+F--F+F"}
repeat = 3
distance = 400*(1/3)**repeat
com = initiator
for i in range(repeat):
com = com.translate(str.maketrans(generator))
for command in com:
turtle(command)
kame.done()
雪片曲線では,イニシエータとジェネレータを次のようにすればよい。
initiator = "F++F++F"
generator = {"F":"F-F++F-F"}
ジェネレータの回転方向が雲形曲線と逆になっている。その理由を考えてみよう。
さて,実際にやってみると,repeat = 2 のときでもコマンド列の文字数は112になる。見ていればわかるが,亀がせっせと線を引いていっても全部を描き終わるまでかなりの時間がかかる。アニメーションはなくていいから,結果を得たいならば,turtle によるタートルグラフィクスではなく,アニメーションのないタートルグラフィクスシステムを作ればよい。
次回はそのタートルグラフィクスシステムを作っていこう。