Pre-COSMOS Day 11 - Functions, part 2 of 2, an advanced session of 50 slides. It picks up where Day 10 left off and goes deep on how small functions cooperate to make a real program. It covers positional against keyword arguments and why defaults must come last, then scope: locals do not leak, parameters are local copies, and assigning to a global raises an UnboundLocalError - with the clean alternative of passing values in and returning them out. From there it covers the accumulator pattern, calling functions inside loops, decomposing a problem into helpers with a main loop, and the random module, using seed for reproducible demos. It culminates in a fully scaffolded your-turn build of Robo-Battle: two robots, a decide(hp) function, and a turn loop that runs until one robot's hp reaches 0, with a randomized-damage stretch. There are five checks, three traps, two real photos, and diagrams of scope and decomposition. Every snippet, including the seeded random calls and the full battle, was run in real Python with the output copied verbatim into the trace tables.
Subject: Python · 83 slides · code lesson
Open the interactive version of this deck · Homework for this lesson
Title
Day 11 · Functions, Part 2 of 2
This is the day it clicks: many small functions, cooperating - exactly how the camp robot's code is organized.
Objectives
Yesterday you wrote single helpers. Today you make them work together into a real program. By the end you can:
random module (and seed for repeatable runs) to build Robo-Battle.Warm-up
Discussion prompt
Before we open Functions: Arguments, Scope & Small Programs: without looking back, what was the main idea of Dictionaries: Mapping Colors to Actions, 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:
Dictionaries as the natural way to map a color to an action or a state to what comes next - exactly how the camp's finite-state robot logic works (the diagnostic rated this fragile). Key-to-value lookup, dict vs list, the KeyError trap (keys not number positions: actions["red"] not actions[0]), safe lookups with .get(key, default) and the in operator, adding/updating keys and len, looping with keys()/values()/items(), and two advanced patterns: the counter/tally and the dict-as-finite-state-machine.
Concept

Real programs aren't one long script. They're several small functions working together - which is exactly how the camp's robot code is organized.
Day 10 gave you the parts: def, parameters, return. Today is assembly - making the parts cooperate without tripping over each other.
The thing that makes cooperation safe is understanding scope - so that's where most of today goes.
Counterexample
Discussion prompt
Real programs aren't one long script. They're several small functions working together - which is exactly how the camp's robot code is organized.
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:
Day 10 gave you the parts: def, parameters, return. Today is assembly - making the parts cooperate without tripping over each other.
Concept
Four ideas, then you build a whole game out of them:
decide(hp), a turn loop.Matching
Match the pairs
From Today's roadmap — match each one to what it actually does. The descriptions have been shuffled.
decide(hp), a turn loop.Why: Arguments, Scope, Functions + loops, Robo-Battle are easy to tell apart while they are sitting next to their descriptions and much harder afterwards, which is what this checks.
Section
Section 1
Concept
Positional: values fill the parameters left-to-right by position. Keyword: you name the parameter, power=9, so position no longer matters.
keyword argument — An argument passed by name, like direction="left". It goes to that exact parameter, so you can skip earlier ones that have defaults.
Worked example
direction and power have defaults, so callers can supply as much or as little as they want.
def move(speed, direction="forward", power=5):
return (speed, direction, power)
print(move(10))
print(move(10, "left"))
print(move(10, power=9))move(10, power=9) skips direction (keeps its default) and sets power by name.
| call | speed, direction, power | returns |
|---|---|---|
| move(10) | 10, forward, 5 | (10, 'forward', 5) |
| move(10, "left") | 10, left, 5 | (10, 'left', 5) |
| move(10, power=9) | 10, forward, 9 | (10, 'forward', 9) |
Comparison
Comparison matrix
From One function, several call styles: refill the speed, direction, power column from what you know. The rest of the table is as it appeared.
| call | speed, direction, power | returns |
|---|---|---|
| move(10) | 10, forward, 5 | (10, 'forward', 5) |
| move(10, "left") | 10, left, 5 | (10, 'left', 5) |
| move(10, power=9) | 10, forward, 9 | (10, 'forward', 9) |
Intuition
Compare set_motor(1, 0, 1) with set_motor(left=1, right=0, brake=1). Same call - but the second one reads like a sentence.
Keyword arguments make a call self-documenting and let you skip the middle settings you don't care about.
Analogy
Discussion prompt
Explain Why keyword arguments help 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:
Compare set_motor(1, 0, 1) with set_motor(left=1, right=0, brake=1). Same call - but the second one reads like a sentence.
Concept
In a def, every parameter with a default must come after all the parameters without one. Otherwise Python can't tell which value belongs where.
default value — A fallback written as name=value in the def. Required (no-default) parameters must be listed before any defaulted ones.
Definition probe
Sort into buckets
Every line below is part of the definition of keyword argument or of default value — one or the other, never both. Put each where it belongs.
Worked example
You can start positional, then switch to keyword - but never go back.
def move(speed, direction="forward", power=5):
return (speed, direction, power)
print(move(speed=10, direction="right"))
print(move(10, "left", 9))All-keyword (line 4) and all-positional (line 5) both work.
| call | returns |
|---|---|
| move(speed=10, direction="right") | (10, 'right', 5) |
| move(10, "left", 9) | (10, 'left', 9) |
Trade off
Comparison matrix
From Mixing positional and keyword in one call: every row here is a choice with a cost. Fill the returns column, then say which row you would actually pick and what you give up for it.
| call | returns |
|---|---|
| move(speed=10, direction="right") | (10, 'right', 5) |
| move(10, "left", 9) | (10, 'left', 9) |
Anomaly
Predict first
A student writes this, and it looks reasonable:
Once you go keyword, you can't drop back to positional.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: After speed=10 (keyword), the bare "left" is positional again.
Keep positionals first, then keywords - or go all keyword.
Why: After speed=10 (keyword), the bare "left" is positional again.
Trap
Once you go keyword, you can't drop back to positional.
Call move(speed=10, "left")
Why: After speed=10 (keyword), the bare "left" is positional again.
Python refuses before it even runs
Why: SyntaxError: positional argument follows keyword argument.
Keep positionals first, then keywords - or go all keyword.
Call move(10, "left")
Why: Both positional, in order - fine.
or move(speed=10, direction="left")
Why: All keyword - also fine, and clearer.
Ranking
Put in order
These are the steps of Calling a function cleanly, scrambled. Put them back in order before the next slide shows you.
def.name=value) - never a positional after a keyword.def itself, put required parameters before defaulted ones.Why: This is the order the recipe itself gives. Recalling the sequence without the slide in front of you is the difference between recognising the method and being able to run it — most of what goes wrong in practice is a step done out of turn.
Pattern
A reliable order for every call you write:
def.name=value) - never a positional after a keyword.def itself, put required parameters before defaulted ones.Edge cases
Discussion prompt
Calling a function cleanly works on the cases you have just seen. Push it to the edge: what is the most degenerate input it still handles — empty, zero, one item, everything equal — and what is the first case where it stops being true? Name the case, not just "it breaks".
Hint: Try the smallest legal input, then the largest, then the one where two things collide. Methods are specified at their edges; the middle takes care of itself.
Answer:
def.name=value) - never a positional after a keyword.def itself, put required parameters before defaulted ones.Check
Recall def move(speed, direction="forward", power=5).
Check your understanding
What does move(10, power=9) return?
Answer: A
Why: speed=10 fills positionally, direction keeps its default 'forward', and power=9 sets power by name. Result: (10, 'forward', 9).
Section
Section 2
Concept
A variable created inside a function is local: it's born when the function starts and gone when it ends. Code outside can't see it.
scope — Where a name is visible. Names made inside a function live in that function's local scope only; names at the top level are global.
Explain it
Discussion prompt
Explain Local vs global 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 variable created inside a function is local: it's born when the function starts and gone when it ends. Code outside can't see it.
Picture it
Figure (svg): An outer box labeled your program contains an inner box labeled function with a local variable x that cannot be seen outside
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:
A function is a room. Variables you make inside stay in the room; when the function ends, the room is torn down and they're gone. The only thing that leaves is what you return (hand out the door).
Intuition
A function is a room. Variables you make inside stay in the room; when the function ends, the room is torn down and they're gone. The only thing that leaves is what you return (hand out the door).
Figure (svg): An outer box labeled your program contains an inner box labeled function with a local variable x that cannot be seen outside
Worked example
x is made inside f. Reading it outside is an error.
def f():
x = 5
return x
print(f())
print(x)Line 5 works (the return value); line 6 fails - x doesn't exist out here.
| line | result |
|---|---|
| print(f()) | 5 (the returned value) |
| print(x) | NameError: name 'x' is not defined |
Concept
When you pass a number in, the parameter is a fresh local copy. Changing it inside does not touch the caller's variable.
So a function can't secretly reach out and rewrite your variables. If you want a new value, the function must return it.
Worked example
drain lowers its own copy of b. The outside battery never moves.
def drain(b):
b = b - 5
return b
battery = 20
drain(battery)
print(battery)We called drain but threw the result away, and battery is untouched.
| line | battery is | note |
|---|---|---|
| battery = 20 | 20 | the caller's variable |
| drain(battery) | 20 | b is a separate copy; result discarded |
| print(battery) | 20 | unchanged |
Anomaly
Predict first
A student writes this, and it looks reasonable:
Calling a function and expecting your variable to update on its own.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Inside, b = b - 5 changes only the local copy b.
Catch the return value back into your variable.
Why: Inside, b = b - 5 changes only the local copy b.
Trap
Calling a function and expecting your variable to update on its own.
battery = 20, then drain(battery)
Why: Inside, b = b - 5 changes only the local copy b.
print(battery) → 20
Why: The caller's battery never moved - the new value was thrown away.
Catch the return value back into your variable.
battery = drain(battery)
Why: The function hands the new value out; you store it back in battery.
print(battery) → 15
Why: State flows out through return, not by reaching into the function.
Break the constraint
Discussion prompt
The rule this trap just fixed:
The function hands the new value out; you store it back in battery.
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:
Inside, b = b - 5 changes only the local copy b.
Concept
Don't fight scope - use it. The safe way to share state between functions:
hp = take_damage(hp, 5)).Worked example
Each call returns the new hp; we store it back each time.
def take_damage(hp, dmg):
return hp - dmg
hp = 20
hp = take_damage(hp, 5)
hp = take_damage(hp, 8)
print(hp)hp is reassigned each time - that's how the value persists.
| line | returns | hp now |
|---|---|---|
| hp = 20 | - | 20 |
| hp = take_damage(hp, 5) | 15 | 15 |
| hp = take_damage(hp, 8) | 7 | 7 |
Anomaly
Predict first
A student writes this, and it looks reasonable:
Even a correct return is wasted if you don't catch it.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: It computes 15 and hands it back - but nothing catches it, so it vanishes.
Assign the result back into your variable.
Why: It computes 15 and hands it back - but nothing catches it, so it vanishes.
Trap
Even a correct return is wasted if you don't catch it.
take_damage(hp, 5) on its own line
Why: It computes 15 and hands it back - but nothing catches it, so it vanishes.
hp is still 20
Why: Calling a function does not change your variable; only assignment does.
Assign the result back into your variable.
hp = take_damage(hp, 5)
Why: The returned 15 is stored in hp.
hp is now 15
Why: The = is what makes the new value stick.
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.
set_motor(1, 0, 1) with set_motor(left=1, right=0, brake=1). Same call - but the second one reads like a sentence.Elimination
Eliminate the wrong options
What happens? def f(): x = 5 f() print(x)
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: x is created inside f(), so it is local - it stops existing when f() ends. print(x) outside raises NameError: name 'x' is not defined.
Check
Think about where x lives.
Check your understanding
What happens?
def f():
x = 5
f()
print(x)
Answer: A
Why: x is created inside f(), so it is local - it stops existing when f() ends. print(x) outside raises NameError: name 'x' is not defined.
Section
Section 3
Concept

A program comes alive when a loop calls a function over and over - one decision per pass.
The loop is the when; the function is the what. Together they're the robot's heartbeat.
Worked example
One helper, called once per color in the list.
def decide(color):
if color == "red":
return "turn"
return "forward"
for c in ["red", "green", "red"]:
print(decide(c))return ends the function each pass - the loop keeps going.
| pass | c | decide(c) prints |
|---|---|---|
| 1 | red | turn |
| 2 | green | forward |
| 3 | red | turn |
Pattern
Step through it
Step through decide() inside a for loop one row at a time. What is driving the change, and what would the row after the last one be?
Concept
Keep a running value in a variable, and on each loop pass reassign it from a function's return. The value carries forward, pass to pass.
accumulator — A variable that holds a running result across a loop, updated each pass - here, battery = drain(battery, cost).
Sorting
Sort into buckets
These are the pieces of Functions: Arguments, Scope & Small Programs, out of order. Put each one back under the part of the lesson it belongs to.
Worked example
battery is the accumulator; each pass costs a different amount.
def drain(b, cost):
return b - cost
battery = 20
for cost in [3, 5, 2]:
battery = drain(battery, cost)
print(battery)Each pass feeds the previous battery back in - that's the accumulation.
| pass | cost | battery after |
|---|---|---|
| start | - | 20 |
| 1 | 3 | 17 |
| 2 | 5 | 12 |
| 3 | 2 | 10 |
Pattern
Step through it
Step through Draining the battery over a loop one row at a time. What is driving the change, and what would the row after the last one be?
Intuition
Every game and every robot controller is this shape: a loop that beats, and on each beat it calls functions to decide and update.
Robo-Battle, coming up, is exactly that: a loop of turns, each turn calling decide and applying the result.
Prediction
Predict first
def decide(color): if color == "red": return "turn" return "forward" for c in ["red", "red", "green"]: print(decide(c)) What prints?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: turn, turn, forward
Why: decide is called each pass: 'red' -> turn, 'red' -> turn, 'green' -> forward. return ends the function call, not the loop, so all three lines print.
Check
Trace it pass by pass.
Check your understanding
def decide(color):
if color == "red":
return "turn"
return "forward"
for c in ["red", "red", "green"]:
print(decide(c))
What prints?
Answer: A
Why: decide is called each pass: 'red' -> turn, 'red' -> turn, 'green' -> forward. return ends the function call, not the loop, so all three lines print.
Section
Section 4
Picture it
Figure (svg): A box labeled run_game branches down into three smaller boxes decide, power, and take_turn
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:
Don't write one giant block. Ask: what are the small jobs? Give each its own function with a clear name and a clear return.
Concept
Don't write one giant block. Ask: what are the small jobs? Give each its own function with a clear name and a clear return.
Figure (svg): A box labeled run_game branches down into three smaller boxes decide, power, and take_turn
Concept
The helpers do the small jobs; a main loop ties them together and keeps the state moving. That's the whole architecture of a small program.
Read it top-down: the loop says what order things happen, the helpers say how each step works.
Worked example
status calls is_low - a small helper feeding a bigger one.
def is_low(b):
return b < 10
def status(b):
if is_low(b):
return "charge"
return "go"
print(status(8), status(20))status(8): is_low(8) is True -> "charge". status(20): False -> "go".
| call | is_low(b) | returns |
|---|---|---|
| status(8) | True | charge |
| status(20) | False | go |
Comparison
Comparison matrix
From A two-function mini program: refill the returns column from what you know. The rest of the table is as it appeared.
| call | is_low(b) | returns |
|---|---|---|
| status(8) | True | charge |
| status(20) | False | go |
Section
Section 5
Concept
import random once at the top, then random.randint(a, b) gives a whole number from a to b - including both ends.
random.randint(a, b) — Returns a random integer N with a <= N <= b. Unlike range(), the top value b CAN come up.
Matching
Match the pairs
Match each term to the definition this lesson gave it — not the one you would guess from the word.
Why: These are the working definitions of keyword argument, default value, scope, accumulator, random.randint(a, b) as Functions: Arguments, Scope & Small Programs uses them. Pairing them correctly is the test of whether you could state each one with the slide switched off.
Worked example
random.seed(7) makes the 'random' numbers come out the same every run - perfect for testing and for matching this slide.
import random
random.seed(7)
for _ in range(5):
print(random.randint(1, 6), end=" ")With seed 7, these five rolls are fixed.
| roll | result (seed 7) |
|---|---|
| 1 | 3 |
| 2 | 2 |
| 3 | 4 |
| 4 | 6 |
| 5 | 1 |
Pattern
Step through it
Step through Repeatable randomness with seed one row at a time. What is driving the change, and what would the row after the last one be?
Concept
Without a seed, every run differs - great for a real game, but awful for debugging. Seeding pins the sequence so you can reproduce a bug, or so your output matches a teammate's.
Set the seed once, at the top, before any randint calls.
Explain it
Discussion prompt
Explain Why seed first 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:
Without a seed, every run differs - great for a real game, but awful for debugging. Seeding pins the sequence so you can reproduce a bug, or so your output matches a teammate's.
Prediction
Predict first
random.randint(1, 6) can return which values?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: 1, 2, 3, 4, 5, or 6
Why: random.randint(a, b) includes BOTH ends, so 1 through 6 - exactly like rolling a die.
Check
Careful - this is where range() habits bite.
Check your understanding
random.randint(1, 6) can return which values?
Answer: A
Why: random.randint(a, b) includes BOTH ends, so 1 through 6 - exactly like rolling a die.
Section
Section 6 · Your turn
Concept
You'll write two helpers, then a loop that runs the rounds until one robot's hp hits 0. Type every line, run after each helper, and read errors - don't erase them.
| # | piece | job |
|---|---|---|
| 1 | decide(hp) | return "defend" if hp < 10, else "attack" |
| 2 | power(move) | return 6 for attack, 2 for defend |
| 3 | the turn loop | alternate A/B until one hp reaches 0 |
Analogy
Discussion prompt
Explain The build: two robots, taking turns 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:
You'll write two helpers, then a loop that runs the rounds until one robot's hp hits 0. Type every line, run after each helper, and read errors - don't erase them.
Worked example
Your turn: write decide(hp) that returns "defend" when hp < 10, otherwise "attack". Predict decide(20).
Hint: if hp < 10: return "defend" then a plain return "attack" below it.
def decide(hp):
if hp < 10:
return "defend"
return "attack"| call | returns |
|---|---|
| decide(20) | attack |
| decide(5) | defend |
Worked example
Your turn: write power(move) (6 for attack, 2 for defend), then use it to lower the enemy's hp by that much.
Hint: if move == "attack": return 6 then return 2. Apply it: enemy = enemy - power(move).
def power(move):
if move == "attack":
return 6
return 2
enemy = 20
enemy = enemy - power("attack")
print(enemy)| call | returns | enemy after |
|---|---|---|
| power("attack") | 6 | 20 - 6 = 14 |
| power("defend") | 2 | (would be 18) |
Worked example
Your turn: alternate turns in a while loop until one hp reaches 0. Flip a turn flag each pass.
Hint: while hp_a > 0 and hp_b > 0: then if turn == "A": ... else: ..., and switch turn at the end of each branch.
while hp_a > 0 and hp_b > 0:
if turn == "A":
move = decide(hp_a)
hp_b = hp_b - power(move)
print("A", move, "B-hp", hp_b)
turn = "B"
else:
move = decide(hp_b)
hp_a = hp_a - power(move)
print("B", move, "A-hp", hp_a)
turn = "A"| whose turn | decide uses | result |
|---|---|---|
| A | hp_a | hit B for power(move) |
| B | hp_b | hit A for power(move) |
Worked example
Both start at 20, A goes first. Watch a robot start defending once its hp drops below 10.
hp_a = 20
hp_b = 20
turn = "A"
while hp_a > 0 and hp_b > 0:
if turn == "A":
move = decide(hp_a)
hp_b = hp_b - power(move)
print("A", move, "B-hp", hp_b)
turn = "B"
else:
move = decide(hp_b)
hp_a = hp_a - power(move)
print("B", move, "A-hp", hp_a)
turn = "A"
print("Winner", "A" if hp_a > 0 else "B")When B's hp is 8 and 2 (both < 10) it defends, doing only 2 to A.
| turn | move | result |
|---|---|---|
| A | attack | B-hp 14 |
| B | attack | A-hp 14 |
| A | attack | B-hp 8 |
| B | defend | A-hp 12 |
| A | attack | B-hp 2 |
| B | defend | A-hp 10 |
| A | attack | B-hp -4 → Winner A |
If yours prints those rows and Winner A - you built a whole game from cooperating functions.
Trade off
Comparison matrix
From Put it together: Robo-Battle: every row here is a choice with a cost. Fill the move column, then say which row you would actually pick and what you give up for it.
| turn | move | result |
|---|---|---|
| A | attack | B-hp 14 |
| B | attack | A-hp 14 |
| A | attack | B-hp 8 |
| B | defend | A-hp 12 |
| A | attack | B-hp 2 |
| B | defend | A-hp 10 |
| A | attack | B-hp -4 → Winner A |
Elimination
Eliminate the wrong options
Both robots start at hp 20 and A goes first. On turn 1, what does A do, and what is B's hp right after?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: hp_a is 20, which is not < 10, so decide returns 'attack'. An attack does 6, so B goes 20 - 6 = 14.
Check
Use power(attack)=6, power(defend)=2, and decide: defend if hp < 10.
Check your understanding
Both robots start at hp 20 and A goes first. On turn 1, what does A do, and what is B's hp right after?
Answer: A
Why: hp_a is 20, which is not < 10, so decide returns 'attack'. An attack does 6, so B goes 20 - 6 = 14.
Worked example
Stretch: make attacks do a random 4-8 and defends 1-3. Seed first so your run matches.
Hint: import random, random.seed(11), then return random.randint(4, 8) for attack.
import random
random.seed(11)
def power(move):
if move == "attack":
return random.randint(4, 8)
return random.randint(1, 3)
# ...same battle loop as before, printing the damage...| turn | move | dmg | result |
|---|---|---|---|
| A | attack | 7 | B-hp 13 |
| B | attack | 8 | A-hp 12 |
| A | attack | 7 | B-hp 6 |
| B | defend | 2 | A-hp 10 |
| A | attack | 8 | B-hp -2 → Winner A |
Comparison
Comparison matrix
From Stretch — random damage with a seed: refill the result column from what you know. The rest of the table is as it appeared.
| turn | move | dmg | result |
|---|---|---|---|
| A | attack | 7 | B-hp 13 |
| B | attack | 8 | A-hp 12 |
| A | attack | 7 | B-hp 6 |
| B | defend | 2 | A-hp 10 |
| A | attack | 8 | B-hp -2 → Winner A |
Concept
Explain your program out loud, in function terms:
power(move)'s return value get used?while loop know when to stop?If you can answer all four, you've got functions, scope, and small-program design cold.
Counterexample
Discussion prompt
Explain your program out loud, in function terms:
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:
If you can answer all four, you've got functions, scope, and small-program design cold.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — Arguments, Up Close · Scope · Functions Inside Loops · Designing a Small Program · A Pinch of Randomness · Build It: Robo-Battle. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
random (seeded).| idea | the move |
|---|---|
| name an argument | power=9 |
| a value made inside stays inside | local scope |
| update a variable | hp = take_damage(hp, 5) |
| run rounds | while ...: call helpers |
| dice roll 1-6 | random.randint(1, 6) |
That's both function days done - you can now read and write the kind of multi-function code the robot actually runs.
Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.