How do I make Turtle to wait for a pressed key

Question:

My group and I created a board game that runs on Turtle. We are having difficulties to make the game run without the need for the IDE console.
We want to use onkeypress to run our game so the user will not have to leave the game window.

#import turtle
from turtle import *
from random import *
from time import *

#drawing board game
def boardgame(size):    
    """Draw a square by drawing a line and turning through 90 degrees 4 times"""
    pendown()
    color("black", "blue")
    begin_fill()
    for _ in range(4):
        forward(size)
        right(90)
    end_fill()
    penup() 

#numbering each tile
def number():
    """Draw the tile number for each tile"""
    # I tried to compress this part of the code, but a lot of bugs occured, so I decided to kep the big lines because it is way more simple
    goto(-300, 80)
    x = 0
    x += 1
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)
    goto(-300, -70)
    x += 5
    write(x)
    forward(square_size)
    x -= 1
    write(x)
    forward(square_size)
    x -= 1
    write(x)
    forward(square_size)
    x -= 1
    write(x)
    forward(square_size)
    x -= 1
    write(x)
    forward(square_size)
    goto(-300, -220)
    x += 5
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)
    x += 1
    write(x)
    forward(square_size)

#assingning tile order

def order(cmd):
    """Whites the order of the tile at the canter of the tile"""
    write(cmd,align="center", font=("Arial", 24, "normal"))

#drawing dice number
def dice_draw(number):
    """Write the dice number"""
    undo()
    goto(450,75)
    N = randint(1,4)
    sleep(1)
    write(N,align="center", font=("Arial", 40, "normal"))
    sleep(0.2)
    undo()
    write(N+2,align="center", font=("Arial", 40, "normal"))
    sleep(0.2)
    undo()
    write(number,align="center", font=("Arial", 40, "normal"))
    sleep(1)


#starting the interface
square_size = 150
penup()
hideturtle()
speed(0)

#writing title
def title():
    sleep(1)
    goto(0, 260)
    write("Turtle Racer",align="center", font=("Comic Sans MS", 80, "normal"))
    sleep(1)

#starting block
def start_box():
    penup()
    goto(-450,225)
    pendown()
    color("black", "green")
    begin_fill()
    forward(75)
    right(90)
    forward(150)
    right(90)
    forward(75)
    right(90)
    forward(150)
    right(90)
    end_fill()
    penup()

#drawing board
def board():

    goto(-375, 225)

    for i in range(5): 
        boardgame(square_size)

        forward(square_size)
    goto(-375,75)
    for i in range(5): 
        boardgame(square_size)

        forward(square_size)
    goto(-375, -75)
    for i in range(5): 
        boardgame(square_size)

        forward(square_size) 


#ending block
def end_box():
    penup()
    goto(375,-75)
    pendown()
    color("black", "red")
    begin_fill()
    forward(75)
    right(90)
    forward(150)
    right(90)
    forward(75)
    right(90)
    forward(150)
    right(90)
    end_fill()
    penup()

#drawing numbers
def draw_number():
    goto(-375, 225)
    number()
    goto(0, 130)
    order('-2')
    goto(300, 130)
    order('+1') 
    goto(0, -20)
    order('+2') 
    goto(-150, -170)
    order('-3')
    goto(300, -170)
    order('-14')
    order('-14')

#draw dice box
def dice_box():
    penup()
    goto(415, 140)
    pendown()
    for _ in range(4):
        forward(70)
        right(90)
    penup()
    goto(450,150)
    pendown()
    write("DICE",align="center", font=("Comic Sans MS", 20, "normal"))
    penup()

#winner message
#def win():

title()
start_box()
board()
end_box()
dice_box()
draw_number()

#end of fernando's code//////////////////////////////////////////////////////////////////////////////

#get the turtles ready to be played
player_one_turtle = Turtle()
player_one_turtle.color('cyan')
player_one_turtle.shape('turtle')
player_one_turtle.penup()
player_one_turtle.goto(-400, 112)

player_two_turtle = Turtle()
player_two_turtle.color('orange')
player_two_turtle.shape('turtle')
player_two_turtle.penup()
player_two_turtle.goto(-400, 188)
#an array for for the player positions that will move to each spot
#currently set for testing purposes
player_one_positions = [(-400, 112),(-300, 112),(-150, 112),(0, 112),(150, 112),(300, 112),(300, 30),(150, 30),(0, 30), (-150, 30), (-300, 30), (-300, -112), (-150, -112), (0, -112), (150, -112), (300, -112), (400, -112)] #on screen board positions
player_two_positions = [(-400, 188),(-300, 188),(-150, 188),(0, 188),(150, 188),(300, 188),(300, -38),(150, -38),(0, -38), (-150, -38), (-300, -38), (-300, -188), (-150, -188), (0, -188), (150, -188), (300, -188), (400, -188)] #on screen board positions
player_one_spot = 0;#which spot the player is on 
player_two_spot = 0;
board_size = 15#number of tiles on the board
dice_val = 0;#define to be used to temporarily store the value of the dice
winner = '';#set when there is a winner, also used to return the player's name 
hot_spot = {3: 1, 5: 6, 8: 10, 12: 9, 15: 1}#takes the board positions and moves them if landed on a specific square

#function returns a number between 1-6
def diceroll():
    number = randint(1, 6)
    return number


#start the game
while (winner == ''): #if the spot is greater than the board, that player has one
    #ask player one to roll
    print("player one value:" + str(player_one_spot))
    print("player two value:" + str(player_two_spot))
    input("Press enter to roll the dice: ")
    dice_val = diceroll()
    dice_draw(dice_val)
    player_one_spot = dice_val + player_one_spot#roll the dice for the player
    print("You roled: " + str(dice_val))
    if player_one_spot > board_size:
        winner = 'player one'
        #move turtle to the end of the board
        player_one_turtle.goto(400, -112)
        break #game is over
    #go to the new spot
    player_one_turtle.goto(player_one_positions[player_one_spot])
    #//move turtle to the new spot if on spot
    if player_one_spot in hot_spot: 
        for i in hot_spot: 
            if player_one_spot == i:
                player_one_spot = hot_spot[i]
                player_one_turtle.goto(player_one_positions[player_one_spot])
    #roll for the second plasyer
    dice_val = diceroll()
    dice_draw(dice_val)
    player_two_spot = dice_val + player_two_spot  #roll the dice for the computer
    print("The computer roled: " + str(dice_val))
    if player_two_spot > board_size:
        winner = 'player two'
        #//move turtle to the end 
        player_two_turtle.goto(400, -188)
        break  
    #go to the new spot
    player_two_turtle.goto(player_two_positions[player_two_spot])
    if player_two_spot in hot_spot: 
        for i in hot_spot: 
            if player_two_spot == i:
                player_two_spot = hot_spot[i]   
                player_two_turtle.goto(player_two_positions[player_two_spot])

print("player one value:" + str(player_one_spot))
print("player two value:" + str(player_two_spot))
if player_one_spot > player_two_spot:
    print('player one wins!')
else: 
    print('player two wins!')
exitonclick()

The problem is in the while loop requiring input to run the code.

input("Press enter to roll the dice: ")

we are having difficulties on finding a replacement for input.

Answers:

It’ not a perfect fit but you can use the textinput() function in Python3 turtle to implement this. A minimalist example:

from turtle import Screen

screen = Screen()

while True:
    answer = screen.textinput("Next Game", "Press OK to roll the dice, Cancel to quit:")

    if answer is None:
        break
Answered By: cdlane

You can listen for the enter keypress event (known as "Return" to Tk):

import turtle
from datetime import datetime


def tick():
    current_time = datetime.now().strftime("%H:%M:%S")
    turtle.clear()
    turtle.goto(0, 50)
    turtle.write(current_time, align="center", font=font)
    turtle.goto(0, -50)
    msg = f"Enter pressed {enter_presses} times"
    turtle.write(msg, align="center", font=font)
    turtle.update()
    turtle.Screen().ontimer(tick, 1000 // 30)


def handle_enter_press():
    global enter_presses
    global enter_pressed

    if enter_pressed:
        return

    enter_pressed = True
    enter_presses += 1
    # run code that should occur after an enter press


def handle_enter_release():
    global enter_pressed
    enter_pressed = False
    # run code that should occur after an enter release


enter_presses = 0
enter_pressed = False  # prevent retriggers when key is held
font = "Courier New", 18, "normal"
turtle.tracer(0)
turtle.penup()
turtle.hideturtle()
turtle.Screen().onkeypress(handle_enter_press, "Return")
turtle.Screen().onkeyrelease(handle_enter_release, "Return")
turtle.listen()
tick()
turtle.exitonclick()

This uses an event-driven approach, so your design will need to be adjusted to run logic from a handler function rather than blocking execution of your main thread until the next line runs in-line. The advantage is that it works entirely within the GUI window, so the UX should be significantly improved over a textinput dialog.

I’ve also added a release handler which adds a bit of complexity. If you remove that, the user can spam the key handler by holding it down. You can still use a boolean to ensure they only trigger it once without the onkeyrelease.

Answered By: ggorlen