Decisions: if / elif / else & Finite-State Thinking

Pre-COSMOS Day 6, for Cluster 10: Robot Inventors, running two hours or more in depth. It covers comparisons and booleans, then if, elif, and else, where the first true branch wins and so the order matters, and and, or, and not, including the classic "or green" bug and the == against = trap. It goes on to more advanced techniques - the in operator, chained comparisons, truthiness, operator precedence, and De Morgan's law - then builds the Maze Robot Brain v1. It ends with finite state machines done two ways: as nested if/elif, and table-driven, using dictionary dispatch together with a transition table mapping (state, input) to (action, next_state). Every snippet is runnable, and the outputs and error messages came verbatim from CPython 3.12.

Subject: Python · 110 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. What you will be able to do

Objectives

Robots decide constantly - if I see red, turn. Today you make programs choose. By the end you can:

1. Compare values with ==, !=, <, >, <=, >= and read the True/False they return.

2. Choose between paths with if / elif / else, knowing the first true branch wins.

3. Combine tests with and, or, not - and avoid the classic or bug.

4. Build the Maze Robot Brain: read a color and decide a move.

5. Explain a finite state machine - states plus rules for switching - and build a patrol/guard robot.

6. Reach for sharper tools - in, chained comparisons, truthiness - and build a table-driven state machine.

2. What survived from List Methods: append, sort, len?

Warm-up

Discussion prompt

Before we open Decisions: if / elif / else & Finite-State Thinking: without looking back, what was the main idea of List Methods: append, sort, len, and what could you do by the end of it that you could not do before?

Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.

Answer:

An in-depth session of 36 slides. append() adds in place, sort() and sort(reverse=True) reorder in place, and len() counts, which leads to the big idea that in-place methods return None, so nums = nums.sort() wipes your data. It also covers append against +, and top-N slicing, with three traps and five checks, then the four-part High-Score Board build with a top-three stretch. It was built for the Pre-COSMOS Day 4 hour.

3. Programs make decisions

Concept

Up to now your code ran straight through, top to bottom. A decision lets it choose: do this only when something is true.

A maze robot does this every moment: if I see green, go forward; if I see red, turn. That choice is what you are about to write.

4. Break it if you can: Programs make decisions

Counterexample

Discussion prompt

Up to now your code ran straight through, top to bottom. A decision lets it choose: do this only when something is true.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

Answer:

A maze robot does this every moment: if I see green, go forward; if I see red, turn. That choice is what you are about to write.

5. A condition is a yes/no question

Concept

Every decision rests on a condition - an expression that is either True or False (a bool). color == "red" asks: is color equal to red?

condition — A True/False expression a decision is based on. The code under an if runs only when its condition is True.

6. By analogy: A condition is a yes/no question

Analogy

Discussion prompt

Explain A condition is a yes/no question by analogy to something with no Python in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Every decision rests on a condition - an expression that is either True or False (a bool). color == "red" asks: is color equal to red?

7. Comparison operators

Concept

These six operators each ask a yes/no question and return a bool:

operatorasksexamplevalue
==equal to?5 == 5True
!=not equal to?5 != 6True
<less than?5 < 6True
>greater than?3 > 9False
<=at most?7 <= 7True
>=at least?7 >= 8False

8. Fill in: asks for Comparison operators

Comparison

Comparison matrix

From Comparison operators: refill the asks column from what you know. The rest of the table is as it appeared.

operatorasksexamplevalue
==equal to?5 == 5True
!=not equal to?5 != 6True
<less than?5 < 6True
>greater than?3 > 9False
<=at most?7 <= 7True
>=at least?7 >= 8False

9. Predict the next row: Comparisons return True or False

Pattern

Predict first

The table runs: 5 == 5 | True · 5 != 6 | True · 3 > 9 | False

In Comparisons return True or False, given the rows so far: what is the next one — the row where expression is 7 >= 7?

Correct: 7 >= 7 | True

expressionvalue
5 == 5True
5 != 6True
3 > 9False
7 >= 7True

Why: The relationship between the columns, not the individual numbers, is what generates the next row. A comparison is a question; its answer is True or False, which you can print, store, or test in an if.

10. Comparisons return True or False

Worked example

print(5 == 5)
print(5 != 6)
print(3 > 9)
print(7 >= 7)

Each comparison evaluates to a bool

Why: A comparison is a question; its answer is True or False, which you can print, store, or test in an if.

Read the answers

Why: Verified by execution: True, True, False, True.

expressionvalue
5 == 5True
5 != 6True
3 > 9False
7 >= 7True

11. Which is which, by value

Discrimination

Sort into buckets

Sort these by value, from memory, without looking back at Comparisons return True or False. Telling them apart on the spot is the skill; the table is only where the answer happens to be written down.

True
5 == 5; 5 != 6; 7 >= 7
False
3 > 9
g1
value is "True" for 5 == 5, 5 != 6, 7 >= 7 — that is what the table on "Comparisons return True or False" records, and it is the single property separating this group from the rest.
g2
value is "False" for 3 > 9 — that is what the table on "Comparisons return True or False" records, and it is the single property separating this group from the rest.

12. Something is wrong here: == compares, = assigns

Anomaly

Predict first

A student writes this, and it looks reasonable:

Trying to check if color is red - with a single =.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Python stops before running anything - it even guesses your mistake in the error message.

Use == to compare. One = sets a value; two == ask if values are equal.

Why: Python stops before running anything - it even guesses your mistake in the error message.

13. Trap: == compares, = assigns

Trap

The trap

Trying to check if color is red - with a single =.

color = "red"
if color = "red":
    print("turn")

A single = means assign, and you can't assign inside an if

Why: Python stops before running anything - it even guesses your mistake in the error message.

expressionresult
if color = "red":SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?

The fix

Use == to compare. One = sets a value; two == ask if values are equal.

color = "red"
if color == "red":
    print("turn")

== asks the yes/no question

Why: color == "red" is True, so the branch runs. Real output: turn. Read it aloud as 'is color equal to red?'

expressionvalueoutput
color == "red"Trueturn

14. Inspect it line by line: Trap: == compares, = assigns

Error analysis

Annotate

Walk the callouts on Trap: == compares, = assigns. Each one is a place this is easy to get subtly wrong.

  • Python stops before running anything - it even guesses your mistake in the error message.
  • color == "red" is True, so the branch runs. Real output: turn. Read it aloud as 'is color equal to red?'

15. == is exact: case and type matter

Concept

== checks for an exact match. "Red" is not equal to "red" - a capital letter is a different character.

Types matter too: the number 5 is not equal to the text "5". This is why a sensor reading must be the right type before you compare it.

16. Teach it back: == is exact: case and type matter

Explain it

Discussion prompt

Explain == is exact: case and type matter to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

== checks for an exact match. "Red" is not equal to "red" - a capital letter is a different character.

17. Comparing strings

Worked example

print("red" == "red")
print("Red" == "red")
print("red" == "blue")

Only an exact, same-case match is True

Why: Verified by execution: "Red" differs from "red" by one capital letter, so it is False.

expressionvaluewhy
"red" == "red"Trueidentical
"Red" == "red"Falsecapital R differs
"red" == "blue"Falsedifferent words

18. What each one costs: Comparing strings

Trade off

Comparison matrix

From Comparing strings: every row here is a choice with a cost. Fill the why column, then say which row you would actually pick and what you give up for it.

expressionvaluewhy
"red" == "red"Trueidentical
"Red" == "red"Falsecapital R differs
"red" == "blue"Falsedifferent words

19. The if statement

Concept

if runs a block of code only when its condition is True. Write if, the condition, a colon, then the indented lines to run.

If the condition is False, the indented block is skipped entirely and the program moves on.

20. An if is a gate

Intuition

Picture each if as a gate on the path. The condition is the lock. If the condition is True the gate opens and you walk through the indented block; if it is False the gate stays shut and you walk around it.

The indented lines are behind the gate. That is why indentation matters: it marks exactly what is inside.

21. A simple if

Worked example

temp = 80
if temp > 50:
    print("warm")
print("done")

Line 2: the condition temp > 50 is True

Why: 80 > 50, so the gate opens and the indented line runs.

Line 4 runs no matter what - it is NOT indented

Why: Verified by execution: prints warm then done. 'done' is outside the if, so it always runs.

lineruns?prints
if temp > 50condition True-
print("warm")yes (inside)warm
print("done")alwaysdone

22. Watch it run: A simple if

Pattern

Step through it

Step through A simple if one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: line is if temp > 50
  2. Step 2: line is print("warm")
  3. Step 3: line is print("done")

23. else: the otherwise branch

Concept

else gives an otherwise path: run this when the if condition was False. It has no condition of its own - it catches everything the if missed.

24. if / else

Worked example

temp = 30
if temp > 50:
    print("warm")
else:
    print("cold")

The condition is False, so else runs

Why: 30 > 50 is False, so the if block is skipped and the else block runs. Verified by execution: prints cold.

temptemp > 50prints
80Truewarm
30Falsecold

25. elif: more than two paths

Concept

When there are several possibilities, elif (else-if) adds more conditions between the if and the else. You can have as many elif branches as you need.

Python checks them top to bottom and takes the first one that is True.

26. Restore the missing line: if / elif / else with a color

Fill the middle

Fill in the blanks

From if / elif / else with a color — one line has had its right-hand side removed. Put it back.

color = "red"
if color == "green":
print("go")
elif color == "red":
print("turn")
else:
print("wait")

Why: color is what everything below it consumes, so the wrong expression here fails later and somewhere else. color is "red", so color == "green" is False.

27. if / elif / else with a color

Worked example

color = "red"
if color == "green":
    print("go")
elif color == "red":
    print("turn")
else:
    print("wait")

Check the if first: is color green?

Why: color is "red", so color == "green" is False. Skip that block.

Check the elif: is color red?

Why: Yes - so it prints turn, and the else is skipped entirely.

branchconditiontaken?
if color == "green"Falseno
elif color == "red"Trueyes -> turn
else(not reached)no

28. Draw the shape of it: if / elif / else with a color

Blank canvas

Draw it

Draw what if / elif / else with a color just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

29. Indentation marks the block

Concept

Each condition line ends with a colon :, and the lines that belong to that branch are indented beneath it (four spaces is standard).

Same indentation = same block. Python uses the spacing itself to know where a branch begins and ends - so line up your code carefully.

30. Only ONE branch runs

Concept

An if / elif / else chain runs exactly one branch - the first whose condition is True, or the else if none match. Then it skips the rest.

It is not many separate ifs; it is one decision with several doors, and you go through only one.

31. Watching the others get skipped

Worked example

color = "blue"
if color == "green":
    print("forward")
elif color == "red":
    print("turn")
else:
    print("stop")

Neither the if nor the elif matches

Why: "blue" is not green and not red, so both conditions are False.

The else catches it

Why: Verified by execution: prints stop - and only stop. The forward and turn lines never run.

branchconditionran?
if greenFalseno
elif redFalseno
elsefallbackyes -> stop

32. Watch it run: Watching the others get skipped

Pattern

Step through it

Step through Watching the others get skipped one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: branch is if green
  2. Step 2: branch is elif red
  3. Step 3: branch is else

33. The first true branch wins - order matters

Concept

Because Python takes the first true branch and stops, the order of your conditions changes the result. A broad condition placed too early can swallow the specific ones below it.

34. A checklist you read top-down

Intuition

Think of the branches as a checklist you read from the top. At the first box you can tick 'yes', you stop and do that action - you never read further.

So the most specific question must come first. Put the widest, easiest-to-pass condition last, or it grabs everything before the picky ones get a turn.

35. Grades in the right order

Worked example

score = 85
if score >= 90:
    print("A")
elif score >= 80:
    print("B")
elif score >= 70:
    print("C")

Strictest test first: >= 90

Why: 85 >= 90 is False, so skip A.

Next: >= 80

Why: Verified by execution: 85 >= 80 is True, so it prints B and stops. Highest threshold first is the correct order.

branch85 passes?taken?
score >= 90nono
score >= 80yesyes -> B
score >= 70(not reached)no

36. Watch it run: Grades in the right order

Pattern

Step through it

Step through Grades in the right order one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: branch is score >= 90
  2. Step 2: branch is score >= 80
  3. Step 3: branch is score >= 70

37. Something is wrong here: the widest test first

Anomaly

Predict first

A student writes this, and it looks reasonable:

Same grades, but the easiest condition is checked first.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: A 95 should be an A, but >= 70 is true first and Python stops there.

Put the strictest condition first so it gets the first chance.

Why: A 95 should be an A, but >= 70 is true first and Python stops there. The >= 90 test never runs.

38. Trap: the widest test first

Trap

The trap

Same grades, but the easiest condition is checked first.

score = 95
if score >= 70:
    print("C")
elif score >= 80:
    print("B")
elif score >= 90:
    print("A")

95 passes >= 70 immediately, so it prints C

Why: A 95 should be an A, but >= 70 is true first and Python stops there. The >= 90 test never runs.

branch95 passes?taken?
score >= 70yesyes -> C (wrong!)
score >= 80(not reached)no
score >= 90(not reached)no

The fix

Put the strictest condition first so it gets the first chance.

score = 95
if score >= 90:
    print("A")
elif score >= 80:
    print("B")
elif score >= 70:
    print("C")

Highest threshold first

Why: Now 95 >= 90 is true first, so it correctly prints A. Verified by execution. Order conditions from most specific to least.

branch95 passes?taken?
score >= 90yesyes -> A

39. Break it on purpose: the widest test first

Break the constraint

Discussion prompt

The rule this trap just fixed:

Put the strictest condition first so it gets the first chance.

Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?

Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.

Answer:

A 95 should be an A, but >= 70 is true first and Python stops there. The >= 90 test never runs.

40. and: both must be true

Concept

and combines two conditions and is True only when both are True. If the robot is on AND the path is clear, move.

41. and in action

Worked example

temp = 40
if temp > 30 and temp < 50:
    print("in range")
else:
    print("out of range")

Both halves must hold

Why: Verified by execution: 40 > 30 is True AND 40 < 50 is True, so the whole condition is True - prints in range.

temp > 30temp < 50and result
TrueTrueTrue -> in range
True (60)False (60)False -> out of range

42. or: at least one must be true

Concept

or is True when at least one side is True (it is only False when both are False). If I see red OR yellow, slow down.

43. Restore the missing line: or in action

Fill the middle

Fill in the blanks

From or in action — one line has had its right-hand side removed. Put it back.

color = "yellow"
if color == "red" or color == "yellow":
print("slow down")
else:
print("keep going")

Why: color is what everything below it consumes, so the wrong expression here fails later and somewhere else. Verified by execution: color == "red" is False, but color == "yellow" is True, so or is True - prints slow down.

44. or in action

Worked example

color = "yellow"
if color == "red" or color == "yellow":
    print("slow down")
else:
    print("keep going")

One true side is enough

Why: Verified by execution: color == "red" is False, but color == "yellow" is True, so or is True - prints slow down.

color == redcolor == yellowor result
FalseTrueTrue -> slow down
FalseFalseFalse -> keep going

45. not: flip true and false

Concept

not reverses a condition. not True is False; not False is True. If the path is NOT clear, stop.

46. not in action

Worked example

clear = False
if not clear:
    print("stop")

not flips the value

Why: Verified by execution: clear is False, so not clear is True, and it prints stop.

clearnot clearprints
FalseTruestop
TrueFalse(nothing)

47. Truth table: and / or / not

Concept

The whole logic of and and or, side by side:

ABA and BA or B
TrueTrueTrueTrue
TrueFalseFalseTrue
FalseTrueFalseTrue
FalseFalseFalseFalse

And not simply flips: not True is False, not False is True.

48. Watch it run: Truth table: and / or / not

Pattern

Step through it

Step through Truth table: and / or / not one row at a time. What is driving the change, and what would the row after the last one be?

  1. Step 1: A is True
  2. Step 2: A is True
  3. Step 3: A is False
  4. Step 4: A is False

49. Guess the shape of the answer: Combining tests for a robot rule

Estimation

Predict first

Move forward only when the way is clear AND the battery is not empty.

Commit before you compute: what does Combining tests for a robot rule come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.

Correct: Both parts checked together

Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Verified by execution: clear is True and 20 > 10 is True, so it prints forward.

50. Combining tests for a robot rule

Worked example

Move forward only when the way is clear AND the battery is not empty.

clear = True
battery = 20
if clear and battery > 10:
    print("forward")
else:
    print("hold")

Both parts checked together

Why: Verified by execution: clear is True and 20 > 10 is True, so it prints forward. If either were False, it would hold.

clearbattery > 10and -> action
TrueTrueTrue -> forward
TrueFalse (5)False -> hold
FalseTrueFalse -> hold

51. Work backwards from the answer: Combining tests for a robot rule

Reverse engineer

Discussion prompt

Work backwards. The example finished here:

Both parts checked together

What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.

Hint: Every quantity in the result had to enter somewhere. Account for each one.

Answer:

Move forward only when the way is clear AND the battery is not empty.

52. Something is wrong here: the "or green" bug

Anomaly

Predict first

A student writes this, and it looks reasonable:

Trying to check if the color is red or green - the tempting short way.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: The bare string "green" is always truthy, so the whole condition is ALWAYS true.

Spell out a full comparison on each side of or.

Why: The bare string "green" is always truthy, so the whole condition is ALWAYS true. It prints even for blue - a silent, dangerous bug.

53. Trap: the "or green" bug

Trap

The trap

Trying to check if the color is red or green - the tempting short way.

color = "blue"
if color == "red" or "green":
    print("red or green")

Python reads this as (color == "red") or ("green")

Why: The bare string "green" is always truthy, so the whole condition is ALWAYS true. It prints even for blue - a silent, dangerous bug.

colorcondition isprints?
bluealways Trueyes (wrong!)
anythingalways Trueyes (wrong!)

The fix

Spell out a full comparison on each side of or.

color = "blue"
if color == "red" or color == "green":
    print("red or green")
else:
    print("neither")

Each side is its own complete test

Why: Verified by execution: "blue" is neither, so it prints neither. Rule: never write or "value" - always write or variable == "value".

colorcondition isprints
blueFalse or Falseneither
greenFalse or Truered or green

54. Fill in: prints? for Trap: the "or green" bug

Comparison

Comparison matrix

From Trap: the "or green" bug: refill the prints? column from what you know. The rest of the table is as it appeared.

colorcondition isprints?
bluealways Trueyes (wrong!)
anythingalways Trueyes (wrong!)

55. Cleaner multi-match: the in operator

Concept

Checking many values with or gets long - and invites the bare-or bug. color in ["red", "green", "blue"] asks is color one of these? in a single, safe expression.

It returns True if the value is somewhere in the list, False otherwise - no repeated ==, no always-true trap.

56. Restore the missing line: in fixes the or bug

Fill the middle

Fill in the blanks

From in fixes the or bug — one line has had its right-hand side removed. Put it back.

color = "blue"
if color in ["red", "green"]:
print("warm color")
else:
print("not red or green")

Why: color is what everything below it consumes, so the wrong expression here fails later and somewhere else. Verified by execution: "blue" is not in ["red", "green"], so it prints not red or green.

57. in fixes the or bug

Worked example

color = "blue"
if color in ["red", "green"]:
    print("warm color")
else:
    print("not red or green")

in checks membership against the whole list at once

Why: Verified by execution: "blue" is not in ["red", "green"], so it prints not red or green. This is the clean replacement for color == "red" or color == "green".

expressionvalue
"green" in ["red", "green", "blue"]True
"yellow" in ["red", "green", "blue"]False
"blue" in ["red", "green"]False

58. Chained comparisons

Concept

Python lets you chain comparisons the way math does: 0 <= score <= 100 means score is between 0 and 100. It reads like the math and needs no and.

80 <= score < 90 is the cleanest way to test a band - one expression instead of score >= 80 and score < 90.

59. A grade band with chaining

Worked example

score = 85
print(0 <= score <= 100)
print(80 <= score < 90)
print(90 <= score < 100)

Each chain is one True/False answer

Why: Verified by execution: 85 is inside 0..100 (True), inside the 80s band (True), but not the 90s (False).

expressionvaluemeaning
0 <= score <= 100Truein valid range
80 <= score < 90Truea B (the 80s)
90 <= score < 100Falsenot an A

60. Truthiness: a value can be the condition

Concept

An if doesn't need a comparison - any value works. Python asks is this truthy? Recall from Day 2: 0, "" (empty text), and empty lists are falsy; everything else is truthy.

So if name: means if name is not empty - a clean way to check the robot actually received some input.

61. Checking for empty input

Worked example

name = ""
if name:
    print("hello", name)
else:
    print("no name given")

An empty string is falsy, so the else runs

Why: Verified by execution: name is "", which is falsy, so it prints no name given. With name = "Robo" the truthy if branch would run instead.

nametruthy?branch
""Falseelse -> no name given
"Robo"Trueif -> hello Robo

62. Precedence: not, then and, then or

Concept

When you mix them, Python applies not first, then and, then or. So True or False and False is read as True or (False and False) = True.

When in doubt, add parentheses. (a or b) and c is clearer than trusting the order - and prevents subtle bugs in a robot's rules.

63. Precedence and a logic shortcut

Worked example

print(True or False and False)
print((True or False) and False)
a, b = True, False
print(not (a and b))
print((not a) or (not b))

Parentheses change the meaning

Why: Without them, and binds tighter than or, giving True. With them, (True or False) and False is False.

De Morgan's law: a handy rewrite

Why: Verified by execution: not (a and b) equals (not a) or (not b) - both True here. Pushing a not across and/or flips the operator. Useful for simplifying tangled conditions.

expressionvalue
True or False and FalseTrue
(True or False) and FalseFalse
not (a and b)True
(not a) or (not b)True

64. How to write a decision

Pattern

1. Name the conditions as yes/no questions

Why: Each branch tests something that is clearly True or False, like color == "red".

2. Order from most specific to least

Why: The first true branch wins, so the strictest test goes on top; the catch-all else goes last.

3. Use == to compare, never a single =

Why: One = assigns and is a SyntaxError inside an if. Two == ask whether values are equal.

4. Combine with and / or / not - full comparisons each side

Why: Write color == "red" or color == "green", never or "green". A bare value is always truthy.

5. Add an else as the safety net

Why: It catches every input you did not list - like an unknown color the robot still must handle.

65. What has to be given first: Build it: Maze Robot Brain v1

Missing information

Discussion prompt

Read the color the robot sees and decide a move - the exact logic the camp robot uses.

What do you need to know — or decide — before the first line can be written? List everything the problem has to hand you.

Hint: Anything you would have to invent to get started is a thing the problem must supply.

Answer:

color is a string like "green". That is exactly what == compares against.

66. Build it: Maze Robot Brain v1

Worked example

Read the color the robot sees and decide a move - the exact logic the camp robot uses.

color = input("Color seen: ")
if color == "green":
    print("forward")
elif color == "red":
    print("turn")
else:
    print("stop")

Line 1: input() reads the color as text

Why: color is a string like "green". That is exactly what == compares against.

Lines 2-7: pick the move with if / elif / else

Why: green -> forward, red -> turn, and anything else -> stop. The else is the safety net for colors you did not list.

the robot seesbranchit prints
greenifforward
redelifturn
blue / anything elseelsestop

67. Guess the shape of the answer: Trace the brain on every color

Estimation

Predict first

Run the same logic on four colors. Watch the else catch both blue and an unknown color.

Commit before you compute: what does Trace the brain on every color come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.

Correct: One pass per color, one branch each

Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Verified by execution. green and red hit the if and elif; blue and purple both fall to the else.

68. Trace the brain on every color

Worked example

Run the same logic on four colors. Watch the else catch both blue and an unknown color.

for color in ["green", "red", "blue", "purple"]:
    if color == "green":
        print("forward")
    elif color == "red":
        print("turn")
    else:
        print("stop")

One pass per color, one branch each

Why: Verified by execution. green and red hit the if and elif; blue and purple both fall to the else.

colorbranch takenprints
greenifforward
redelifturn
blueelsestop
purpleelsestop

69. Which is which, by branch taken

Discrimination

Sort into buckets

Sort these by branch taken, from memory, without looking back at Trace the brain on every color. Telling them apart on the spot is the skill; the table is only where the answer happens to be written down.

if
green
elif
red
else
blue; purple
g1
branch taken is "if" for green — that is what the table on "Trace the brain on every color" records, and it is the single property separating this group from the rest.
g2
branch taken is "elif" for red — that is what the table on "Trace the brain on every color" records, and it is the single property separating this group from the rest.
g3
branch taken is "else" for blue, purple — that is what the table on "Trace the brain on every color" records, and it is the single property separating this group from the rest.

70. What is a finite state machine?

Concept

A finite state machine (FSM) is a set of states plus rules for switching between them. At any moment the machine is in exactly one state.

state — One of the modes a machine can be in - like patrol or guard. A finite state machine has a fixed, countable list of them.

transition — A rule that switches the machine from one state to another when something happens - like 'seeing blue moves patrol to guard'.

71. Take the definitions apart: condition vs state

Definition probe

Sort into buckets

Every line below is part of the definition of condition or of state — one or the other, never both. Put each where it belongs.

condition
A True/False expression a decision is based on.; The code under an if runs only when its condition is True.
state
One of the modes a machine can be in - like patrol or guard.; A finite state machine has a fixed, countable list of them.
b1
A True/False expression a decision is based on. The code under an if runs only when its condition is True.
b2
One of the modes a machine can be in - like patrol or guard. A finite state machine has a fixed, countable list of them.

72. Rooms you move between

Intuition

Think of states as rooms in a building and transitions as doors. You are always standing in exactly one room, and certain events let you walk through a door into another.

What you can do depends on which room you are in. The same key (seeing blue) opens a different door depending on where you currently stand.

73. State changes what an input means

Concept

The point of an FSM: the same input produces a different action depending on the current state. Seeing red while patrolling means turn; seeing red while guarding means sound the alarm.

In code, the state is just a variable (like mode), and you check it with the same if / elif tools you already know.

74. Picture it first: A two-state machine: patrol and guard

Picture it

Figure (svg): Two circles labeled PATROL and GUARD, with arrows in both directions each labeled 'sees blue', showing the robot switches between the two states when it sees blue.

Discussion prompt

Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.

Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.

Answer:

Here is the robot's whole brain as a picture: two states, and a blue light flips between them.

75. A two-state machine: patrol and guard

Concept

Here is the robot's whole brain as a picture: two states, and a blue light flips between them.

Figure (svg): Two circles labeled PATROL and GUARD, with arrows in both directions each labeled 'sees blue', showing the robot switches between the two states when it sees blue.

76. What has to be given first: Same color, different action

Missing information

Discussion prompt

Red means turn while patrolling, but alarm while guarding. The state decides.

What do you need to know — or decide — before the first line can be written? List everything the problem has to hand you.

Hint: Anything you would have to invent to get started is a thing the problem must supply.

Answer:

Verified by execution: mode is "guard", so it takes the guard branch, sees red, and prints ALARM - not turn.

77. Same color, different action

Worked example

Red means turn while patrolling, but alarm while guarding. The state decides.

mode = "guard"
color = "red"
if mode == "patrol":
    if color == "red":
        print("turn")
elif mode == "guard":
    if color == "red":
        print("ALARM")

First check the state, then the color

Why: Verified by execution: mode is "guard", so it takes the guard branch, sees red, and prints ALARM - not turn.

modecoloraction
patrolredturn
guardredALARM

78. Guess the shape of the answer: A transition: blue switches the mode

Estimation

Predict first

Seeing blue doesn't just act - it changes the state, by reassigning the mode variable.

Commit before you compute: what does A transition: blue switches the mode come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.

Correct: Trace the state change

Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Verified by execution: prints 'switching to guard' then 'mode is now guard'.

79. A transition: blue switches the mode

Worked example

Seeing blue doesn't just act - it changes the state, by reassigning the mode variable.

mode = "patrol"
color = "blue"
if mode == "patrol":
    if color == "blue":
        mode = "guard"
        print("switching to guard")
elif mode == "guard":
    if color == "blue":
        mode = "patrol"
        print("switching to patrol")
print("mode is now", mode)

Line 5 reassigns the state variable

Why: In patrol, seeing blue runs mode = "guard" - that single assignment IS the transition.

Trace the state change

Why: Verified by execution: prints 'switching to guard' then 'mode is now guard'. The machine has moved rooms.

stepmode
startpatrol
sees blue in patrolguard
printedmode is now guard

80. Work backwards from the answer: A transition: blue switches the mode

Reverse engineer

Discussion prompt

Work backwards. The example finished here:

Trace the state change

What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.

Hint: Every quantity in the result had to enter somewhere. Account for each one.

Answer:

Seeing blue doesn't just act - it changes the state, by reassigning the mode variable.

81. Something is wrong here: forgetting to update the state

Anomaly

Predict first

A student writes this, and it looks reasonable:

Announcing the switch but never changing the mode variable.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: There is no mode = "guard" line, so mode is still "patrol".

Actually reassign the state variable to make the transition real.

Why: There is no mode = "guard" line, so mode is still "patrol". Next time, the robot behaves as if it never switched - a stuck machine.

82. Trap: forgetting to update the state

Trap

The trap

Announcing the switch but never changing the mode variable.

mode = "patrol"
color = "blue"
if mode == "patrol" and color == "blue":
    print("switching to guard")
print("mode is now", mode)

It says it switched, but the state never moved

Why: There is no mode = "guard" line, so mode is still "patrol". Next time, the robot behaves as if it never switched - a stuck machine.

expressionvalue
modepatrol (unchanged!)

The fix

Actually reassign the state variable to make the transition real.

mode = "patrol"
color = "blue"
if mode == "patrol" and color == "blue":
    mode = "guard"
    print("switching to guard")
print("mode is now", mode)

mode = "guard" makes the switch stick

Why: Verified by execution: now mode is "guard" afterward. A transition is only real when the state variable actually changes.

expressionvalue
modeguard

83. Which of these survive contact with Decisions: if / elif / else & Finite-State…?

Two truths and a lie

Sort into buckets

Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.

Holds up
Up to now your code ran straight through, top to bottom. A decision lets it choose: do this only when something is true.; Every decision rests on a condition - an expression that is either True or False (a bool). color == "red" asks: is color equal to red?; == checks for an exact match. "Red" is not equal to "red" - a capital letter is a different character.
Breaks
Trying to check if color is red - with a single =.; Same grades, but the easiest condition is checked first.
sound
These are stated as this lesson states them — each one survives the edge cases Decisions: if / elif / else & Finite-State Thinking puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

84. When if/elif chains get big

Concept

A two-state robot needs a handful of branches. A four-state robot reacting to five colors needs twenty - nested ifs become a wall of code that is hard to read and easy to break.

Two techniques scale far better: a dispatch dictionary for actions, and a transition table for the whole machine. Both turn logic into data.

85. Teach it back: When if/elif chains get big

Explain it

Discussion prompt

Explain When if/elif chains get big to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

A two-state robot needs a handful of branches. A four-state robot reacting to five colors needs twenty - nested ifs become a wall of code that is hard to read and easy to break.

86. Dictionary dispatch: look up the action

Concept

Instead of an if/elif that maps each color to a move, store the map as a dictionary and look it up directly: actions[color].

dispatch table — A dictionary that maps each input to its action, replacing a long if/elif chain with a single lookup. Add a new input by adding a row, not a branch.

87. Term to definition: Decisions: if / elif / else & Finite-State Thinking

Matching

Match the pairs

Match each term to the definition this lesson gave it — not the one you would guess from the word.

  • t1. condition
  • t2. state
  • t3. transition
  • t4. dispatch table
  • d1. A True/False expression a decision is based on. The code under an if runs only when its condition is True.
  • d2. One of the modes a machine can be in - like patrol or guard. A finite state machine has a fixed, countable list of them.
  • d3. A rule that switches the machine from one state to another when something happens - like 'seeing blue moves patrol to guard'.
  • d4. A dictionary that maps each input to its action, replacing a long if/elif chain with a single lookup. Add a new input by adding a row, not a branch.

Why: These are the working definitions of condition, state, transition, dispatch table as Decisions: if / elif / else & Finite-State Thinking uses them. Pairing them correctly is the test of whether you could state each one with the slide switched off.

88. Dispatch replaces if/elif

Worked example

actions = {"green": "forward", "red": "turn", "blue": "stop"}
print(actions["red"])
print(actions.get("purple", "stop"))

One lookup does the whole decision

Why: actions["red"] finds the key "red" and returns "turn" - no branching at all.

.get(key, default) handles unknown inputs

Why: Verified by execution: actions.get("purple", "stop") returns "stop" because purple is not a key. That default replaces the else branch.

expressionvalue
actions["red"]"turn"
actions["green"]"forward"
actions.get("purple", "stop")"stop" (default)

89. Draw the shape of it: Dispatch replaces if/elif

Blank canvas

Draw it

Draw what Dispatch replaces if/elif just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

90. A transition table: the machine as data

Concept

A full FSM also needs the next state. Store the rules as a dictionary keyed by (state, input) whose value is (action, next_state).

Now the machine is data. Adding a state or a color is one new row in the table - not another branch buried inside nested ifs.

91. By analogy: A transition table: the machine as data

Analogy

Discussion prompt

Explain A transition table: the machine as data by analogy to something with no Python in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

A full FSM also needs the next state. Store the rules as a dictionary keyed by (state, input) whose value is (action, next_state).

92. Predict the next row: A table-driven FSM

Pattern

Predict first

The table runs: (patrol, blue) | (switch to guard, guard) · (guard, red) | (ALARM, guard)

In A table-driven FSM, given the rows so far: what is the next one — the row where (mode, color) is (guard, blue)?

Correct: (guard, blue) | (switch to patrol, patrol)

(mode, color)-> (action, next mode)
(patrol, blue)(switch to guard, guard)
(guard, red)(ALARM, guard)
(guard, blue)(switch to patrol, patrol)

Why: The relationship between the columns, not the individual numbers, is what generates the next row. rules[("patrol", "blue")] is the pair ("switch to guard", "guard").

93. A table-driven FSM

Worked example

rules = {
    ("patrol", "green"): ("forward", "patrol"),
    ("patrol", "red"): ("turn", "patrol"),
    ("patrol", "blue"): ("switch to guard", "guard"),
    ("guard", "green"): ("hold", "guard"),
    ("guard", "red"): ("ALARM", "guard"),
    ("guard", "blue"): ("switch to patrol", "patrol"),
}
mode = "patrol"
color = "blue"
action, mode = rules[(mode, color)]
print(action, "->", mode)

One lookup gives BOTH the action and the next state

Why: rules[("patrol", "blue")] is the pair ("switch to guard", "guard"). Unpacking sets action and the new mode in a single line.

The transition is built into the table

Why: Verified by execution: prints switch to guard -> guard. The same row also makes mode become guard - no separate if needed. Every rule lives in one readable table.

(mode, color)-> (action, next mode)
(patrol, blue)(switch to guard, guard)
(guard, red)(ALARM, guard)
(guard, blue)(switch to patrol, patrol)

94. Inspect it line by line: A table-driven FSM

Error analysis

Annotate

Walk the callouts on A table-driven FSM. Each one is a place this is easy to get subtly wrong.

  • rules[("patrol", "blue")] is the pair ("switch to guard", "guard"). Unpacking sets action and the new mode in a single line.
  • Verified by execution: prints switch to guard -> guard. The same row also makes mode become guard - no separate if needed. Every rule lives in one readable table.

95. Two ways to build an FSM - when to use each

Concept

Nested if/elif is clearest for a small machine - two or three states and a few inputs. You can read the whole logic top to bottom.

A transition table wins as the machine grows: many states and inputs, rules that change often, or rules you load from a file. The camp robot starts with ifs and graduates to a table.

96. Break it if you can: Two ways to build an FSM - when to use each

Counterexample

Discussion prompt

A transition table wins as the machine grows: many states and inputs, rules that change often, or rules you load from a file. The camp robot starts with ifs and graduates to a table.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

97. How to build a finite state machine

Pattern

1. List the states

Why: Decide the fixed set of modes, e.g. patrol and guard. Store the current one in a variable like mode.

2. Branch on the state first

Why: Use if mode == ... to pick which set of rules applies right now.

3. Inside each state, decide on the input

Why: A second if/elif on the color (or sensor) chooses the action for that state.

4. Transition by reassigning the state

Why: When an event should switch modes, write mode = "...". Forgetting this leaves the machine stuck.

5. Keep states and inputs spelled exactly

Why: == is exact and case-sensitive, so "guard" must match "guard" everywhere - a typo silently breaks a branch.

98. Where this shows up: Decisions: if / elif / else & Finite-State…

Real world

Discussion prompt

Outside this lesson: where does Decisions: if / elif / else & Finite-State Thinking actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of How to build a finite state machine is doing the work in it.

Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.

Answer:

Pre-COSMOS Day 6 (Cluster 10: Robot Inventors), 2+ hours in depth. Comparisons and booleans; if / elif / else with first-true-branch-wins so order matters; and / or / not (and the classic 'or green' bug); the == vs = trap; advanced techniques (the in operator, chained comparisons, truthiness, operator precedence and De Morgan's law); building the Maze Robot Brain v1; and finite state machines two ways - nested if/elif and table-driven (dictionary dispatch plus a (state, input) -> (action, next_state) transition table).

99. Check yourself: what does == return?

Check

Two comparisons - mind the capital letter.

print(3 == 3)
print("yes" == "Yes")
expressionvalue
3 == 3?
"yes" == "Yes"?

Check your understanding

What does this print, line by line?

  • A. True then False (correct)
  • B. True then True
  • C. True then "yes"
  • D. 3 then yes

Answer: A

Why: == asks 'are these equal?' and returns a bool. 3 == 3 is True. "yes" == "Yes" is False because == is case-sensitive - lowercase y differs from uppercase Y. Verified by execution.

Why B tempts people
== is case-sensitive, so "yes" and "Yes" are not equal - a capital letter is a different character. The second line is False.
Why C tempts people
== always returns True or False, never one of the strings. It compares the values; it does not hand back the text.
Why D tempts people
== does not echo the values back; it reports whether they are equal, as True or False.

100. What each one costs: Check yourself: what does == return?

Trade off

Comparison matrix

From Check yourself: what does == return?: every row here is a choice with a cost. Fill the value column, then say which row you would actually pick and what you give up for it.

expressionvalue
3 == 3?
"yes" == "Yes"?

101. Check yourself: which branch runs?

Check

Pick the single branch that runs.

color = "blue"
if color == "green":
    print("forward")
elif color == "red":
    print("turn")
else:
    print("stop")
coloroutput
"blue"?

Check your understanding

What does this print?

  • A. stop (correct)
  • B. forward
  • C. turn
  • D. forward turn stop

Answer: A

Why: color is "blue", which is not green and not red, so both the if and elif are False and the else branch runs, printing stop. Verified by execution.

Why B tempts people
forward prints only when color == "green". Here color is "blue", so that branch is skipped.
Why C tempts people
turn prints only when color == "red". "blue" is not "red", so this branch is skipped too.
Why D tempts people
Only ONE branch of an if/elif/else runs. Python takes the first true one - or the else - and skips the rest.

102. Check yourself: order matters

Check

A 95 should be an A. What does this buggy code actually print?

score = 95
if score >= 70:
    print("C")
elif score >= 80:
    print("B")
elif score >= 90:
    print("A")
scoreoutput
95?

Check your understanding

What does this print?

  • A. C (correct)
  • B. A
  • C. A B C
  • D. B

Answer: A

Why: The first true branch wins. 95 >= 70 is True, so it prints C and stops - even though 95 also passes the later tests. The fix is to check the strictest condition (>= 90) first. Verified by execution.

Why B tempts people
That is what you want, but the >= 90 test never runs - the >= 70 branch is true first and Python stops there.
Why C tempts people
Only one branch runs, not all three. The first true test (>= 70) wins and the rest are skipped.
Why D tempts people
The >= 80 branch is skipped too. Python stops at the very first true test, which here is >= 70.

103. Check yourself: and

Check

Both parts of the and - decide the output.

temp = 40
if temp > 30 and temp < 50:
    print("OK")
else:
    print("out of range")
temp > 30 and temp < 50value
with temp = 40?

Check your understanding

What does this print?

  • A. OK (correct)
  • B. out of range
  • C. True
  • D. OK out of range

Answer: A

Why: temp is 40. temp > 30 is True AND temp < 50 is True, so the combined condition is True and it prints OK. and needs both sides true. Verified by execution.

Why B tempts people
Both parts are true - 40 is above 30 and below 50 - so the and is true and the if branch runs, not the else.
Why C tempts people
The if prints the string "OK", not the boolean True. The condition is True, which then runs the OK branch.
Why D tempts people
Only one branch runs. Since the condition is true, only OK prints and the else is skipped.

104. Check yourself: the or bug

Check

color is "blue". Look closely at the or.

color = "blue"
if color == "red" or "green":
    print("matched red or green")
the ifruns?
color == "red" or "green"?

Check your understanding

Does this print "matched red or green"?

  • A. Yes - because of a bug (correct)
  • B. No, blue is neither
  • C. It crashes with an error
  • D. Only if color is red

Answer: A

Why: Python reads this as (color == "red") or ("green"). The bare string "green" is always truthy, so the whole condition is always true - it prints even for blue. The fix is color == "red" or color == "green". Verified by execution.

Why B tempts people
You would expect that, but the condition is (color == "red") or ("green"), and "green" is always truthy, so the branch runs no matter what color is.
Why C tempts people
It does not crash - it runs, just incorrectly. That is what makes the bug dangerous: it looks fine and stays quiet.
Why D tempts people
It prints for any color, including blue, because the bare "green" half is always true. Each side of or must be its own full comparison.

105. Check yourself: the state transition

Check

Trace the mode variable.

mode = "patrol"
color = "blue"
if mode == "patrol" and color == "blue":
    mode = "guard"
print(mode)
stepmode
startpatrol
after the if?

Check your understanding

What does this print?

  • A. guard (correct)
  • B. patrol
  • C. blue
  • D. patrol guard

Answer: A

Why: mode starts as "patrol" and color is "blue", so the and condition is true and mode is reassigned to "guard". print(mode) then shows guard. Reassigning the state variable is what makes a finite state machine change states. Verified by execution.

Why B tempts people
The condition is true (patrol and blue), so mode = "guard" runs and replaces the old value. print shows the new state, guard.
Why C tempts people
print(mode) shows the mode variable, not the color. mode became "guard"; color is a separate variable still holding "blue".
Why D tempts people
mode holds one value at a time. It changed from patrol to guard, so only guard remains to print.

106. Fill in: mode for Check yourself: the state transition

Comparison

Comparison matrix

From Check yourself: the state transition: refill the mode column from what you know. The rest of the table is as it appeared.

stepmode
startpatrol
after the if?

107. Check yourself: the in operator

Check

Is the color one of the listed three?

color = "yellow"
print(color in ["red", "green", "blue"])
expressionvalue
color in [...]?

Check your understanding

What does this print?

  • A. False (correct)
  • B. True
  • C. yellow
  • D. Error

Answer: A

Why: in checks whether color is one of the items in the list. "yellow" is not in ["red", "green", "blue"], so it returns False. Verified by execution.

Why B tempts people
"yellow" is not one of red, green, or blue, so the membership test is False, not True.
Why C tempts people
in returns a bool (True or False), not the value you searched for.
Why D tempts people
in is a valid operator for lists and strings - there is no error here.

108. Check yourself: a transition-table lookup

Check

Trace the unpacking on line 2.

rules = {("patrol", "blue"): ("switch", "guard")}
action, mode = rules[("patrol", "blue")]
print(mode)
variablevalue
mode?

Check your understanding

What does this print?

  • A. guard (correct)
  • B. switch
  • C. patrol
  • D. blue

Answer: A

Why: rules[("patrol", "blue")] is the pair ("switch", "guard"). Unpacking sets action to "switch" and mode to "guard", so print(mode) shows guard. Verified by execution.

Why B tempts people
"switch" is the action - it goes into the first variable. The second value, "guard", goes into mode.
Why C tempts people
"patrol" was the OLD state used to look up the rule. The table returns the next state, "guard".
Why D tempts people
blue was the input color in the key, not a value the lookup returns. mode becomes "guard".

109. Connect it up: Decisions: if / elif / else & Finite-State Thinking

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — How to write a decision · How to build a finite state machine · Programs make decisions · A condition is a yes/no question · Comparison operators. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

110. What you can do now

Recap

Conditions return True/False; if / elif / else runs the first true branch (so order matters); and / or / not combine tests; and a finite state machine is states plus transitions you make by reassigning a mode variable.

You wantWriteRemember
compare valuescolor == "red"two ==, not one =
choose a pathif ... elif ... elsefirst true branch wins
both truea and bor = at least one
one of manycolor in ["red", "green"]clean, and dodges the or bug
WRONG orcolor == "red" or "green"always true - a bug
switch statemode = "guard"a transition reassigns the state
a bigger machinerules[(mode, color)]table-driven FSM scales

The big ideas: order your branches most-specific first, give each or side a full comparison, and make a state change real by reassigning the state variable. Now go build the Maze Robot Brain - and give it patrol and guard modes.

Sources

  1. Python 3 Tutorial - More Control Flow Tools (if statements)
  2. Python 3 Library Reference - Boolean Operations and Comparisons
  3. Finite-state machine (states + transitions) - concept reference
  4. All snippets executed under CPython 3.12; outputs and error messages copied from real runs. — Author verification run, 2026-06-18 (Pre-COSMOS Prep Plan, Day 6).

Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108