Students rebuild the stars game with a list of stars and lists of speeds and points beside it, so one loop moves every star, then meet the weakness of lists side by side (they must stay in step).
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.
Predict and Run 10 min · Investigate 15 min · Modify 10 min · Make 15 min
Read the unit primer first. stars.append(s) adds a turtle to the end of a list. speeds[i] and points[i] are the values for stars[i]: lists side by side ("parallel lists") linked only by the place number. They work while every list is changed together, and break when one is not. The bug task shows this: five stars but four speeds gives IndexError: list index out of range. The lesson ends with four lists for one star, which is the problem next lesson fixes.
Keeping lists side by side in step. Let the IndexError happen, then ask them to count the items in each list.
| What you will see | A question to ask | The fix |
|---|---|---|
| IndexError: list index out of range. | Does every list have one item for every star? | Append to every list in the same loop that makes the stars. |
| A star moves at another star's speed. | Do the lists have their items in the same order? | Fill all the lists in the same loop, one item each time round. |
| The bad star costs points but stays gold. | Where is the bad star's colour set? | Set s.color("red") in the loop when bad is True for that star. |
One possible solution for each task. Other correct programs are fine.
from turtle import *
import random
speed(0)
penup()
goto(0, -180)
left(90)
score = 0
pen = Turtle()
pen.hideturtle()
pen.penup()
pen.goto(-220, 200)
stars = []
speeds = []
points = []
for i in range(6):
s = Turtle()
s.shape("circle")
s.color("gold")
s.penup()
s.goto(-150 + i * 100, 200)
s.setheading(270)
stars.append(s)
speeds.append(random.randint(3, 7))
points.append(1)
def show_score():
pen.clear()
pen.write("Score: " + str(score), False, "left", ("Arial", 16, "normal"))
def go_left():
goto(xcor() - 25, ycor())
def go_right():
goto(xcor() + 25, ycor())
def tick():
global score
for i in range(len(stars)):
stars[i].forward(speeds[i])
if stars[i].distance(xcor(), ycor()) < 25:
score += points[i]
stars[i].goto(random.randint(-200, 200), 200)
if stars[i].ycor() < -220:
stars[i].goto(random.randint(-200, 200), 200)
show_score()
ontimer(tick, 50)
onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()
from turtle import *
import random
speed(0)
penup()
goto(0, -180)
left(90)
score = 0
pen = Turtle()
pen.hideturtle()
pen.penup()
pen.goto(-220, 200)
stars = []
speeds = []
points = []
for i in range(4):
s = Turtle()
s.shape("circle")
s.color("gold")
s.penup()
s.goto(-150 + i * 100, 200)
s.setheading(270)
stars.append(s)
speeds.append(random.randint(3, 7))
points.append(random.randint(1, 3))
def show_score():
pen.clear()
pen.write("Score: " + str(score), False, "left", ("Arial", 16, "normal"))
def go_left():
goto(xcor() - 25, ycor())
def go_right():
goto(xcor() + 25, ycor())
def tick():
global score
for i in range(len(stars)):
stars[i].forward(speeds[i])
if stars[i].distance(xcor(), ycor()) < 25:
score += points[i]
stars[i].goto(random.randint(-200, 200), 200)
if stars[i].ycor() < -220:
stars[i].goto(random.randint(-200, 200), 200)
show_score()
ontimer(tick, 50)
onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()
from turtle import *
import random
speed(0)
penup()
goto(0, -180)
left(90)
score = 0
pen = Turtle()
pen.hideturtle()
pen.penup()
pen.goto(-220, 200)
stars = []
speeds = []
points = []
bad = []
for i in range(4):
s = Turtle()
s.shape("circle")
s.color("gold")
s.penup()
s.goto(-150 + i * 100, 200)
s.setheading(270)
stars.append(s)
speeds.append(random.randint(3, 7))
points.append(1)
if i == 0:
bad.append(True)
s.color("red")
else:
bad.append(False)
def show_score():
pen.clear()
pen.write("Score: " + str(score), False, "left", ("Arial", 16, "normal"))
def go_left():
goto(xcor() - 25, ycor())
def go_right():
goto(xcor() + 25, ycor())
def tick():
global score
for i in range(len(stars)):
stars[i].forward(speeds[i])
if stars[i].distance(xcor(), ycor()) < 25:
if bad[i]:
score -= 3
else:
score += points[i]
stars[i].goto(random.randint(-200, 200), 200)
if stars[i].ycor() < -220:
stars[i].goto(random.randint(-200, 200), 200)
show_score()
ontimer(tick, 50)
onkey(go_left, "Left")
onkey(go_right, "Right")
listen()
show_score()
tick()
mainloop()
Stretch: Add a fifth list, sizes, and use it to make some stars bigger with turtlesize-style shapes (or different shapes) and worth more.
Support: Give students the bad list already filled in, and ask them only to change what happens when a star is caught.
names = ["Ada", "Bo"] and ages = [12, 13, 11]. What is wrong?
The lists are out of step: three ages for two names, so the third age belongs to nobody (and a loop over ages would fail on names[2]).
Next lesson keeps everything about one star in one dictionary, so nothing can fall out of step. Databases have the same choice: separate columns kept in step, or one record per thing.