Turtleグラフィックス⑥ フラクタル図形

Image from Gyazo

フラクタル図形

Turtleグラフィックスを利用して フラクタル図形 を描いてみましょう. フラクタル図形 とは,図形の一部が図形の全体と 自己相似 な関係を持つ図形のことです. 特定の処理を再帰的に繰り返して実行することで描くことができます. フラクタル図形は自然界でも観測が可能で,「シダの葉」や「雲の形」はフラクタル図形とされています. ここでは,フラクタルの性質を持つ「コッホ曲線」と「2分木」を描くことに挑戦しましょう.

準備

Muエディタを起動したら,Python3 モードを選択しましょう. ツールバーにある「保存」をクリックして,「chapter7.py」という名前でスクリプトを保存します. また,Turtleグラフィックスのライブラリ(モジュール)をインポートしておきましょう.

# Turtleグラフィックスのライブラリをインポート
from turtle import *

コッホ曲線

コッホ曲線は次の図に示す操作を再帰的に適用することで描くことができます. 直線を三分割し,中央の線分を底辺とした正三角形を描きます. このとき,図形全体を構成する4つの線分は同じ長さとなります. この処理を,各線分に対して再起的に適用することで, 2次,3次など高次のコッホ曲線を描くことができます.

Image from Gyazo

再帰を利用しない実装

関数koch()を定義して,再帰を利用しない方法で1次のコッホ曲線を描いてみましょう.

# 1次のコッホ曲線
def koch(length):

    next_length = length / 3

	forward(next_length)
    left(60)
	forward(next_length)
    right(120)
	forward(next_length)
    left(60)
	forward(next_length)
speed(0)
penup()
goto(-200, 0)
pendown()

length = 400 # 直線の長さ
koch(length)

Image from Gyazo

上記の1次のコッホ曲線の最初の辺だけ2次に変更してみましょう. 最初のforward(next_length)を,自己相似となるように,次のように置き換えます. このとき,2次のコッホ曲線の1辺の長さはlengthの1/9になります.

# 1次のコッホ曲線(最初の辺だけ2次に)
def koch(length):
    next_length = length / 3
    
    #----------
    # 最初の辺だけ2次に変更
    next_next_length = length / 3 / 3
	
    forward(next_next_length)
    left(60)
    forward(next_next_length)
    right(120)
    forward(next_next_length)
    left(60)
    forward(next_next_length)
    #---------
    
    left(60)
    forward(next_length)
    right(120)
    forward(next_length)
    left(60)
    forward(next_length)

Image from Gyazo

例題1

再帰を利用しないで2次のコッホ曲線を完成させてください.

再帰を利用した実装

関数koch()を,再帰を利用してコッホ曲線を描くように修正しましょう. forward(next_length)が,koch(n-1, next_length)に置き換わっています. 再帰的にkoch()を実行するときは,次元nを1だけ小さくし,nが0になったときに再帰処理を停止しています.

# n次のコッホ曲線
def koch(n, length):
    if n == 0:
        forward(length)
        return # 再帰の終了

    # n-1次の直線の長さ
    next_length = length / 3

    koch(n-1, next_length)
    left(60)
    koch(n-1, next_length)
    right(120)
    koch(n-1, next_length)
    left(60)
    koch(n-1, next_length)
speed(0)
penup()
goto(-200, 0)
pendown()

n = 0 # 次数
length = 400 # 直線の長さ
koch(n, length)

Image from Gyazo

n = 1 # 次数
length = 400 # 直線の長さ
koch(n, length)

Image from Gyazo

n = 2 # 次数
length = 400 # 直線の長さ
koch(n, length)

Image from Gyazo

n = 3 # 次数
length = 400 # 直線の長さ
koch(n, length)

Image from Gyazo

2分木

2分木は次の図に示す操作を再帰的に適用することで描くことができます. 1次では直線を描き,2次では左の枝と右の枝に分岐します. 左の枝は,左に30°回転し,その長さを0.8倍します. 右の枝は,右に30°回転し,その長さを0.5倍します. この処理を,再起的に適用することで,3次,4次など高次の2分木を描くことができます.

Image from Gyazo

再帰を利用しない実装

関数tree()を定義して,再帰を利用しない方法で2次の2分木を描いてみましょう.

# 2次の2分木
def tree(length, angle):

    forward(length)

	# 左の枝
    left(angle)
    next_left_length = 0.8 * length # 枝の長さを0.8倍
    forward(next_left_length)
    backward(next_left_length)

	# 右の枝
    right(angle * 2)
    next_right_length = 0.5 * length # 枝の長さを0.5倍
    forward(next_right_length)
    backward(next_right_length)

	# 始点に戻る
    left(angle)
    backward(length)	
speed(0)
penup()
goto(100, -200)
setheading(90)
pendown()

length = 150 # 枝の長さ
angle = 30 # 分岐の角度
tree(length, angle)

Image from Gyazo

上記の2次の2分木の左の枝だけ3次に変更してみましょう. 最初のforward(next_left_length)wabckward(next_left_length)を,自己相似となるように,次のように置き換えます. このとき,3次の2分木の左の枝の長さはlength * 0.8 * 0.8,右の枝の長さはlength * 0.8 * 0.5になります.

# 2次の2分木(左の枝だけ3次に)
def tree(length, angle):

    forward(length)

	# 左の枝
    left(angle)
    next_left_length = 0.8 * length # 枝の長さを0.8倍
    
    #----------
    # 左の枝だけ2次に変更
    forward(next_left_length)

	# 左の枝
    left(angle)
    next_next_left_length = 0.8 * next_left_length # 枝の長さを0.8倍
    forward(next_next_left_length)
    backward(next_next_left_length)

	# 右の枝
    right(angle * 2)
    next_next_right_length = 0.5 * next_left_length # 枝の長さを0.5倍
    forward(next_next_right_length)
    backward(next_next_right_length)

	# 始点に戻る
    left(angle)
    backward(next_left_length) 
    #----------

	# 右の枝
    right(angle * 2)
    next_right_length = 0.5 * length # 枝の長さを0.5倍
    forward(next_right_length)
    backward(next_right_length)

	# 始点に戻る
    left(angle)
    backward(length)

Image from Gyazo

例題2

再帰を利用しないで3次の2分木を完成させてください.

再帰を利用した実装

関数tree()を,再帰を利用して2分木を描くように修正しましょう. コッホ曲線と同じように,再帰的にtree()を実行するときは,次元nを1だけ小さくし,nが0になったときに再帰処理を停止しています.

# n次の2分木
def tree(n, length, angle):
    if n == 0:
        return # 再帰の終了

    forward(length)

	# 左の枝
    left(angle)
    next_left_length = 0.8 * length # 枝の長さを0.8倍
    tree(n-1, next_left_length, angle)

	# 右の枝
    right(angle * 2)
    next_right_length = 0.5 * length # 枝の長さを0.5倍
    tree(n-1, next_right_length, angle)

	# 始点に戻る
    left(angle)
    backward(length)
speed(0)
penup()
goto(100, -200)
setheading(90)
pendown()

n = 2 # 次数
length = 150 # 枝の長さ
angle = 30 # 分岐の角度
tree(n, length, angle)

Image from Gyazo

n = 4
length = 150
angle = 30
tree(n, length, angle)

Image from Gyazo

n = 6
length = 150
angle = 30
tree(n, length, angle)

Image from Gyazo

n = 8
length = 150
angle = 30
tree(n, length, angle)

Image from Gyazo

課題

次の課題に取組んでください.

Image from Gyazo

Image from Gyazo

Image from Gyazo

課題を完成させたらスクリプトを保存し,「chapter7.py」を提出してください.

参考書籍

愛知県名古屋市にある椙山女学園大学 文化情報学部 向研究室の公式サイトです. 専門は情報科学であり,人工知能やデータベースなどの技術要素を指導しています. この公式サイトでは,授業で使用している教材を公開すると共に, ベールに包まれた女子大教員のミステリアスな日常を4コマ漫画でお伝えしていきます. サイトに関するご意見やご質問はFacebookまたはTwitterでお問い合わせください.