Turtle
前回、PythonのグラフィックライブラリTurtleでジェネレータを使ったTurtleの動かし方を紹介しました。

今回はジェネレータを使ってさらに複数の亀さんを同時(っぽく)に動かす方法を紹介します。
ちなみにジェネレータを使わずに2つの亀さんを準備し、動かしてみるとこんな感じになります。
import turtle
r = 100
t1 = turtle.Turtle()
t1.circle(r)
t2 = turtle.Turtle()
t2.pencolor("Red")
t2.right(180)
t2.circle(r)
turtle.done()プログラムは上から順に処理されていくので、どうやっても2つの円が同時に描かれることはありません。
2つの亀さんを同時(っぽく)に動かす方法
それではどうやって複数の亀さんを同時(っぽく)動かすのか、その方法を解説していきます。
ちなみに毎回「同時(っぽく)」と書いているように、完全に同時に描くわけではありません。
流れをいうと、こんな感じです。
- 2匹(もしくは複数)の亀さんを用意
 - 亀さん1を少しだけ動かす
 - 亀さん2を少しだけ動かす
 - 2、3を繰り返す
 
つまり複数の亀さんを順に少しずつ動かすことによって、同時に動いているように見せかけるというわけです。
いきなりたくさんの亀さんを動かすのは難しいので、とりあえず2匹の亀さんを同時(っぽく)に動かしてみましょう。
import turtle
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t2.pencolor("Red")
t2.right(180)
def move(t):
    for i in range(36):
        t.forward(20)
        t.right(10)
        yield(0)
t1_move = move(t1)
t2_move = move(t2)
         
while True:
    flag_t1 = next(t1_move, 1)
    flag_t2 = next(t2_move, 1)
    if flag_t1 == 1 and flag_t2 == 1:
        break
    
turtle.done()順に解説していきましょう。
まず最初の部分は準備です。
import turtle
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t2.pencolor("Red")
t2.right(180)turtleをインポートいて、亀1(t1)、亀2(t2)を準備します。
亀2はわかりやすいように線を赤にして、さらに逆向きにしています。
次は亀さんの動きの準備です。
def move(t):
    for i in range(36):
        t.forward(20)
        t.right(10)
        yield(0)
t1_move = move(t1)
t2_move = move(t2)ここでジェネレータ(move関数)を作成し、亀1と亀2に動きを覚え込ませます。
「t1_move = move(t1)」のように引数を入力したジェネレータを変数に格納することで、「next(ジェネレータ)」で毎回「yield」まで実行されるようになります。
ということで最後に亀さんを動かします。
while True:
    flag_t1 = next(t1_move, 1)
    flag_t2 = next(t2_move, 1)
    if flag_t1 == 1 and flag_t2 == 1:
        break
    
turtle.done()1周回ったら亀さんの動きを停止させたいので、2匹の亀さんそれぞれにflagを作成しています。
このflagはmove関数から「0」が返されなくなったら、つまり上記の例では36回の繰り返しが終わったら、「next(ジェネレータ, 値)」の値、つまり今回は「1」が返されるようになります。
そこで亀1、亀2の両方のflagが「1」になったときに「break」で繰り返しを止めています。
流れとしてはこんな感じです。
複数の亀さんを同時(っぽく)に動かす方法
では次にもっと多くの亀さんを同時(っぽく)に動かす方法を紹介していきます。
プログラム全体としてはこんな感じ。
import turtle
num_turtles = 5
turtles = []
for i in range(num_turtles):
    t = turtle.Turtle()
    t.right(360/num_turtles*(i))
    turtles.append(t)
def move(t):
    for i in range(36):
        t.forward(20)
        t.right(10)
        yield(0)
turtles_move = []
for turtle in turtles:
    turtles_move.append(move(turtle))
         
flag = 0
while True:
    for t_move in turtles_move:
        flag = flag + next(t_move, 1)
    if flag >= num_turtles:
        breakまず準備部分ですが、いくつの亀さんを準備するかを決めていない場合は、亀さんを作成したらリストに格納していきます。
import turtle
num_turtles = 5
turtles = []
for i in range(num_turtles):
    t = turtle.Turtle()
    t.right(360/num_turtles*(i))
    turtles.append(t)そして亀さんの動きの準備ですが、こちらもリストを使って動きを覚え込ませた亀さんを格納していきます。
def move(t):
    for i in range(36):
        t.forward(20)
        t.right(10)
        yield(0)
turtles_move = []
for turtle in turtles:
    turtles_move.append(move(turtle))最後の亀さんを動かす部分です。
flag = 0
while True:
    for t_move in turtles_move:
        flag = flag + next(t_move, 1)
    if flag >= num_turtles:
        breakwhile文で繰り返す前にflagを準備して、全てのflagが「1」に、つまりたし合わせたら亀さんの数(以上)になったら繰り返しを停止しています。
flagnの使い方はもう少しスマートな方法がありそうですが、とりあえず思った通りに動いているので、今回はこれでよしとします。
塗りつぶす際の注意点
複数の亀さんを使う場合、塗りつぶしには注意をしなければいけません。
なぜなら塗りつぶしの判定は亀さん単位だからです。
つまり複数の亀さんによって描かれた線が交差していたとしても、塗りつぶしの判定としては交差していないことになるのです。
ということで試してみましょう。
import turtle
import random
num_turtles =5
turtles = []
for i in range(num_turtles):
    t = turtle.Turtle()
    t.right(360/num_turtles*(i))
    turtles.append(t)
def move(t):
    pencolor = (random.random(), random.random(), random.random())
    fillcolor = (random.random(), random.random(), random.random())
    
    t.color(pencolor, fillcolor)
    t.begin_fill()
    for i in range(36):
        t.forward(20)
        t.right(10)
        yield(0)
    t.end_fill()
turtles_move = []
for turtle in turtles:
    turtles_move.append(move(turtle))
         
while True:
    flag = 0
    for t_move in turtles_move:
        flag = flag + next(t_move, 1)
    if flag == num_turtles:
        breakということで前に紹介した塗りつぶしを使って複雑な図形を描く方法は、複数の亀さんを同時に動かす方法とは同時にしようできないようなので注意してください。


次回は一度基礎に戻ってタプル(tuple)に関して勉強します。

ではでは今回はこんな感じで。

コメント