← Teacher guide

Optional: Control panel

An optional lesson in the user interface direction. Students turn the game into an app with rows of buttons built from lists, so adding a control means adding to a list.

Python functions and events · Final challenge: Catch the turtle · about 45 minutes · Open the student lesson

Classroom resources

Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.

Students will be able to

Timing

Predict, Run and Investigate 15 min · Difficulty row 15 min · Your own controls 15 min

Before class

The big idea: buttons are data. Three lists (the names, the positions, the values) and two loops (one draws the buttons, one checks which was clicked) replace a pile of copied if statements. "New game" waits 1.1 seconds before starting: that lets any timer still running from the last game stop first, so two games never run at once.

Running the lesson

  1. Predict: the Pause button covers x from -60 to 60, so a click at x = 0 presses Pause.
  2. Investigate: follow the loop for a click at x = 100. Only the third button matches.
  3. Ask: what goes wrong if names has four items but bxs has three? (The loop asks for a position that does not exist.)
  4. Modify: the difficulty row is the same pattern again: three lists, a drawing loop and a checking loop.
  5. Make: students design a row of their own. A colour theme with bgcolor is a good first choice.

The hard part (on purpose)

Controls stored as lists that must stay the same length. Ask them to count each list's items when an IndexError appears.

When students get stuck

What you will seeA question to askThe fix
An IndexError when clicking or drawing.Do all the lists that go together have the same number of items?Lists used side by side (names and bxs) must be the same length.
Two rows of buttons overlap.What y value does each row use?Give each row its own y, at least 50 apart for 40-high buttons.
A click changes the difficulty but the turtle still moves at the old speed.Is delay in the global line of clicked?Add delay to clicked's global line.

Answers to the checks

  1. Predict: You click at x = 0 on the row of buttons. Which button is pressed?
    Pause: its button starts at bxs[1] = -60 and is 120 wide, so it covers x from -60 to 60.
  2. Follow a click: A click at x = 100, y = -170. Follow the loop in clicked.
    -60, no, 70, yes
    Only the third button covers x = 100 (it runs from 70 to 190), so press("Go") runs.
  3. Keep the lists in step: You add a fourth name to names but forget to add a position to bxs. What happens?
    An error: the loop asks for bxs[3], which does not exist
    The loops go up to len(names), so they ask for a fourth position. Parallel lists must stay the same length.

Solutions

One possible solution for each task. Other correct programs are fine.

difficulty row

from turtle import *
from ui import inside, draw_button

speed(0)
penup()
hideturtle()

xs = [-120, 0, 120, 120, 0, -120]
ys = [70, 110, 70, -20, -50, -20]
place = 0
tx = 0
ty = 0
score = 0
showing = False
time_left = 30
playing = False
delay = 1000

names = ["New game", "Pause", "Go"]
bxs = [-190, -60, 70]

levels = ["Easy", "Medium", "Hard"]
lxs = [-190, -60, 70]
delays = [1300, 1000, 700]


def draw_scene():
    clear()
    goto(-190, 160)
    write(score, False, "left", ("Arial", 20, "normal"))
    goto(150, 160)
    write(time_left, False, "left", ("Arial", 20, "normal"))
    for i in range(len(names)):
        draw_button(bxs[i], -190, 120, 40, names[i])
    for i in range(len(levels)):
        draw_button(lxs[i], -140, 120, 40, levels[i])
    goto(tx, ty)


def hop():
    global place, tx, ty, showing
    if playing:
        tx = xs[place]
        ty = ys[place]
        place = (place + 1) % len(xs)
        goto(tx, ty)
        showturtle()
        showing = True
        ontimer(hide, delay - 300)
        ontimer(hop, delay)


def hide():
    global showing
    if showing:
        showing = False
        hideturtle()


def tick():
    global time_left, playing
    if playing:
        time_left = time_left - 1
        if time_left == 0:
            playing = False
            hideturtle()
        else:
            ontimer(tick, 1000)
        draw_scene()


def go():
    global playing
    if playing == False and time_left > 0:
        playing = True
        hop()
        ontimer(tick, 1000)


def press(name):
    global score, time_left, place, playing
    if name == "New game":
        playing = False
        score = 0
        time_left = 30
        place = 0
        draw_scene()
        ontimer(go, 1100)
    if name == "Pause":
        playing = False
        hideturtle()
    if name == "Go":
        go()


def clicked(x, y):
    global score, showing, delay
    if playing and showing and inside(x, y, tx - 20, ty - 20, 40, 40):
        score = score + 1
        showing = False
        hideturtle()
        draw_scene()
    for i in range(len(names)):
        if inside(x, y, bxs[i], -190, 120, 40):
            press(names[i])
    for i in range(len(levels)):
        if inside(x, y, lxs[i], -140, 120, 40):
            delay = delays[i]


draw_scene()
onscreenclick(clicked)
listen()
mainloop()

your own controls

from turtle import *
from ui import inside, draw_button

speed(0)
penup()
hideturtle()

xs = [-120, 0, 120, 120, 0, -120]
ys = [70, 110, 70, -20, -50, -20]
place = 0
tx = 0
ty = 0
score = 0
showing = False
time_left = 30
playing = False
delay = 1000

names = ["New game", "Pause", "Go"]
bxs = [-190, -60, 70]

levels = ["Easy", "Medium", "Hard"]
lxs = [-190, -60, 70]
delays = [1300, 1000, 700]

themes = ["Day", "Night", "Sea"]
txs = [-190, -60, 70]
backgrounds = ["white", "lightgrey", "lightblue"]


def draw_scene():
    clear()
    goto(-190, 160)
    write(score, False, "left", ("Arial", 20, "normal"))
    goto(150, 160)
    write(time_left, False, "left", ("Arial", 20, "normal"))
    for i in range(len(names)):
        draw_button(bxs[i], -190, 120, 40, names[i])
    for i in range(len(levels)):
        draw_button(lxs[i], -140, 120, 40, levels[i])
    for i in range(len(themes)):
        draw_button(txs[i], 120, 120, 40, themes[i])
    goto(tx, ty)


def hop():
    global place, tx, ty, showing
    if playing:
        tx = xs[place]
        ty = ys[place]
        place = (place + 1) % len(xs)
        goto(tx, ty)
        showturtle()
        showing = True
        ontimer(hide, delay - 300)
        ontimer(hop, delay)


def hide():
    global showing
    if showing:
        showing = False
        hideturtle()


def tick():
    global time_left, playing
    if playing:
        time_left = time_left - 1
        if time_left == 0:
            playing = False
            hideturtle()
        else:
            ontimer(tick, 1000)
        draw_scene()


def go():
    global playing
    if playing == False and time_left > 0:
        playing = True
        hop()
        ontimer(tick, 1000)


def press(name):
    global score, time_left, place, playing
    if name == "New game":
        playing = False
        score = 0
        time_left = 30
        place = 0
        draw_scene()
        ontimer(go, 1100)
    if name == "Pause":
        playing = False
        hideturtle()
    if name == "Go":
        go()


def clicked(x, y):
    global score, showing, delay
    if playing and showing and inside(x, y, tx - 20, ty - 20, 40, 40):
        score = score + 1
        showing = False
        hideturtle()
        draw_scene()
    for i in range(len(names)):
        if inside(x, y, bxs[i], -190, 120, 40):
            press(names[i])
    for i in range(len(levels)):
        if inside(x, y, lxs[i], -140, 120, 40):
            delay = delays[i]
    for i in range(len(themes)):
        if inside(x, y, txs[i], 120, 120, 40):
            bgcolor(backgrounds[i])


draw_scene()
onscreenclick(clicked)
listen()
mainloop()

Stretch and support

Stretch: Add a row that chooses between two different paths (two pairs of lists) for the turtle.

Support: Give the difficulty row's three lists already written; students add only the two loops.

Exit ticket

A panel has names = ["A", "B", "C"] and bxs = [-190, -60, 70], each button 120 wide. Which button does a click at x = -100 press?

A. Its button runs from -190 to -70, and -100 is inside that range.

What each step is for

Where it leads

Gradio lets you list controls (gr.Button, gr.Radio) and draws them and checks clicks for you. On a web page, HTML draws the buttons and JavaScript listens for clicks. Students have built what both do.