Nested selection and match
Decisions inside decisions, and choosing by exact value with a case statement.
Do this lesson in the simulatorSome 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")
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")
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")
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())
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
- Add a
stopcommand that turns the LED red and does not move. - Make the robot refuse to drive forward when there is less than 30 cm of room, using a nested
ifinside thatcase. - Rewrite the command program with
elifinstead ofmatch. Which is easier to read?