Nested selection and match

Decisions inside decisions, and choosing by exact value with a case statement.

F2.4Decisions and loopsGCSE15 min

Do this lesson in the simulator

Some decisions only make sense after another one. There is no point asking how fast to drive if the way is blocked. And some decisions pick one of many exact values: which command did the user type? This lesson covers both: decisions inside decisions, and match, Python's case statement.

A decision inside a decision

A block can hold another if. The inner question is only asked when the outer one lets the program in:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

if distance() > 30:
    if battery() > 50:
        print("go fast")
        forward(80, distance=20)
    else:
        print("go gently")
        forward(30, distance=20)
else:
    print("blocked")

Run this in the simulator

This is nested selection. Indentation shows which if each else belongs to: the inner else lines up with the inner if, the outer else with the outer if. Move an else four spaces and it belongs to a different question.

Nested or joined?

Often and says the same thing in one line:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

d = distance()
b = battery()
if d > 30 and b > 50:
    print("go fast")
elif d > 30:
    print("go gently")
else:
    print("blocked")

Run this in the simulator

Both versions give the same answer for every distance and battery. Nest when the inner decision has several outcomes of its own, or when the outer question must be settled first (for example, check the user typed a number before comparing it). Join with and when it reads more simply.

Tracing a nested decision

Predict the output for each pair of values before you run it, then change d and b and check:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

d = 25
b = 80
if d < 30:
    if b < 20:
        print("stuck and flat")
    else:
        print("stuck")
else:
    if b < 20:
        print("free but flat")
    else:
        print("free")

Run this in the simulator

Try d = 25, b = 10, then d = 60, b = 10, then d = 60, b = 80. Four combinations, four outcomes: nesting covers every case.

match: choosing by exact value

When one value decides between several exact answers, a chain of elifs repeats the same comparison again and again. match says it once:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

command = input("Which way? (forward, back, left, right) ")
match command:
    case "forward":
        forward(50, distance=20)
    case "back":
        backward(50, distance=20)
    case "left" | "right":
        print("sideways!")
        if command == "left":
            left(50, distance=20)
        else:
            right(50, distance=20)
    case _:
        print("I do not know", command)
print("at", position())

Run this in the simulator

match command: takes the value once. Each case is one possible value; the first that matches runs, and the rest are skipped. | means "or", so "left" | "right" matches either. case _: matches anything at all, so it catches every other answer: put it last, like else.

The same program with elif works too. match is simply tidier when every branch compares one value against fixed answers. It is a case statement, which other languages call switch.

Task: command mode

The robot asks Which way? and then How far?. Use match (or elif) on the direction to drive that far: forward, back, left or right. For any other word, print unknown and do not move. The task answers right and 20; your program must work for any answers, so do not type them in.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

command = input("Which way? ")
far = float(input("How far? "))

Challenges

  1. Add a stop command that turns the LED red and does not move.
  2. Make the robot refuse to drive forward when there is less than 30 cm of room, using a nested if inside that case.
  3. Rewrite the command program with elif instead of match. Which is easier to read?