「プログラムでシダを描画する」にようやく参加できた!
@noc06140728 さんのコードをベースに作成しました。ありがとうございます。
##変更点
- 再帰をなくしてジェネレータだけを使用
- 画像に濃淡を持たせた
- 関数をパラメータを各々ひとまとめにした
##コード
# coding: utf-8
import random
N = 1000000
WIDTH = 500
HEIGHT = 500
fern = [
[1.0, [+0.836, +0.044, 0.0, -0.044, +0.836, 0.169]],
[0.3, [-0.141, +0.302, 0.0, +0.302, +0.0141,0.127]],
[0.3, [+0.141, -0.302, 0.0, +0.302, +0.141, 0.169]],
[0.3, [0.0, 0.0, 0.0, 0.0, 0.175337, 0.0]],
]
p_table = []
def W(n,v):
c = fern[n][1]
return (c[0] * v[0] + c[1] * v[1] + c[2], c[3] * v[0] + c[4] * v[1] + c[5])
# Python 2.7 には itertools.accumulate がないので以下から借用して簡略化
# http://docs.python.jp/3.3/library/itertools.html#itertools.accumulate
def accumulate(iterable):
it = iter(iterable)
total = next(it)
yield total
for e in it:
total = total + e
yield total
def g(v, n):
it = 0
while it < n:
it += 1
yield v
r = random.random()
for i, p in enumerate(p_table):
if r < p:
v = W(i,v)
break;
if __name__ == '__main__':
# 確率の値ををならす
p_total = sum(f[0] for f in fern)
p_table = [a/p_total for a in accumulate([f[0] for f in fern])]
# 点の軌跡を溜めておくバッファ
acc = [0] * 3 * WIDTH * HEIGHT
# 最初の点
v = (0.0, 0.0)
acc_max = 1
for p in g(v, N):
x, y = (int((p[0] + 0.5) * WIDTH), HEIGHT - int(p[1] * HEIGHT))
if x >=0 and x < WIDTH and y >= 0 and y < HEIGHT:
acc_index = x + y * HEIGHT
acc[acc_index] += 1
if acc[acc_index] > acc_max:
acc_max = acc[acc_index]
from math import pow
from PIL import Image
im = Image.new("RGB", (WIDTH, HEIGHT), (255, 255, 255))
pix = im.load()
for i in xrange(WIDTH * HEIGHT):
#if acc[i]:
# 暗いところを持ち上げる
d = int(pow(float(acc[i]) / float(acc_max),1.0/15.0) * 255.0)
pix[i % WIDTH, i / WIDTH] = (0, d, 0)
im.show()
##まとめ
楽しかった!