How to move multiple turtles in a for loop?

Viewed 1096

So, I am a recent beginner to python and for my class I am being tasked with making a turtle race with 10 turtles that all move and should stop at the finish line. I was given directions to make a list for the turtles and have a while loop to make them move a random amount and a nested if loop to check for the winner. I am having trouble making all the turtles move at once, when I run my code, it moves the turtles one by one instead of all together, any ideas?

import turtle as trtl
import random as rand
zoomers = []
zom = [0,1,2,3,4,5,6,7,8,9]
tloc = -130
trtl.penup()
trtl.goto(-150, 150)
trtl.pendown()
trtl.goto(-150,-140)
trtl.penup()
trtl.goto(180,150)
trtl.pendown()
trtl.goto(180,-140)
trtl.hideturtle()
for z in zom:
  zoom = trtl.Turtle("turtle")
  zoom.penup()
  zoom.goto(-150,-tloc)
  tloc += 25
  robux = rand.randrange(0,20)
  zoomers.append(zoom)
  for n in zoomers:
    cash = 0
    while cash < 100:
      zoom.forward(robux)
      cash = cash + 1
    if zoom.xcor() == 180:
      print("We have a winner!")
      break```
5 Answers

There isn't a direct way to do that, but here is the next best thing.

Create a turtle Screen. Set its tracer() to 0, and update the screen in each iteration of the loop. It can get too fast, so import sleep from the time module to slow things down a little.

Minimal example:

from turtle import Turtle, Screen
from random import randrange
from time import sleep

wn = Screen()
wn.tracer(0)

t1 = Turtle('turtle')
t2 = Turtle('turtle')

t1.penup()
t2.penup()

t1.goto(-100, 50)
t2.goto(-100, -50)

while True:
    sleep(0.1)
    t1.forward(randrange(0, 20))
    t2.forward(randrange(0, 20))
    wn.update()

All the other solutions so far move the turtles a random distance in a fixed time slice. Let's turn that around and move the turtles a constant distance in a random time slice:

from turtle import Turtle, Screen
from random import randrange

def run(turtle):
    turtle.forward(5)

    if turtle.xcor() < half_width:
        screen.ontimer(lambda: run(turtle), randrange(20, 150))

screen = Screen()

half_width = screen.window_width() / 2
lane_width = 20

for order, color in enumerate(['red', 'green', 'blue']):
    turtle = Turtle('turtle')
    turtle.speed('fastest')
    turtle.color(color)
    turtle.penup()

    turtle.goto(-half_width, (order | 1) * lane_width)
    lane_width *= -1
    run(turtle)

screen.exitonclick()

We can model this without even using the turtle library:

import random

twerbles = list(zip(range(10), [0]*10)) #list of turtles all starting at position 0 (numbered 0-10)
finishline = 10 #the threshold they must pass

while True:
    twerbles = [(twerble, position+random.randint(1,2)) for twerble, position in twerbles] #move each turtle up a random amount.

    print(twerbles) #this can be removed if you dont want to see their positions as they go

    winners = [twerble for twerble, position in twerbles if position >= finishline] #list of turtles that passed the threshold (if any)
    if winners: print(winners); break #if there are winners print them and stop looping
[(0, 1), (1, 2), (2, 1), (3, 2), (4, 1), (5, 2), (6, 1), (7, 1), (8, 1), (9, 2)]
[(0, 2), (1, 3), (2, 2), (3, 3), (4, 2), (5, 4), (6, 3), (7, 3), (8, 3), (9, 3)]
[(0, 4), (1, 5), (2, 4), (3, 4), (4, 4), (5, 6), (6, 5), (7, 5), (8, 4), (9, 5)]
[(0, 5), (1, 7), (2, 6), (3, 5), (4, 6), (5, 8), (6, 6), (7, 7), (8, 5), (9, 6)]
[(0, 6), (1, 8), (2, 8), (3, 6), (4, 7), (5, 9), (6, 7), (7, 9), (8, 7), (9, 7)]
[(0, 8), (1, 9), (2, 10), (3, 7), (4, 9), (5, 11), (6, 8), (7, 11), (8, 8), (9, 9)]

[2, 5, 7] #winning turtles

moving w/ turtles

import turtle as trtl
import random

finishline = 30

twerbles = [(trtl.Turtle("turtle"), 0) for i in range(10)]

for i,(twerble,position) in enumerate(twerbles):
  twerble.penup()
  twerble.goto(-150,150 - i*25)

while True:
    twerbles = [(twerble, position+random.randint(1,2)) for twerble, position in twerbles]

    for twerble, position in twerbles:
        twerble.forward(position)

    winners = [twerble for twerble, position in twerbles if position >= finishline]
    if winners:
        break

You are using a single turtle. You can easily do this by creating multiple turtle objects. I have used 3 turtle objects and they have a small race.

Try this code and you can implement your winner logic in this code.

import turtle as trtl
import random as rand

zoom1 = trtl.Turtle()
zoom2 = trtl.Turtle()
zoom3 = trtl.Turtle()

zoomers = [zoom1, zoom2, zoom3]

for zoom in zoomers:
  zoom.penup()

zoom1.goto(-150, 150)
zoom2.goto(-120, 150)
zoom3.goto(-90, 150)

for zoom in zoomers:
  zoom.pendown()
  zoom.right(90)

for zoom in zoomers:
  robux = rand.randrange(10,50)
  zoom.forward(robux)

Edit: You need non-blocking code to implement turtles moving simultaneously and independently of each other. You can do that by using multi-threading. Try this.

You need to create a collection of turtles. Loop movement (a single step) for each turtle until a turtle finishes.

Try this code:

import turtle as trtl
import random as rand
zoomers = []
zom = [0,1,2,3,4,5,6,7,8,9]
tloc = -130
trtl.penup()
trtl.goto(-150, 150)
trtl.pendown()
trtl.goto(-150,-140)
trtl.penup()
trtl.goto(180,150)
trtl.pendown()
trtl.goto(180,-140)
trtl.hideturtle()

zoomers = [trtl.Turtle("turtle") for z in zom]

for i,t in enumerate(zoomers):
  t.penup()
  t.goto(-150,150 - i*25)


for i,z in enumerate(zom):
  zoom = zoomers[i]   #trtl.Turtle("turtle")
  tloc += 25
#  zoomers.append(zoom)

running = True
while running:
    for zoom in zoomers:
      robux = rand.randrange(0,20)
      zoom.forward(robux)
      if zoom.xcor() >= 180:
        print("We have a winner!")
        running = False
        break

input('Press enter to exit...')
Related