LoginSignup
25
25

More than 5 years have passed since last update.

「プログラムでシダを描画する」をPythonで描画する

Posted at

「プログラムでシダを描画する」シリーズに便乗して、Pythonでも書いてみました。

出力結果

Screenshot_from_2014-05-27 00:35:50.png

ソースコード

再帰呼び出し版

  • オリジナルと類似の再帰呼び出し版です。
  • 関数定義には lambda を使ってスッキリ書いてみました。
  • 画像ライブラリ PIL(Python Imaging Library) または Pillow が必要です。
import random

N = 20
xm = 0
ym = 0.5
h = 0.6

width = 500
height = 500

W1x = lambda x, y: 0.836 * x + 0.044 * y
W1y = lambda x, y: -0.044 * x + 0.836 * y + 0.169
W2x = lambda x, y: -0.141 * x + 0.302 * y
W2y = lambda x, y: 0.302 * x + 0.141 * y + 0.127
W3x = lambda x, y: 0.141 * x - 0.302 * y
W3y = lambda x, y: 0.302 * x + 0.141 * y + 0.169
W4x = lambda x, y: 0
W4y = lambda x, y: 0.175337 * y

def f(im, k, x, y):
    if 0 < k:
        f(im, k - 1, W1x(x, y), W1y(x, y))
        if random.random() < 0.3:
            f(im, k - 1, W2x(x, y), W2y(x, y))
        if random.random() < 0.3:
            f(im, k - 1, W3x(x, y), W3y(x, y))
        if random.random() < 0.3:
            f(im, k - 1, W4x(x, y), W4y(x, y))
    else:
        s = 490
        im.putpixel((int(x * s + width * 0.5), int(height - y * s)), (0, 128, 0))

if __name__ == '__main__':
    from PIL import Image
    im = Image.new("RGB", (width, height), (255, 255, 255))
    f(im, N, 0, 0)
    im.show()

これでは、関数 f() で画像関連の引数を渡したり、関数内部に描画ロジックを書く必要があったりして、ちょっと美しくないので、もう少し Pythonic にしてみました。

再帰呼び出し+ジェネレータ版

  • ジェネレータを使って、再帰呼び出しの結果を yield で返してやるようにしました。
  • 描画ロジックは、関数 f() の外へ追い出すことができました。
import random

N = 20
xm = 0
ym = 0.5
h = 0.6

width = 500
height = 500

W1x = lambda x, y: 0.836 * x + 0.044 * y
W1y = lambda x, y: -0.044 * x + 0.836 * y + 0.169
W2x = lambda x, y: -0.141 * x + 0.302 * y
W2y = lambda x, y: 0.302 * x + 0.141 * y + 0.127
W3x = lambda x, y: 0.141 * x - 0.302 * y
W3y = lambda x, y: 0.302 * x + 0.141 * y + 0.169
W4x = lambda x, y: 0
W4y = lambda x, y: 0.175337 * y

def f(k, x, y):
    if 0 < k:
        for p in f(k - 1, W1x(x, y), W1y(x, y)):
            yield p
        if random.random() < 0.3:
            for p in f(k - 1, W2x(x, y), W2y(x, y)):
                yield p
        if random.random() < 0.3:
            for p in f(k - 1, W3x(x, y), W3y(x, y)):
                yield p
        if random.random() < 0.3:
            for p in f(k - 1, W4x(x, y), W4y(x, y)):
                yield p
    else:
        s = 490
        yield x * s + width * 0.5, height - y * s

if __name__ == '__main__':
    from PIL import Image
    im = Image.new("RGB", (width, height), (255, 255, 255))
    for p in f(N, 0, 0):
        im.putpixel((int(p[0]), int(p[1])), (0, 128, 0))
    im.show()

まとめ

  • 再帰呼び出し+ジェネレータの合わせ技
  • 描画ロジックと座標計算ロジックを分離
  • yield でさらりと書けるジェネレータはお気に入りです。
25
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
25