cat posts/en/python-lernen-03-entscheidungen-und-schleifen.md
Learning Python (Part 3): Decisions and loops
Comparisons, conditions, and loops, plus a game loop that lets the dungeon respond to commands and change its state during play.
Up to and including part 2, our program ran stubbornly from top to bottom. It could store and change values, but every time it started, it ran the same statements in the same order.
Today the dungeon learns to make decisions and to repeat statements. For that, we use conditions and loops. By the end, our text adventure has a game loop that waits for commands and responds differently to the player's input.
Comparisons return Booleans
Before Python can make a decision, it needs a condition. To start, we'll mainly
use comparisons for that. Their result is either True or False.
You already know these Booleans from part 2 as the bool data type:
>>> 100 > 50
True
>>> 100 < 50
False
>>> 100 == 100
True
There are several operators for comparisons:
| Operator | Meaning | Example |
|---|---|---|
== |
equal to | hp == 100 |
!= |
not equal to | hp != 0 |
> |
greater than | gold > 50 |
< |
less than | hp < 25 |
>= |
greater than or equal to | level >= 5 |
<= |
less than or equal to | hp <= 25 |
You can assign the result of a comparison to a variable like any other value:
hp = 20
ist_verletzt = hp < 100
print(ist_verletzt)
The output is:
True
ist_verletzt is German for “is injured.”
= and == aren't the same
A single equals sign assigns a value to a name:
hp = 100
A double equals sign, on the other hand, compares two values:
hp == 100
So the two expressions do completely different jobs:
hp = 100assigns the value100tohp.hp == 100checks whetherhphas the value100.
Mixing up = and == happens easily when you're starting out. Depending on
where it happens, it leads to a syntax error or just to different code than you
intended.
Conditions with if
With if, you run a block of code only if a condition evaluates to true:
hp = 20
if hp <= 25:
print("Careful, you're badly injured!")
Since 20 <= 25 gives True, the indented line runs.
If the adventurer has 80 hit points instead, the comparison is False.
Python skips the indented block:
hp = 80
if hp <= 25:
print("Careful, you're badly injured!")
print(f"You have {hp} hit points.")
The output is:
You have 80 hit points.
Indentation forms code blocks
The if condition is followed by a colon. The statements that belong to the
if are indented:
if hp <= 25:
print("Careful!")
print("You should heal yourself.")
print("This line always runs.")
The two indented print statements together form a code block. They run only
if the condition is met.
The last line isn't indented, so it no longer belongs to the if block. It runs
regardless of the condition.
Python code is usually indented with four spaces. Most code editors do this
automatically as soon as you press Enter after the colon.
Multiple cases with elif and else
With elif, you can check further conditions. The abbreviation stands for
else if. A final else kicks in if none of the previous conditions was met:
hp = 20
if hp <= 0:
print("You have been defeated.")
elif hp <= 25:
print("Your condition is critical!")
else:
print("You can keep fighting.")
Python checks the conditions from top to bottom:
- Is
hpless than or equal to0? - If not: Is
hpless than or equal to25? - If that isn't true either: Run the
elseblock.
As soon as a condition evaluates to true, Python runs the matching block. The
remaining branches of this if/elif/else chain are skipped.
The order of the conditions matters
The more specific condition should often come first:
if hp <= 0:
print("You have been defeated.")
elif hp <= 25:
print("Your condition is critical!")
If we checked hp <= 25 first, that condition would also be true at 0 or
negative hit points. Python would run that block and never get to the defeat
message.
Combining conditions
With and, or, and not, you can combine conditions.
and: Both conditions must be met
hp = 50
hat_schluessel = True
if hp > 0 and hat_schluessel:
print("You can open the locked door.")
The whole expression is true only if the adventurer still has hit points and
has the key (hat_schluessel is German for “has key”).
You could also write hat_schluessel == True. With a Boolean variable, though,
this comparison is unnecessary. hat_schluessel itself already gives True or
False.
or: At least one condition must be met
gold = 100
hat_schluessel = False
if gold >= 100 or hat_schluessel:
print("You can get past the guard.")
The expression is true because the adventurer has enough gold. That
hat_schluessel has the value False doesn't matter in this case.
not: Flipping a Boolean
tuer_verschlossen = False
if not tuer_verschlossen:
print("The door is already open.")
not flips the Boolean:
TruebecomesFalse.FalsebecomesTrue.
Since tuer_verschlossen (door locked) is False here, not tuer_verschlossen
gives True.
while: Repeating as long as a condition is met
A while loop repeats its code block as long as its condition evaluates to
true:
runden = 3
while runden > 0:
print(f"Rounds left: {runden}")
runden = runden - 1
print("The fight is over.")
The output is:
Rounds left: 3
Rounds left: 2
Rounds left: 1
The fight is over.
On each pass, runden (rounds) goes down by 1. As soon as the variable
reaches 0, runden > 0 is no longer true, and the loop ends.
Watch out for infinite loops
If you forget to change runden, the condition stays true forever:
runden = 3
while runden > 0:
print(f"Rounds left: {runden}")
This loop runs on and on because runden keeps the value 3.
You can usually stop a running Python program in the terminal with
Ctrl+C.
for: Going through values one by one
With a for loop, you can go through several values one after another. For our
first example, we use range(...), which gives us a sequence of numbers:
for runde in range(1, 4):
print(f"Round {runde}")
The output is:
Round 1
Round 2
Round 3
range(1, 4) starts at 1 and ends before 4. So the stop value itself
isn't included.
You can also specify a step:
for zahl in range(3, 0, -1):
print(zahl)
print("Go!")
The output is:
3
2
1
Go!
The three values of range(...) mean:
range(start, stop, schritt)
start: the first valuestop: the limit, which isn't includedschritt: the change from one value to the next (German for “step”)
Since the step is -1, the loop counts backward.
A for loop isn't limited to numbers, though. In general, it can go through the
elements of any iterable. Later on, we'll mainly use it for collections such as
lists and dictionaries.
Controlling loops with break and continue
With break, you end the current loop immediately:
while True:
befehl = input("> ")
if befehl == "quit":
break
print(f"You entered {befehl}.")
print("The game has ended.")
The condition of while True is always true. Without break, the loop would
keep running forever.
As soon as the player types quit, break runs, and Python continues the
program after the loop. befehl is German for command.
With continue, you skip the rest of the code in the current pass and start the
next one:
for zahl in range(1, 6):
if zahl == 3:
continue
print(zahl)
The output is:
1
2
4
5
At the value 3, Python runs continue. So the print statement in that pass
is skipped.
The dungeon, step 3
Now we'll use these basics to build a simple game loop.
Open dungeon.py and replace the previous content with the following code:
# Dungeon—Part 3: Decisions and game loop
print("You stand before the rusty gate of a forgotten dungeon.")
print("A cold draft blows toward you.")
name = input("What's your name, adventurer? ")
gold = int(input("How many gold coins are you bringing? "))
hp = 100
max_hp = 100
print()
print(f"Welcome, {name}!")
print(f"HP: {hp}/{max_hp} | Gold: {gold}")
print()
print("You're standing in a dark hall.")
print("Passages lead north and east.")
print("Available commands: north, east, status, quit")
while True:
befehl = input("\n> ").strip().lower()
if befehl == "quit":
print("You leave the dungeon. Until next time.")
break
elif befehl == "north":
print("You head north and reach a locked door.")
elif befehl == "east":
print("You sneak east and surprise a goblin.")
schaden = 25
hp = max(hp - schaden, 0)
print(f"The goblin hits you. You lose {schaden} hit points.")
print(f"HP: {hp}/{max_hp}")
if hp == 0:
print("You sink to the ground. Your adventure ends here.")
break
elif befehl == "status":
print(f"{name} | HP: {hp}/{max_hp} | Gold: {gold}")
if hp <= 25:
print("Your condition is critical!")
elif hp < max_hp:
print("You're injured, but you can keep fighting.")
else:
print("You're unharmed.")
else:
print("I don't understand that.")
print("Available commands: north, east, status, quit")
Run the program:
python dungeon.py
One possible run looks like this:
You stand before the rusty gate of a forgotten dungeon.
A cold draft blows toward you.
What's your name, adventurer? Karl
How many gold coins are you bringing? 50
Welcome, Karl!
HP: 100/100 | Gold: 50
You're standing in a dark hall.
Passages lead north and east.
Available commands: north, east, status, quit
> east
You sneak east and surprise a goblin.
The goblin hits you. You lose 25 hit points.
HP: 75/100
> status
Karl | HP: 75/100 | Gold: 50
You're injured, but you can keep fighting.
> north
You head north and reach a locked door.
> quit
You leave the dungeon. Until next time.
What happens in the game loop
The heart of our game is this loop:
while True:
befehl = input("\n> ").strip().lower()
while True starts a loop whose condition is always true. On each pass,
input(...) waits for a new command. The loop ends only when one of our break
statements runs.
The two string methods prepare the input for the comparison:
.strip()
.lower()
strip() removes spaces and other whitespace characters at the start and end.
lower() converts uppercase letters to lowercase.
That way, inputs like these are treated the same:
east
EAST
East
Then the if/elif/else chain checks which command the player entered.
The east command changes the player state:
hp = max(hp - schaden, 0)
First, the damage is subtracted from the hit points. max(...) then returns the
larger of the two values. That way, hp can't drop below 0 here.
If the adventurer has no hit points left, break ends the game loop:
if hp == 0:
print("You sink to the ground. Your adventure ends here.")
break
The status command contains a nested if: Inside the elif block that was
already selected, another condition is checked.
elif befehl == "status":
print(f"{name} | HP: {hp}/{max_hp} | Gold: {gold}")
if hp <= 25:
print("Your condition is critical!")
This way, the dungeon can first respond to the command and then print a fitting message depending on the current hit points.
Pitfalls
-
Using
=instead of==: A single=assigns a value. For a comparison, you need==. -
Forgetting the colon:
if,elif,else,while, andformust be followed by a colon. -
Indenting code incorrectly: The indentation determines which statements belong to a block. Stick to four spaces, and don't mix tabs and spaces.
-
Checking conditions in the wrong order: A more general condition can catch a more specific one. For example, check
hp <= 0beforehp <= 25. -
Building an infinite loop: A
whileloop ends only if its condition eventually evaluates to false or the loop is ended some other way. Withwhile True, our example needsbreakfor that. -
Using
breakoutside a loop:breakonly works inside awhileorforloop. -
Forgetting that input can differ in letter case: Without
.lower(),"east"and"EAST"would be two different strings.
Exercises
1. Use a healing potion
Add a heal command to the game loop. It should give the adventurer back 20
hit points, but never more than max_hp.
Solution
Add another `elif` block before the final `else`:elif befehl == "heal":
heilung = 20
hp = min(hp + heilung, max_hp)
print("You drink a healing potion.")
print(f"HP: {hp}/{max_hp}")
2. Program a countdown
Write a for loop that counts down from 3 to 1 and then prints "Go!".
Solution
for zahl in range(3, 0, -1):
print(zahl)
print("Go!")
Going deeper
For branching on values, Python 3.10 and later also offers match and case.
Depending on the problem, that can be easier to read than a long if/elif
chain:
match/case: Structural pattern matching
Next up
Right now, our rooms still consist of individual if and elif blocks. With
every new room and command, the game loop would get longer and harder to follow.
That's why, in part 4, you learn about collections: lists and dictionaries. With them, we describe rooms, exits, and a real inventory as data, instead of hard-coding every possible path into the game loop.
Keyboard shortcuts
- j k
- scroll down / up
- n p
- next / previous section
- g G
- start / end of the article
- t
- show outline
- ?
- show this help
- Esc
- close
0 comments
No comments yet. Be the first!
Sign in to leave a comment.