An optional, harder extension of the Reaction timer. Students add decoy signals, levels with target times kept in a list, and lives, managing several pieces of state at once.
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, Run, Investigate 10 min · Milestone 1 10 min · Milestone 2 15 min · Milestone 3 20 min · Make it yours 5 min
This lesson is optional: it is for students who finished the Reaction timer and Radio duel and want a harder challenge. It needs nothing new, only more of the same ideas at once. A decoy (a cross instead of the heart) appears about one round in three (pick random 0 to 2 = 0); a second true/false variable, decoy, remembers that moment. Levels use a list of target times, targets: the current level is the place in the list, so reaction < targets[level] gets harder as the level rises. When the level reaches the length of the list, the player has won. Lives count mistakes.
Which check comes first in the A button, and a list of targets by level. Ask them to say the order of the questions before testing.
| What you will see | A question to ask | The fix |
|---|---|---|
| Pressing on a cross shows the too-early cross, not the skull. | Which is checked first in A: waiting, decoy, or else? | Order: if waiting … else if decoy … else. |
| The level goes up even when slow. | Which way round is the comparison? | Use reaction < targets[level]: faster than the target. |
| Something goes wrong after the last level. | Which places exist in targets? | When level equals the length of targets, the player has won: show Champion and start again. |
One possible solution for each task. Other correct programs are fine.

let start = 0
let waiting = false
let decoy = false
input.onButtonPressed(Button.B, function () {
waiting = false
decoy = false
basic.clearScreen()
basic.pause(randint(1000, 3000))
if (randint(0, 2) == 0) {
decoy = true
basic.showIcon(IconNames.No)
} else {
basic.showIcon(IconNames.Heart)
start = input.runningTime()
waiting = true
}
})
input.onButtonPressed(Button.A, function () {
if (waiting) {
waiting = false
basic.showNumber(input.runningTime() - start)
} else if (decoy) {
decoy = false
basic.showIcon(IconNames.Skull)
} else {
basic.showIcon(IconNames.No)
}
})

let start = 0
let waiting = false
let decoy = false
let reaction = 0
let level = 0
let targets = [800, 600, 450, 350, 300]
input.onButtonPressed(Button.B, function () {
waiting = false
decoy = false
basic.clearScreen()
basic.pause(randint(1000, 3000))
if (randint(0, 2) == 0) {
decoy = true
basic.showIcon(IconNames.No)
} else {
basic.showIcon(IconNames.Heart)
start = input.runningTime()
waiting = true
}
})
input.onButtonPressed(Button.A, function () {
if (waiting) {
waiting = false
reaction = input.runningTime() - start
if (reaction < targets[level]) {
level += 1
basic.showNumber(level)
} else {
basic.showIcon(IconNames.Sad)
}
} else if (decoy) {
decoy = false
basic.showIcon(IconNames.Skull)
} else {
basic.showIcon(IconNames.No)
}
})

let start = 0
let waiting = false
let decoy = false
let reaction = 0
let level = 0
let lives = 3
let targets = [800, 600, 450, 350, 300]
input.onButtonPressed(Button.B, function () {
waiting = false
decoy = false
basic.clearScreen()
basic.pause(randint(1000, 3000))
if (randint(0, 2) == 0) {
decoy = true
basic.showIcon(IconNames.No)
} else {
basic.showIcon(IconNames.Heart)
start = input.runningTime()
waiting = true
}
})
input.onButtonPressed(Button.A, function () {
if (waiting) {
waiting = false
reaction = input.runningTime() - start
if (reaction < targets[level]) {
level += 1
if (level == targets.length) {
basic.showString("Champion")
level = 0
lives = 3
} else {
basic.showNumber(level)
}
} else {
lives += -1
basic.showIcon(IconNames.Sad)
}
} else if (decoy) {
decoy = false
lives += -1
basic.showIcon(IconNames.Skull)
} else {
basic.showIcon(IconNames.No)
}
if (lives == 0) {
basic.showString("Game over")
basic.showNumber(level)
level = 0
lives = 3
}
})
Open task: any program that does what the step asks.
Stretch: Make the decoy chance grow with the level: pick random 0 to (4 − level), so higher levels trick you more often.
Support: Students who find this heavy can stop after Milestone 2; the levels alone make a good game.
level is 2 and targets is 800, 600, 450, 350, 300. What time must you beat, and why?
450 ms: level 2 is the place in the list, counted from 0.
The other optional lesson, Tournament, takes the Radio duel further with a scoreboard list. Class ideas: a class high-level board; students design a sixth level and argue what its target should be.