Write your own functions, then use them to make a button and a game.
Each lesson works two ways. Students can work through the online tutorial at their own pace (it checks their answers and saves their progress in their browser), or you can teach it to the whole class from the slides, then send students into the tutorial for the Modify and Make steps.
Every lesson guide has plain-language notes, the answers to every check, a solution for every task, and slides and a worksheet for Waypoints Prepare. These guide pages are not linked from student pages, but they are not secret either: keep printed Teacher editions for answers you do not want students to find.
Whole-course cheat sheet: Open to print (every command, grouped by unit: a handout for the final challenge)
Read a longer program and change it without breaking it.
Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown
Name steps, give them inputs and outputs, and keep them in modules.
A function is a named set of steps. def square(): teaches Python a new word, square, and the indented lines say what it means. Writing the def does nothing on its own; the steps run when you call it: square().
A parameter is an input: def square(size): lets each call choose, square(50) or square(150). A function can also return an answer: def metres(m): return m * 20 gives back a number other code can use, like forward(metres(5)). A module is a file of related functions that other programs import.
A function is a recipe card. Writing the card does not cook anything; following it (calling) does. A parameter is "serves 4" on the card: the same recipe for a different amount. return is handing the finished dish back to whoever asked for it.
Where it breaks: print is like showing someone a photo of the dish. They can see it, but they cannot eat it. A function that prints instead of returning gives nothing back, which is why the Returns lesson's bug stops with an error.
def square(): with a loop of four forward(100) and right(90) under it. Run it: nothing is drawn.square() at the bottom (not indented). Now a square appears.def square(size):, use forward(size), and call square(50) then square(100).size); the argument is the value in the call (50).Every later lesson is built from functions: event handlers in Interaction, draw_button and inside in the ui module, and every part of the final game.
Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown
Events, and a button built from scratch.
Until now programs ran top to bottom and stopped. Event-driven programs set things up, then wait. When something happens (a click, a key, a timer), they run a function. onscreenclick(stamp) means "when the picture is clicked, run stamp". The function handed over is called a callback. mainloop() keeps the program waiting until you press Stop.
A button is three things: a rectangle drawn on screen, a label, and a hit test, the check that a click landed inside the rectangle.
Every app works this way: it waits for you, then reacts. Building a button by hand shows what tools like Gradio and every phone app do behind the scenes. The visible button is the small part; drawing it, checking the click and updating the screen are the rest.
A callback is like leaving your phone number with a shop: "call me when it arrives". You do not keep asking; they call you.
Where it breaks: you give them your number, not a phone call. onscreenclick(stamp) hands over the name; onscreenclick(stamp()) with brackets calls the function immediately, once, which is the classic bug.
dot(30, "orange") to a different size and colour.mainloop() keeps it waiting for events. Press Stop to end it.global score as its first line.The final challenge is an event-driven game: a timer moves the turtle, clicks catch it, and buttons start the game and buy upgrades.
Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown
Build a game that uses everything, then add power-ups. Two optional lessons go further.
A game (or an app) is three things working together:
True and False are values a variable can hold to remember something that is either so or not: showing = True while the turtle is on screen.
The challenge uses everything from the course in one program, so students see that the pieces fit together. It also previews both directions they can take next: user interface (buttons, status bars, control panels, towards Gradio and web pages) and games (screens, levels, movement, towards MakeCode Arcade and microStudio).
A board game: the board and pieces are the data, the rulebook is the rules, and taking turns is the loop.
Where it breaks: in a board game, players move the pieces. In a program, the loop and the events change the data, and the screen is redrawn to show it. If the data changes but nothing redraws, the player never sees it.
xs and ys to a path of your own and play again.700 in ontimer(hide, 700) to 400. The turtle hides sooner: a rule changed.global line.true is not the same.Finishing Catch the turtle and Power-ups marks the course Challenge complete. Control panel leads towards apps (Gradio, web pages); Game levels leads towards games (MakeCode Arcade, microStudio).
Cheat sheet: Open to print (A4, with a picture of what each command draws) · Markdown
Self-paced briefs students can pick up after the lesson named on each. Students tick their own milestones and claim a badge; the page lights the skills their code uses. Badges stay in the student's browser: ask them to press Show your teacher. Open the projects page
Draw a street: houses, trees, shops or anything else, of different sizes and colours, along one line. Each kind of thing is drawn by a function you write once and call many times.
Milestones:
The list can hold sizes, x positions or colours; any of these counts. Students who write one long program with no functions have met the goal of a picture but not the brief: point them at the milestone about calling one function many times.
from turtle import *
speed(0)
def house(x, size, colour):
penup()
goto(x, -60)
pendown()
fillcolor(colour)
begin_fill()
for side in range(4):
forward(size)
left(90)
end_fill()
fillcolor("brown")
begin_fill()
goto(x, -60 + size)
goto(x + size / 2, -60 + size * 1.5)
goto(x + size, -60 + size)
goto(x, -60 + size)
end_fill()
def tree(x, size):
penup()
goto(x, -60)
pendown()
fillcolor("sienna")
begin_fill()
for side in range(2):
forward(size / 4)
left(90)
forward(size / 2)
left(90)
end_fill()
penup()
goto(x + size / 8, -60 + size / 2)
pendown()
fillcolor("green")
begin_fill()
circle(size / 3)
end_fill()
street = [("house", 50, "lightblue"), ("tree", 70, ""), ("house", 70, "pink"), ("house", 40, "khaki"), ("tree", 60, "")]
x = -230
for thing in street:
if thing[0] == "house":
house(x, thing[1], thing[2])
else:
tree(x, thing[1])
x = x + thing[1] + 25
hideturtle()
Choose something you can count (your week's screen time, the class's favourite fruits, rainfall) and draw it as a bar chart. A function decides each bar's colour from its value, so big and small values look different.
Milestones:
Real data makes this stick: let students collect a small set first (five to eight numbers). write() is a recipe from Events; students who reach for it early can copy it from the Reference.
from turtle import *
speed(0)
hours = [2, 3, 1, 4, 6, 5, 2]
def colour_for(value):
if value >= 5:
return "tomato"
elif value >= 3:
return "gold"
return "mediumseagreen"
def bar(height, colour):
fillcolor(colour)
pendown()
begin_fill()
left(90)
forward(height)
right(90)
forward(30)
right(90)
forward(height)
left(90)
end_fill()
penup()
forward(10)
penup()
goto(-180, -100)
for h in hours:
bar(h * 30, colour_for(h))
hideturtle()
Make a drawing toy: a click draws a shape where the mouse is (a dot, a square, anything), and keys change the colour, the shape or the size. Someone else should be able to play with it without reading your code.
Milestones:
Remind students to click the drawing first so keys reach it. The global line is the usual stumbling block; the friendly error names it.
from turtle import *
speed(0)
penup()
hideturtle()
colours = ["tomato", "gold", "teal", "purple"]
c = 0
size = 30
squares = False
def square(length):
pendown()
fillcolor(colours[c])
begin_fill()
for side in range(4):
forward(length)
left(90)
end_fill()
penup()
def draw_here(x, y):
goto(x, y)
if squares:
square(size)
else:
dot(size, colours[c])
def next_colour():
global c
c = (c + 1) % len(colours)
def bigger():
global size
size = size + 10
def switch_shape():
global squares
squares = not squares
for x in range(-150, 151, 75):
draw_here(x, 0)
next_colour()
onscreenclick(draw_here)
onkey(next_colour, "c")
onkey(bigger, "b")
onkey(switch_shape, "s")
listen()
mainloop()
Make a small game that is not Catch the turtle: a target that moves on a timer, something to click or dodge, a score and a way to win or lose. Keep it small enough to finish this week.
Milestones:
Scope is the risk: ask for a one-sentence pitch before students code. The last milestone is the play test from the Power-ups lesson; it is worth a short lesson of its own.
from turtle import *
import random
speed(0)
penup()
shape("circle")
color("tomato")
score = 0
lives = 5
caught = True
playing = True
def show():
clear()
here = position()
goto(-190, 160)
write("Score " + str(score) + " Lives " + str(lives), False, "left", ("Arial", 16, "normal"))
goto(here)
def move():
global lives, caught, playing
if not caught:
lives = lives - 1
if lives == 0 or score >= 10:
playing = False
show()
hideturtle()
return
caught = False
goto(random.randint(-150, 150), random.randint(-120, 120))
show()
ontimer(move, 1200)
def clicked(x, y):
global score, caught
if playing and not caught and abs(x - xcor()) < 20 and abs(y - ycor()) < 20:
score = score + 1
caught = True
show()
onscreenclick(clicked)
move()
mainloop()