Python turtle race: go to a point and turn back - python

Hi I have another question: how do you make a turtle go to a point and turn back? I want the turtles to go to the point with x coordinate 160 and turn back, continuing the race at the same time (meaning that they don't all move at the same speed).
Here is my code:
import turtle
from random import randint
turtle.speed(0)
turtle.penup()
turtle.goto(-140,140)
for step in range(15):
turtle.write(step,align='center')
turtle.right(90)
turtle.forward(10)
turtle.pendown()
turtle.forward(180)
turtle.penup()
turtle.backward(190)
turtle.left(90)
turtle.forward(20)
roy = turtle.Turtle()
roy.color('red')
roy.shape('turtle')
roy.penup()
roy.goto(-160,100)
roy.pendown()
bob = turtle.Turtle()
bob.color('blue')
bob.shape('turtle')
bob.penup()
bob.goto(-160,70)
bob.pendown()
oreo = turtle.Turtle()
oreo.color('orange')
oreo.shape('turtle')
oreo.penup()
oreo.goto(-160,40)
oreo.pendown()
yay = turtle.Turtle()
yay.color('yellow')
yay.shape('turtle')
yay.penup()
yay.goto(-160,10)
yay.pendown()
go = turtle.Turtle()
go.color('green')
go.shape('turtle')
go.penup()
go.goto(-160,-20)
go.pendown()
for turn in range(100):
roy.forward(randint(1,5))
bob.forward(randint(1,5))
oreo.forward(randint(1,5))
yay.forward(randint(1,5))
go.forward(randint(1,5))
if roy.xcor() >= 160:
roy.left(180)
else:
break
if bob.xcor() >= 160:
bob.left(180)
else:
break
if yay.xcor() >= 160:
yay.left(180)
else:
break
if oreo.xcor() >= 160:
oreo.left(180)
else:
break
if go.xcor() >= 160:
go.left(180)
else:
break
I know there's something wrong with my "if" loop in the end, but I don't know what happened.
By the way my turtle turns out like this
Help is appreciated!

Your else break is a problem, it ends the race when the first turtle tries to turn around. Also, left(180) can be problematic if the turtle overshoots the turn point a bit as it will start to spin. Using setheading(180) is safer as it will avoid the spin and send the turtle back towards the starting line:
from turtle import Screen, Turtle
from random import randint, choice
screen = Screen()
turtle = Turtle()
turtle.hideturtle()
turtle.speed('fastest')
turtle.penup()
turtle.goto(-140, 140)
for step in range(15):
turtle.write(step, align='center')
turtle.right(90)
turtle.forward(10)
turtle.pendown()
turtle.forward(180)
turtle.penup()
turtle.backward(190)
turtle.left(90)
turtle.forward(20)
roy = Turtle()
roy.color('red')
roy.shape('turtle')
roy.penup()
roy.goto(-160, 100)
roy.pendown()
bob = Turtle()
bob.color('blue')
bob.shape('turtle')
bob.penup()
bob.goto(-160, 70)
bob.pendown()
oreo = Turtle()
oreo.color('orange')
oreo.shape('turtle')
oreo.penup()
oreo.goto(-160, 40)
oreo.pendown()
yay = Turtle()
yay.color('yellow')
yay.shape('turtle')
yay.penup()
yay.goto(-160, 10)
yay.pendown()
go = Turtle()
go.color('green')
go.shape('turtle')
go.penup()
go.goto(-160, -20)
go.pendown()
while True:
racer = choice([roy, bob, oreo, yay, go])
racer.forward(randint(1, 5))
if racer.xcor() > 160:
racer.setheading(180)
elif racer.xcor() < -160:
break # we have a winner!
screen.mainloop()
Your while True: doesn't really belong in an event-driven environment like turtle and can be replaced with an ontimer() event. But, one step at a time.

Related

I need to figure out a way for my program to tell the user that they win or lose depending on if the turtle is in the circle or not

This code has the turtle make a shape and then gives the user ten moves to go forward, back, right, and left to move the turtle back into the circle. I need to figure out a way for my program to tell the user that they win or lose depending on if the turtle is in the circle or not I am trying to use the xpos and ypos commands to tell where the turtle is but I'm not sure how to use them so that I can make it tell when the turtle is in teh circle or not.
#Importing the package
import turtle
shape = str()
direction = str()
#Change turtle color and background color
turtle.color("green")
turtle.Screen().bgcolor("blue")
screen = turtle.Screen()
#Ask the user what shape they want the turtle to be
shape = turtle.textinput("Enter a shape", "Enter a shape: classic, arrow, turtle, circle, square, or triangle.")
turtle.shape(shape)
#Making a circle
turtle.penup()
turtle.goto(-200, -100)
turtle.pendown()
turtle.fillcolor("red")
turtle.begin_fill()
turtle.circle(100)
turtle.end_fill()
turtle.penup()
turtle.color("green")
#Move turtle back to start
turtle.goto(0, 0)
#Moving the turtle into the circle
for counter in range(1, 11, 1):
#getting the direction from the user
direction = screen.textinput("Direction", "Enter F for Forward, B for Backward, R for Right and L for Left")
if direction == "F":
turtle.forward(100)
elif direction == "B":
turtle.backward(100)
elif direction == "R":
turtle.right(90)
turtle.forward(100)
else:
turtle.left(90)
turtle.forward(100)
#end if
#Find where the turtles ending position is
xpos = turtle.xcor()
ypos = turtle.ycor()
turtle.write("Sorry You Lost", align="center", font=('Arial', '16', 'bold'))
turtle.write("Good Job You Won!", align="center", font=('Arial', '16', 'bold'))
turtle.exitonclick()
from turtle import Screen, Turtle
#Change turtle color and background color
tim = Turtle()
screen = Screen()
tim.color("green")
screen.bgcolor("blue")
#Ask the user what shape they want the turtle to be
shape = screen.textinput("Enter a shape", "Enter a shape: classic, arrow, turtle, circle, square, or triangle: ")
tim.shape(shape)
#Making a circle
tim.penup()
tim.goto(-200, -100)
tim.pendown()
tim.fillcolor("red")
tim.begin_fill()
tim.circle(100)
tim.end_fill()
tim.penup()
tim.color("green")
#Move turtle back to start
tim.goto(0, 0)
#Moving the turtle into the circle
for counter in range(1, 11, 1):
#getting the direction from the user
direction = screen.textinput("Direction", "Enter F for Forward, B for Backward, R for Right and L for Left")
if direction == "F":
tim.forward(100)
elif direction == "B":
tim.backward(100)
elif direction == "R":
tim.right(90)
tim.forward(100)
else:
tim.left(90)
tim.forward(100)
#end if
#Find where the turtles ending position is
xpos = tim.xcor()
ypos = tim.ycor()
print(xpos)
print(ypos)
tim.write("Sorry You Lost", align="center")
tim.write("Good Job You Won!", align="center")
screen.exitonclick()
Here, I fixed your code and I think it is now working what you exactly wanted.

Why won't Python Turtle respond to my movement inputs?

I'm taking a coding course this semester and for one of the projects it requires us to make a game of any kind. I chose to make a game contained within a box where enemies move on screen travel completely across then appear again at a different x or y coordinate to add some variety. The issue I'm dealing with is following adding the code needed to create "enemies" the keys I set for the movement of the player turtle no longer work, another strange thing is that the player turtle will spin in place right as the program is run. I am at a total loss as to how to make the turtle respond to the code as it worked correctly prior to writing the code for the enemies. I don't believe the code for the enemies is the issue as when it is commented out it still acts the same way. I didn't include the enemies code for the sake of brevity. this code is done in Python 3. Please help if you can!
EDIT: I removed the parenthesis following the window.onkeypress(mov_x,"x") and after adding the code back in for the enemies it won"t respond, it works without the code for the enemies but that kinda removes the point of the game. Thank you for the help!
import turtle
import random
#screen
window = turtle.Screen()
window.title("Final Project Game")
window.bgcolor("gray")
window.setup(width=600,height=600)
#player
t= turtle.Turtle()
t.speed(5)
t.shape("triangle")
t.color("blue")
t.penup()
#player movement
def mov_rt():
t.seth(0)
t.fd(20)
def mov_lt():
t.seth(180)
t.fd(20)
def mov_up():
t.seth(90)
t.fd(20)
def mov_dw():
t.seth(270)
t.fd(20)
window.onkeypress(mov_rt,"d")
window.onkeypress(mov_lt,"a")
window.onkeypress(mov_up,"w")
window.onkeypress(mov_dw,"s")
window.listen()
#enemies
enemies = []
turt_num = turtle.numinput("Final","Number of Enemies", default=5, minval=1,maxval=10)
e_dir= [0,90,180,270]
if turt_num == 1:
e1= turtle.Turtle("square",visible=False)
e1.speed(5)
e1.color("red")
e1.penup()
e1.setpos(random.randint(-290,290),random.randint(-290,290))
e1.seth(random.choice(e_dir))
enemies.append(e1)
e1.st()
elif turt_num == 2:
e1= turtle.Turtle("square",visible=False)
e1.speed(5)
e1.color("red")
e1.penup()
e1.setpos(random.randint(-290,290),random.randint(-290,290))
e1.seth(random.choice(e_dir))
enemies.append(e1)
e2= turtle.Turtle("square",visible=False)
e2.speed(5)
e2.color("red")
e2.penup()
e2.setpos(random.randint(-290,290),random.randint(-290,290))
e2.seth(random.choice(e_dir))
enemies.append(e2)
e1.st()
e2.st()
elif turt_num ==3:
e1= turtle.Turtle("square",visible=False)
e1.speed(5)
e1.color("red")
e1.penup()
e1.setpos(random.randint(-290,290),random.randint(-290,290))
e1.seth(random.choice(e_dir))
enemies.append(e1)
e2= turtle.Turtle("square",visible=False)
e2.speed(5)
e2.color("red")
e2.penup()
e2.setpos(random.randint(-290,290),random.randint(-290,290))
e2.seth(random.choice(e_dir))
enemies.append(e2)
e3= turtle.Turtle("square",visible=False)
e3.speed(5)
e3.color("red")
e3.penup()
e3.setpos(random.randint(-290,290),random.randint(-290,290))
e3.seth(random.choice(e_dir))
enemies.append(e3)
e1.st()
e2.st()
e3.st()
#borders
def border(): #if you hold down the button it wont reappear bc youre still moving while the turtle is trying to move to the desired target
tx, ty= t.pos()
if t.xcor() >295:
t.ht()
t.setpos(-295,ty)
t.st()
if t.xcor() <-295:
t.ht()
t.setpos(295,ty)
t.st()
if t.ycor() >295:
t.ht()
t.setpos(tx,-295)
t.st()
if t.ycor() <-295:
t.ht()
t.setpos(tx,295)
t.st()
#main game loop
while True:
window.update()
border()
turtle.mainloop()
Try to use
window.onkey()
That is a different way to listen and it does the exact same thing.
Also, remember at the end of that code you need
window.listen()
Common beginner's error. Instead of:
window.onkeypress(mov_rt(),"d")
window.onkeypress(mov_lt(),"a")
window.onkeypress(mov_up(),"w")
window.onkeypress(mov_dw(),"s")
Do:
window.onkeypress(mov_rt, "d")
window.onkeypress(mov_lt, "a")
window.onkeypress(mov_up, "w")
window.onkeypress(mov_dw, "s")
That is, you don't want to call your event handler function, you instead want to pass the name of your event hanlder function for the system to call later, when something actually happens.
Below is a rework of your code to address this as well as some other turtle and Python issues:
from turtle import Screen, Turtle
def border():
x, y = turtle.position()
if x > 295:
turtle.hideturtle()
turtle.setx(-295)
turtle.showturtle()
elif x < -295:
turtle.hideturtle()
turtle.setx(295)
turtle.showturtle()
if y > 295:
turtle.hideturtle()
turtle.sety(-295)
turtle.showturtle()
elif y < -295:
turtle.hideturtle()
turtle.sety(295)
turtle.showturtle()
# player movement
def mov_rt():
turtle.setheading(0)
turtle.forward(20)
border()
def mov_lt():
turtle.setheading(180)
turtle.forward(20)
border()
def mov_up():
turtle.setheading(90)
turtle.forward(20)
border()
def mov_dw():
turtle.setheading(270)
turtle.forward(20)
border()
screen = Screen()
screen.title("Final Project Game")
screen.bgcolor('gray')
screen.setup(width=600, height=600)
# player
turtle = Turtle()
turtle.speed('normal')
turtle.shape('triangle')
turtle.color('blue')
turtle.penup()
screen.onkeypress(mov_rt, 'd')
screen.onkeypress(mov_lt, 'a')
screen.onkeypress(mov_up, 'w')
screen.onkeypress(mov_dw, 's')
screen.listen()
screen.mainloop()
Note removal of while True: loop as it has no place in an event-driven environment like turtle -- it potentially blocks events from being processed.

Draw then erase square

I'm trying to draw a square using python graphics then erase it after 3 seconds. I have the code below:
import threading as th
import turtle
import random
thread_count = 0
def draw_square():
turtle.goto(random.randint(-200,200), random.randint(-200,200))
for i in range(4):
turtle.forward(100)
turtle.left(90)
def erase_square(x,y):
turtle.pencolor('white')
turtle.fillcolor('white')
turtle.goto(x,y)
turtle.begin_fill()
for i in range(4):
turtle.forward(target_size)
turtle.left(90)
turtle.end_fill()
def square_timer():
global thread_count
if thread_count <= 10:
print("Thread count", thread_count)
draw_square()
T = th.Timer(3, square_timer)
T.start()
The square_update() function will draw 10 squares then stop. I'm trying to make it draw one square then clear it using the erase_square() by painting white over it, then another and repeat the process and stop when it reaches 10. I can't figure how to make the erase function go to the random location of the drawn square and 'erase' it. How can I make it draw and erase the square?
The most straightforward way to clear a drawing is with the clear() method rather than trying to draw white over the image:
from turtle import Screen, Turtle
from random import randint
def draw_square():
turtle.goto(randint(-200, 200), randint(-200, 200))
turtle.pendown()
for _ in range(4):
turtle.forward(100)
turtle.left(90)
turtle.penup()
def erase_square():
turtle.clear()
screen.ontimer(square_update) # no time, ASAP
def square_update():
draw_square()
screen.ontimer(erase_square, 3000) # 3 seconds in milliseconds
screen = Screen()
turtle = Turtle()
turtle.hideturtle()
turtle.speed('fastest')
turtle.penup()
square_update()
screen.exitonclick()
You can use the undo() method as #JonathanDrukker suggests, but you have to undo each step. Even for a simple shape like a square, this takes a little thought, but with a complex shape, this is difficult. The number of operations added to the undo buffer don't always match the calls that you make to turtle. But we can get that count from turtle itself, as long as we don't do any other turtle actions between drawing and erasing:
def draw_square():
turtle.goto(randint(-200, 200), randint(-200, 200))
count = turtle.undobufferentries()
turtle.pendown()
for _ in range(4):
turtle.forward(100)
turtle.left(90)
turtle.penup()
return turtle.undobufferentries() - count
def erase_square(undo_count):
for _ in range(undo_count):
turtle.undo()
screen.ontimer(square_update)
def square_update():
undo_count = draw_square()
screen.ontimer(lambda: erase_square(undo_count), 3000)
But what I'd do is make the turtle itself the square and then just move it rather than erase and (re)draw the square:
from turtle import Screen, Turtle
from random import randint
CURSOR_SIZE = 20
def draw_square():
turtle.goto(randint(-200, 200), randint(-200, 200))
def square_update():
turtle.hideturtle()
draw_square()
turtle.showturtle()
screen.ontimer(square_update, 3000)
screen = Screen()
turtle = Turtle()
turtle.hideturtle()
turtle.shape('square')
turtle.shapesize(100 / CURSOR_SIZE)
turtle.fillcolor('white')
turtle.penup()
square_update()
screen.exitonclick()

How to reset the turtles and erase the text in turtle graphics?

I made this turtle game
import turtle
import random
import time
from turtle import Turtle
# Window
window = turtle.Screen()
window.title("Turtle Race")
window.bgcolor("forestgreen")
turtle.color("white")
turtle.speed(0)
turtle.penup()
turtle.setposition(-140, 200)
turtle.write("Turtle Race", font=("Arial", 40, "bold"))
# Dirt
turtle.setposition(-400, -180)
turtle.color("chocolate")
turtle.begin_fill()
turtle.pendown()
turtle.forward(800)
turtle.right(90)
turtle.forward(300)
turtle.right(90)
turtle.forward(800)
turtle.right(90)
turtle.forward(300)
turtle.end_fill()
# Finish line
stamp_size = 20
square_size = 15
finish_line = 200
turtle.color("black")
turtle.shape("square")
turtle.shapesize(square_size / stamp_size)
turtle.penup()
for i in range(10):
turtle.setposition(finish_line, (150 - (i * square_size * 2)))
turtle.stamp()
for j in range(10):
turtle.setposition(finish_line + square_size, ((150 - square_size) - (j * square_size * 2)))
turtle.stamp()
turtle.hideturtle()
def play():
# Turtle 1
turtle1 = Turtle()
turtle1.speed(0)
turtle1.color("black")
turtle1.shape("turtle")
turtle1.penup()
turtle1.goto(-250, 100)
turtle1.pendown()
# Turtle 2
turtle2 = Turtle()
turtle2.speed(0)
turtle2.color("cyan")
turtle2.shape("turtle")
turtle2.penup()
turtle2.goto(-250, 50)
turtle2.pendown()
# Turtle 3
turtle3 = Turtle()
turtle3.speed(0)
turtle3.color("magenta")
turtle3.shape("turtle")
turtle3.penup()
turtle3.goto(-250, 0)
turtle3.pendown()
# Turtle 4
turtle4 = Turtle()
turtle4.speed(0)
turtle4.color("yellow")
turtle4.shape("turtle")
turtle4.penup()
turtle4.goto(-250, -50)
turtle4.pendown()
time.sleep(1) # pausing the game for 1 sec before game starts
# Asking user to play
print("Please choose one colour out of \nBlack \nCyan \nMagenta \nYellow ")
user_bet = input("Place your bet on your any one colour turtle: ").upper()
while not(user_bet == "BLACK" or user_bet == "CYAN" or user_bet == "MAGENTA" or user_bet == "YELLOW"):
print("Please choose one colour out of \nBlack \nCyan \nMagenta \nYellow ")
user_bet = input("Place your bet on your any one colour turtle: ").upper()
# Initial distance covered by turtles
tut1_len = 0
tut2_len = 0
tut3_len = 0
tut4_len = 0
# Moving the turtles
for _i in range(145):
tut1 = random.randint(1, 5)
tut2 = random.randint(1, 5)
tut3 = random.randint(1, 5)
tut4 = random.randint(1, 5)
turtle1.forward(tut1)
tut1_len += tut1
turtle2.forward(tut2)
tut2_len += tut2
turtle3.forward(tut3)
tut3_len += tut3
turtle4.forward(tut4)
tut4_len += tut4
# Deciding the winner
result_dic = {"black": tut1_len, "cyan": tut2_len, "magneta": tut3_len, "yellow": tut4_len}
winner = max(result_dic, key=lambda x: result_dic[x]).upper()
turtle.penup()
turtle.color("blue")
if user_bet == winner:
turtle.goto(-140, 50)
turtle.write("You won the bet", font=("Arial", 30, "bold"))
else:
turtle.goto(-140, 50)
turtle.write("You lost the bet", font=("Arial", 30, "bold"))
turtle.pendown()
play()
choice = input("Do you want to play again?\n Press y for yes and n for no: ").upper()
while choice == "y".upper() or choice == "yes".upper():
play()
else:
quit()
The game works and i wanted the game to ask user to play again and it does that but every time the game reruns the turtles run over previous turtle the the text which display ** You won the bet** or ** You lost the bet** is also written over previous another one.
I din't find any method to clear text written in screen nor to erase the turtles lines.
Please help me.
And it would me really helpful if you guys give me suggestion on how to improve this code like how to make it more short and i am little confused about my own logic on line 106 about that or operator but this is secondary please help me on my primary problem first.
My recommendation in a situation like this, where text is being updated on the screen, is that you have a turtle dedicated just to writing that text. Put that turtle into position before the action starts and then just use clear() and write() on that turtle from then on. Don't use it for anything else.
it would me really helpful if you guys give me suggestion on how to
improve this code
One key thing with a program like this is to not assume how many racers there will be, and write your code accordingly. You should be able to adjust the number up or down slightly (or just change your color choices) without having to do a major rewrite.
I've reworked your code to address both of the above issues:
from turtle import Screen, Turtle
from random import randint
STAMP_SIZE = 20
SQUARE_SIZE = 15
FINISH_LINE = 200
LANE_WIDTH = 50
BIG_FONT = ('Arial', 40, 'bold')
MEDIUM_FONT = ('Arial', 30, 'bold')
COLORS = ['black', 'cyan', 'magenta', 'yellow', 'white']
def play():
pen.clear()
lane = LANE_WIDTH
for n, color in enumerate(COLORS, start=1):
turtle = turtles[color]
turtle.hideturtle()
turtle.goto(-250, n // 2 * lane)
turtle.showturtle()
lane = -lane
# Asking user to play
user_bet = None
while user_bet not in COLORS:
print("Please choose one colour out of", *["\n" + color.title() for color in COLORS])
user_bet = input("Place your bet on your any one colour turtle: ").lower()
# Moving the turtles
for _ in range(145):
for turtle in turtles.values():
distance = randint(1, 5)
turtle.forward(distance)
# Deciding the winner
winner = max(turtles, key=lambda x: turtles[x].xcor())
pen.clear()
if user_bet == winner:
pen.write("You won the bet!", align='center', font=MEDIUM_FONT)
else:
pen.write("You lost the bet.", align='center', font=MEDIUM_FONT)
# Screen
screen = Screen()
screen.title("Turtle Race")
screen.bgcolor('forestgreen')
turtle = Turtle()
turtle.hideturtle()
turtle.speed('fastest')
turtle.penup()
# Dirt
turtle.setposition(-400, -180)
turtle.color('chocolate')
turtle.begin_fill()
for _ in range(2):
turtle.forward(800)
turtle.right(90)
turtle.forward(300)
turtle.right(90)
turtle.end_fill()
# Finish line
turtle.color('black')
turtle.shape('square')
turtle.shapesize(SQUARE_SIZE / STAMP_SIZE)
for i in range(10):
turtle.setposition(FINISH_LINE, 150 - i * SQUARE_SIZE*2)
turtle.stamp()
turtle.setposition(FINISH_LINE + SQUARE_SIZE, (150 - SQUARE_SIZE) - i * SQUARE_SIZE*2)
turtle.stamp()
turtle.setposition(0, 200)
turtle.write("Turtle Race", align='center', font=BIG_FONT)
pen = Turtle()
pen.hideturtle()
pen.color('blue')
pen.penup()
pen.setposition(0, 50)
turtle_prototype = Turtle()
turtle_prototype.hideturtle()
turtle_prototype.shape('turtle')
turtle_prototype.speed('fastest')
turtle_prototype.penup()
turtles = {}
for color in COLORS:
turtle = turtle_prototype.clone()
turtle.color(color)
turtles[color] = turtle
choice = 'yes'
while choice.lower() in ('y', 'yes'):
play()
choice = input("Do you want to play again?\nPress y for yes and n for no: ")

2 player race using Python turtles

I have tried to create a basic 2 player race using turtles in Python 3. I used an example game with a similar code to what I wanted to produce which I found on this site.
Does anyone know of a method to listen for button clicks while running an if statement to check if a variable has changed in value?
This is my code:
import turtle
window = turtle.Screen()
window.bgcolor('lightblue')
window.title('wacky racers')
turtle.speed(100)
turtle.penup()
turtle.goto(-140, 140)
# creates racetrack
for step in range(15):
turtle.write(step, align='center')
turtle.right(90)
for num in range(8):
turtle.penup()
turtle.forward(10)
turtle.pendown()
turtle.forward(10)
turtle.penup()
turtle.backward(160)
turtle.left(90)
turtle.forward(20)
# Creates player 1
player1 = turtle.Turtle()
player1.color('red')
player1.shape('turtle')
player1.penup()
player1.goto(-160, 100)
player1.pendown()
# creates player 2
player2 = turtle.Turtle()
player2.color('blue')
player2.shape('turtle')
player2.penup()
player2.goto(-160, 0)
player2.pendown()
# button functions
def k1():
player1.forward(10)
def k2():
player2.forward(10)
def k3():
window.bye()
#########
turtle.listen()
turtle.onkey(k1, "Left")
turtle.onkey(k2, "Right")
turtle.onkey(k3, 'q')
while True:
if player1.xcor() > 100:
print("player 1 wins")
window.bye()
if player2.xcor() > 100:
print("player 2 wins")
window.bye()
This code makes the game crash on screen setup. however, if I remove the while loop, the game runs but does not end after either player1 or player 2 passes x position 100.

Categories