← Teacher guide

Lists of stars

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).

Objects with turtles · Many things on screen · about 50 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 and Run 10 min · Investigate 15 min · Modify 10 min · Make 15 min

Before class

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.

Running the lesson

  1. Predict: places start at 0, so place 2 is the third item. Point at the same column in both lists.
  2. Run: ask how many lines a fifth star costs now (one number) compared with last lesson (11 lines).
  3. Investigate: in the trace, say each row aloud: star 1 uses speed 7 and 1 point.
  4. Bug task: ask students to count the stars and the speeds. Then ask which line should change.
  5. Make: four lists for one star. Ask what could go wrong when someone adds a fifth property.

The hard part (on purpose)

Keeping lists side by side in step. Let the IndexError happen, then ask them to count the items in each list.

When students get stuck

What you will seeA question to askThe 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.

Answers to the checks

  1. Predict: What does it print?
    5 5. Place 2 is the third item in each list (places start at 0): speeds[2] is 5 and points[2] is 5. Both describe the same star.
  2. Eight stars: What would you change to play with eight stars?
    range(4) to range(8)
    The loop makes the stars, so one number sets how many. Every list grows with it, because the loop appends to all three.
  3. Same place, same star: speeds is [4, 7, 3, 5] and points is [1, 1, 1, 1]. Fill in what the loop in tick uses for each star.
    7, 1, 5, 1
    The same i picks the same star from every list. stars[1] is the second star, so its speed is speeds[1], which is 7.
  4. Spot the bug: Someone made a fifth star but it stops with an IndexError. Click the line where Python stops.
    line 11
    There are five stars but only four speeds, so speeds[4] does not exist. Lists side by side must be changed together: every new star needs a speed too.
  5. Where this leads: Each star now has a turtle, a speed, points and bad in four lists. What happens if one list gets a star the others do not?
    The lists fall out of step: an IndexError, or a star using another star's values
    Lists side by side only work while they stay in step. Next lesson keeps everything about one star together, in one dictionary.

Solutions

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

Modify › Six stars

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()

Modify › Different points

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()

Make a bad star

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 and support

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.

Exit ticket

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]).

What each step is for

Where it leads

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.