pythonturtle-graphicspython-turtlesimultaneous

Python Multiple Turtles Moving (seemingly) Simultaneously


I'm working on testing something for my teacher, he wants to see how the program below could possibly run faster if we simulated the simultaneous (i know it can't be perfectly simultaneous, this is just an experiment for the sake of learning/practicing) movement of multiple turtles. I've tried using modules like multiprocessing, threading, and even some crazy stupid attempt to time and delay (I'm in high school and I just learned about classes in python because of a previous question I asked I think last week).

So after many failed attempts I'm asking if someone has a few ideas of what else to try, or a direction to go in to simulate simultaneous movement of the turtles

import turtle
from turtle import Turtle

turtle.getscreen().delay(0)
class MyTurtle(Turtle):
    def petal(self):
        for i in range(90):
            self.fd(1)
            self.rt(1)
        self.rt(90)
        for i in range(90):
            self.fd(1)
            self.rt(1)

    def stem(self):
        self.pencolor('green')
        self.fd(250)

    def flowerhead(self):
        for i in range(9):
          self.pencolor('red')
          self.begin_fill()
          self.petal()
          self.lt(230)
          self.end_fill()

    def stempetal(self):
        self.seth(90)
        self.rt(15)
        self.fillcolor('green')
        self.begin_fill()
        self.petal()
        self.end_fill()

    

tony = MyTurtle(shape='turtle')
todd = MyTurtle(shape='turtle')
tina = MyTurtle(shape='turtle')
tiny = MyTurtle(shape='turtle')
tweeny = MyTurtle(shape='turtle')


def flower1():
    todd.speed('fastest')
    todd.fillcolor('blue')
    todd.flowerhead()
    todd.seth(270)
    todd.stem()
    todd.stempetal()
            
def flower2():
    tony.speed('fastest')
    tony.setpos(80, -15)
    tony.pencolor('green')
    tony.goto(0, -200)
    tony.fillcolor('purple')
    tony.goto(80,-15)
    tony.rt(40)
    tony.flowerhead()
    

def flower3():
    tina.speed('fastest')
    tina.setpos(-80, -15)
    tina.pencolor('green')
    tina.goto(0, -200)
    tina.fillcolor('teal')
    tina.goto(-80,-15)
    tina.lt(40)
    tina.flowerhead()
    
    
def flower4():
    tiny.speed('fastest')
    tiny.setpos(160, -25)
    tiny.pencolor('green')
    tiny.goto(0, -200)
    tiny.fillcolor('black')
    tiny.goto(160, -25)
    tiny.flowerhead()
    
    
def flower5():
    tweeny.speed('fastest')
    tweeny.setpos(-160, -25)
    tweeny.pencolor('green')
    tweeny.goto(0, -200)
    tweeny.fillcolor('pink')
    tweeny.goto(-160,-25)
    tweeny.lt(40)
    tweeny.flowerhead()
    
    
flower2()
tony.hideturtle()
flower4()
tiny.hideturtle()
flower3()
tina.hideturtle()
flower5()
tweeny.hideturtle()
flower1()
todd.hideturtle()

Solution

  • You've asked for two different things, 'run faster' and 'simulate simultaneous movement'. I believe we can do both (separately) but I don't believe that tracer() and update() are the answer in this situation as they'd just be a band-aid to cover over the real issue.

    wants to see how the program below could possibly run faster

    If you want it to run faster, fix the bottleneck which is the petal() function. Replace it with something that uses turtle's built-in circle() function which is faster. For example:

    def petal(self):
        self.circle(-60, 90)
        self.rt(90)
        self.circle(-60, 90)
    

    This speeds up your code by a factor of 25X with no other changes.

    simulate simultaneous movement of the turtles

    This can be done with turtle's own ontimer() event hander and some careful programming. Surprisingly, we use your original petal() logic as it breaks up the graphics into minute steps between which we can switch off processing to another timed event:

    from random import randint
    from turtle import Turtle, Screen
    
    class MyTurtle(Turtle):
    
        def petals(self, size=30, count=8, speed=100):
            if size == 30:
                self.begin_fill()
    
            if size > 0:  # drawing leading edge of petal
                self.fd(3)
                self.rt(3)
    
                screen.ontimer(lambda: self.petals(size - 1, count, speed), speed)
                return
    
            if size == 0:  # switch to other edge of petal
                self.rt(90)
    
            if size > -30:  # drawing trailing edge of petal
                self.fd(3)
                self.rt(3)
    
                screen.ontimer(lambda: self.petals(size - 1, count, speed), speed)
                return
    
            self.end_fill()  # finish this petal
            self.lt(230) # prepare for the next petal
    
            if count > 0:  # drawing the next petal
                screen.ontimer(lambda: self.petals(count=count - 1, speed=speed), speed)
                return
    
            self.hideturtle()  # finished drawing
    
        def stem(self):
            self.pencolor('green')
            self.fd(250)
    
        def flowerhead(self):
            self.pencolor('red')
    
            self.petals(speed=randint(50, 250))
    
    def flower2():
        tony.color('green', 'purple')
        tony.penup()
        tony.goto(0, -200)
        tony.pendown()
        tony.showturtle()
        tony.goto(80, -15)
        tony.rt(40)
        tony.flowerhead()
    
    def flower3():
        tina.color('green', 'turquoise')
        tina.penup()
        tina.goto(0, -200)
        tina.pendown()
        tina.showturtle()
        tina.goto(-80, -15)
        tina.lt(40)
        tina.flowerhead()
    
    def flower5():
        tweeny.color('green', 'pink')
        tweeny.penup()
        tweeny.goto(0, -200)
        tweeny.pendown()
        tweeny.showturtle()
        tweeny.goto(-160, -25)
        tweeny.lt(40)
        tweeny.flowerhead()
    
    tony = MyTurtle(shape='turtle', visible=False)
    tina = MyTurtle(shape='turtle', visible=False)
    tweeny = MyTurtle(shape='turtle', visible=False)
    
    screen = Screen()
    
    screen.ontimer(flower2, 100)
    screen.ontimer(flower3, 120)
    screen.ontimer(flower5, 100)
    
    screen.mainloop()
    

    RUNNING IMAGE

    enter image description here

    It won't be any faster, as it's just a simulation. (Well, it does go a little faster as I made petal drawing slightly cruder in return for speed.) If you look closely, you can see the turtles are (intentionally) moving at their own individual speed.