Reputation: 19
I want to make a fractal tree in python. I have made the tree, but I want to have 2 turtles or more to draw my fractal tree all at once. Is there a way to do that? I've looked for solutions but none of them is what I really want. Here is my code:
import turtle
tree = turtle.Turtle()
tree.ht()
tree.penup()
tree.sety(-200)
tree.left(90)
import turtle
tree0 = turtle.Turtle()
tree0.ht()
tree0.penup()
tree0.sety(-200)
tree0.left(90)
startx = tree.xcor()
starty = tree.ycor()
startx = tree0.xcor()
starty = tree0.ycor()
def fractalright(angle, length, x, y):
tree.speed(0)
tree.setx(x)
tree.sety(y)
tree.pendown()
tree.forward(length)
tree.right(angle)
length = length - 20
x = tree.xcor()
y = tree.ycor()
if length < 0:
return
tree.penup()
fractalright(angle, length, x, y)
tree.penup()
tree.setx(x)
tree.sety(y)
tree.left(angle)
fractalright (-angle, length, x, y)
def fractalleft(angle, length, x, y):
tree0.speed(0)
tree0.setx(x)
tree0.sety(y)
tree0.pendown()
tree0.forward(length)
tree0.right(angle)
length = length - 20
x = tree0.xcor()
y = tree0.ycor()
if length < 0:
return
tree0.penup()
fractalleft(angle, length, x, y)
tree0.penup()
tree0.setx(x)
tree0.sety(y)
tree0.left(angle)
fractalleft (-angle, length, x, y)
I am using python 3 and please let me know if you know a solution. Thanks!!
Upvotes: 1
Views: 878
Reputation: 41905
The key to using module threading
with turtle
is to not allow additional threads to manipulate the turtles -- they instead queue up their turtle requests and let the main thread process them:
import queue
from threading import Thread, active_count
from turtle import Turtle, Screen
def forward(turtle, distance):
graphics.put((turtle.forward, distance))
def right(turtle, angle):
graphics.put((turtle.right, angle))
def left(turtle, angle):
graphics.put((turtle.left, angle))
def fractalright(turtle, angle, length):
forward(turtle, length)
if length - 20 > 0:
right(turtle, angle)
fractalright(turtle, angle, length - 20)
left(turtle, angle)
fractalright(turtle, -angle, length - 20)
forward(turtle, -length)
def fractalleft(turtle, angle, length):
forward(turtle, length)
if length - 20 > 0:
left(turtle, angle)
fractalleft(turtle, angle, length - 20)
right(turtle, angle)
fractalleft(turtle, -angle, length - 20)
forward(turtle, -length)
def process_queue():
while not graphics.empty():
action, argument = graphics.get()
action(argument)
if active_count() > 1:
screen.ontimer(process_queue, 100)
START_X, START_Y = 0, -200
screen = Screen()
screen.mode('logo') # make starting direction 0 degrees towards top
tree1 = Turtle(visible=False)
tree1.color('green')
tree1.penup()
tree1.goto(START_X, START_Y)
tree1.pendown()
tree2 = Turtle(visible=False)
tree2.color('dark green')
tree2.penup()
tree2.goto(START_X, START_Y)
tree2.pendown()
graphics = queue.Queue(1) # size = number of hardware threads you have - 1
def fractal1():
fractalright(tree1, 30, 100)
def fractal2():
fractalleft(tree2, 30, 100)
thread1 = Thread(target=fractal1)
thread1.daemon = True # thread dies when main thread (only non-daemon thread) exits.
thread1.start()
thread2 = Thread(target=fractal2)
thread2.daemon = True # thread dies when main thread (only non-daemon thread) exits.
thread2.start()
process_queue()
screen.exitonclick()
We're using the queue module for thread-safe communications. I rewrote your fractalright()
and fractalleft()
functions to minimize the variety of graphics operations they require.
If all goes correctly, you should see the light green and dark green portions of the tree being drawn independently at the same time. Your computer needs to have at least a couple of hardware threads available.
Upvotes: 0
Reputation: 355
Distilling away the details of how you are drawing the trees, the basic task is to execute two instances of some draw function in parallel with different arguments to specify one "left tree" and one "right tree." This basic structure can be implemented as follows:
from multiprocessing.dummy import Pool
import time
def draw_function(current_tree):
# Replace the following lines with what you need to do with turtles
print("Drawing tree {}".format(current_tree))
time.sleep(1)
# Replace this with list of tuples of arguments to draw_function specifying
# angle, length, x, y, left vs right, etc.
list_of_trees = ["left_tree", "right_tree"]
my_pool = Pool(2)
results = my_pool.map(draw_function, list_of_trees)
my_pool.close()
my_pool.join()
In your case, I'm a little unclear on the distinction between fractalleft
and fractalright
, since they appear identical, but that logic should form the basis for your draw_function
. You should create a separate turtle for each execution of draw_function
, but note that you needn't re-import turtle.
Upvotes: 1