Есть ли способ добавить счетчик под моим кодом светофора?

#python #python-3.x #turtle-graphics

#python #python-3.x #черепаха-графика

Вопрос:

Этот код отображает светофор на turtle.screen(). Я пытаюсь добавить таймер обратного отсчета в свой код, который должен отображаться на экране черепахи под светофором, а не на терминале python.

 import turtle
import time
wn = turtle.Screen()
wn.title("traffic lights")
wn.bgcolor("black")
#box
pen = turtle.Turtle()
pen.color("yellow")
pen.width(3)
pen.hideturtle()
pen.penup()
pen.goto(-30, 60)
pen.pendown()
pen.fd(60)
pen.rt(90)
pen.fd(120)
pen.rt(90)
pen.fd(60)
pen.rt(90)
pen.fd(120)

#red
red_light = turtle.Turtle()
red_light.shape("circle")
red_light.color("grey")
red_light.penup()
red_light.goto(0,40)

#yellow
yellow_light= turtle.Turtle()
yellow_light.shape("circle")
yellow_light.color("grey")
yellow_light.penup()
yellow_light.goto(0,0)

#green
green_light= turtle.Turtle()
green_light.shape("circle")
green_light.color("grey")
green_light.penup()
green_light.goto(0,-40)

while True:
    yellow_light.color("grey")
    red_light.color("red")
    time.sleep(4)

    red_light.color("grey")
    green_light.color("green")
    time.sleep(3)

    green_light.color("grey")
    yellow_light.color("yellow")
    time.sleep(2)
  

Куда я могу добавить код счетчика, чтобы его можно было отобразить на экране черепахи

Ответ №1:

Одна из трудностей при добавлении такой функции заключается в том, что эта программа собрана неправильно. В мире, управляемом событиями, таком как turtle, следует избегать таких вещей, как while True: и time.sleep(4) . Вместо этого рассмотрите собственный ontimer() метод turtle, который выполняет лучшую работу и хорошо воспроизводит события.

Первое, что нужно сделать, это исправить ваш код для использования конечного автомата и ontimer() для изменения огней:

 def state_machine():
    if red_light.pencolor() == 'red':
        red_light.color('grey')
        green_light.color('green')
        screen.ontimer(state_machine, 3000)

    elif green_light.pencolor() == 'green':
        green_light.color('grey')
        yellow_light.color('yellow')
        screen.ontimer(state_machine, 2000)

    elif yellow_light.pencolor() == 'yellow':
        yellow_light.color('grey')
        red_light.color('red')
        screen.ontimer(state_machine, 4000)
  

Чтобы это сработало, один из индикаторов должен сначала гореть, а не быть серым. Как только это заработает, мы также можем добавить таймер обратного отсчета:

 def countdown(seconds):
    count.clear()
    count.write(seconds, align='center', font=FONT)

    seconds -= 1

    if seconds > 0:
        screen.ontimer(lambda s=seconds: countdown(s), 1000)
  

И собрать все это вместе:

 from turtle import Screen, Turtle

FONT = ('Arial', 18, 'normal')

screen = Screen()
screen.title("Traffic Lights")
screen.bgcolor('black')

# box
pen = Turtle(visible=False)
pen.color('yellow')
pen.width(3)
pen.penup()
pen.goto(-30, 60)
pen.pendown()

for _ in range(2):
    pen.fd(60)
    pen.rt(90)
    pen.fd(120)
    pen.rt(90)

# count down timer
count = Turtle(visible=False)
count.color('white')
count.penup()
count.sety(-100)

# red light
red_light = Turtle('circle')
red_light.color('grey')
red_light.penup()
red_light.sety(40)

# yellow light
yellow_light = Turtle('circle')
yellow_light.color('yellow')  # initially on
yellow_light.penup()

# green light
green_light = Turtle('circle')
green_light.color('grey')
green_light.penup()
green_light.sety(-40)

def countdown(seconds):
    count.clear()
    count.write(seconds, align='center', font=FONT)

    seconds -= 1

    if seconds > 0:
        screen.ontimer(lambda s=seconds: countdown(s), 1000)

def state_machine():
    if red_light.pencolor() == 'red':
        red_light.color('grey')
        green_light.color('green')
        countdown(3)
        screen.ontimer(state_machine, 3000)

    elif green_light.pencolor() == 'green':
        green_light.color('grey')
        yellow_light.color('yellow')
        countdown(2)
        screen.ontimer(state_machine, 2000)

    elif yellow_light.pencolor() == 'yellow':
        yellow_light.color('grey')
        red_light.color('red')
        countdown(4)
        screen.ontimer(state_machine, 4000)

state_machine()

screen.exitonclick()
  

Еще одним преимуществом этого подхода является то, что при выходе из исходного кода вы обычно получаете десять строк сообщений об ошибках, поскольку закрытие окна не синхронизировано с вашими sleep() вызовами. В исправленном коде выше закрытие окна завершается чисто, без сообщений об ошибках, поскольку все синхронизировано.