cat posts/python-lernen-03-entscheidungen-und-schleifen.md
Python lernen (Teil 3): Entscheidungen und Schleifen
Vergleiche, Bedingungen und Schleifen – mit einem Game-Loop, durch den der Dungeon auf Befehle reagiert und seinen State während des Spiels verändert.
Bis einschließlich Teil 2 lief unser Programm stur von oben nach unten. Es konnte Werte speichern und verändern, führte aber bei jedem Start dieselben Anweisungen in derselben Reihenfolge aus.
Heute lernt der Dungeon, Entscheidungen zu treffen und Anweisungen zu wiederholen. Dafür verwenden wir Bedingungen und Schleifen. Am Ende besitzt unser Text-Adventure einen Game-Loop, der auf Befehle wartet und unterschiedlich auf die Eingaben des Spielers reagiert.
Vergleiche liefern Booleans
Bevor Python eine Entscheidung treffen kann, braucht es eine Bedingung. Für den
Anfang verwenden wir dafür vor allem Vergleiche. Ihr Ergebnis ist entweder
True oder False.
Diese Booleans kennst Du bereits aus Teil 2 als Datentyp bool:
>>> 100 > 50
True
>>> 100 < 50
False
>>> 100 == 100
True
Für Vergleiche stehen verschiedene Operatoren zur Verfügung:
| Operator | Bedeutung | Beispiel |
|---|---|---|
== |
gleich | hp == 100 |
!= |
ungleich | hp != 0 |
> |
größer als | gold > 50 |
< |
kleiner als | hp < 25 |
>= |
größer oder gleich | level >= 5 |
<= |
kleiner oder gleich | hp <= 25 |
Das Ergebnis eines Vergleichs kannst Du wie jeden anderen Wert einer Variablen zuweisen:
hp = 20
ist_verletzt = hp < 100
print(ist_verletzt)
Die Ausgabe lautet:
True
= und == sind nicht das Gleiche
Ein einzelnes Gleichheitszeichen weist einem Namen einen Wert zu:
hp = 100
Ein doppeltes Gleichheitszeichen vergleicht dagegen zwei Werte:
hp == 100
Die beiden Ausdrücke haben also völlig unterschiedliche Aufgaben:
hp = 100weisthpden Wert100zu.hp == 100prüft, obhpden Wert100hat.
Die Verwechslung von = und == ist beim Einstieg schnell passiert und führt
je nach Stelle zu einem Syntaxfehler oder schlicht zu anderem Code als
beabsichtigt.
Bedingungen mit if
Mit if führst Du einen Code-Block nur dann aus, wenn eine Bedingung als wahr
ausgewertet wird:
hp = 20
if hp <= 25:
print("Vorsicht, Du bist schwer verletzt!")
Da 20 <= 25 den Wert True ergibt, wird die eingerückte Zeile ausgeführt.
Besitzt der Abenteurer dagegen 80 Lebenspunkte, ist der Vergleich False.
Python überspringt den eingerückten Block:
hp = 80
if hp <= 25:
print("Vorsicht, Du bist schwer verletzt!")
print(f"Du besitzt {hp} Lebenspunkte.")
Die Ausgabe lautet:
Du besitzt 80 Lebenspunkte.
Einrückungen bilden Code-Blöcke
Nach der if-Bedingung steht ein Doppelpunkt. Die Anweisungen, die zum if
gehören, werden eingerückt:
if hp <= 25:
print("Vorsicht!")
print("Du solltest Dich heilen.")
print("Diese Zeile wird immer ausgeführt.")
Die beiden eingerückten print-Anweisungen bilden gemeinsam einen Code-Block.
Sie werden nur ausgeführt, wenn die Bedingung erfüllt ist.
Die letzte Zeile ist nicht eingerückt und gehört deshalb nicht mehr zum
if-Block. Sie wird unabhängig von der Bedingung ausgeführt.
Für Einrückungen werden in Python üblicherweise vier Leerzeichen verwendet.
Die meisten Code-Editoren erledigen das automatisch, sobald Du nach dem
Doppelpunkt Enter drückst.
Mehrere Fälle mit elif und else
Mit elif kannst Du weitere Bedingungen prüfen. Die Abkürzung steht für
else if. Ein abschließendes else greift, wenn keine der vorherigen
Bedingungen erfüllt war:
hp = 20
if hp <= 0:
print("Du bist besiegt.")
elif hp <= 25:
print("Dein Zustand ist kritisch!")
else:
print("Du kannst weiterkämpfen.")
Python prüft die Bedingungen von oben nach unten:
- Ist
hpkleiner oder gleich0? - Falls nicht: Ist
hpkleiner oder gleich25? - Falls auch das nicht zutrifft: Führe den
else-Block aus.
Sobald eine Bedingung als wahr ausgewertet wird, führt Python den zugehörigen
Block aus. Die restlichen Zweige dieser if/elif/else-Kette werden nicht
mehr geprüft.
Die Reihenfolge der Bedingungen ist wichtig
Die speziellere Bedingung sollte häufig zuerst stehen:
if hp <= 0:
print("Du bist besiegt.")
elif hp <= 25:
print("Dein Zustand ist kritisch!")
Würden wir zuerst hp <= 25 prüfen, träfe diese Bedingung auch bei 0 oder
negativen Lebenspunkten zu. Python würde bereits diesen Block ausführen und die
Meldung über die Niederlage nicht mehr erreichen.
Bedingungen miteinander verknüpfen
Mit and, or und not kannst Du Bedingungen kombinieren.
and: Beide Bedingungen müssen erfüllt sein
hp = 50
hat_schluessel = True
if hp > 0 and hat_schluessel:
print("Du kannst die verschlossene Tür öffnen.")
Der gesamte Ausdruck ist nur dann wahr, wenn der Abenteurer noch Lebenspunkte hat und den Schlüssel besitzt.
Du könntest auch hat_schluessel == True schreiben. Bei einer booleschen
Variablen ist dieser Vergleich aber unnötig. hat_schluessel selbst liefert
bereits True oder False.
or: Mindestens eine Bedingung muss erfüllt sein
gold = 100
hat_schluessel = False
if gold >= 100 or hat_schluessel:
print("Du kannst die Wache passieren.")
Der Ausdruck ist wahr, weil der Abenteurer genügend Gold besitzt. Dass
hat_schluessel den Wert False hat, spielt in diesem Fall keine Rolle.
not: Einen Boolean umkehren
tuer_verschlossen = False
if not tuer_verschlossen:
print("Die Tür ist bereits offen.")
not kehrt den Boolean um:
- Aus
TruewirdFalse. - Aus
FalsewirdTrue.
Da tuer_verschlossen hier False ist, ergibt not tuer_verschlossen den Wert
True.
while: Wiederholen, solange eine Bedingung erfüllt ist
Eine while-Schleife wiederholt ihren Code-Block, solange ihre Bedingung als
wahr ausgewertet wird:
runden = 3
while runden > 0:
print(f"Runden übrig: {runden}")
runden = runden - 1
print("Der Kampf ist vorbei.")
Die Ausgabe lautet:
Runden übrig: 3
Runden übrig: 2
Runden übrig: 1
Der Kampf ist vorbei.
Bei jedem Durchlauf wird runden um 1 verringert. Sobald die Variable den
Wert 0 erreicht, ist runden > 0 nicht mehr erfüllt und die Schleife endet.
Vorsicht vor Endlosschleifen
Vergisst Du, runden zu verändern, bleibt die Bedingung dauerhaft wahr:
runden = 3
while runden > 0:
print(f"Runden übrig: {runden}")
Diese Schleife läuft immer weiter, weil runden den Wert 3 behält.
Ein laufendes Python-Programm kannst Du im Terminal normalerweise mit
Strg+C abbrechen.
for: Werte nacheinander durchlaufen
Mit einer for-Schleife kannst Du mehrere Werte nacheinander durchlaufen. Für
unser erstes Beispiel verwenden wir range(...), das uns eine Reihe von Zahlen
liefert:
for runde in range(1, 4):
print(f"Runde {runde}")
Die Ausgabe lautet:
Runde 1
Runde 2
Runde 3
range(1, 4) beginnt bei 1 und endet vor 4. Der Stop-Wert selbst gehört
also nicht mehr dazu.
Du kannst auch eine Schrittweite angeben:
for zahl in range(3, 0, -1):
print(zahl)
print("Los!")
Die Ausgabe lautet:
3
2
1
Los!
Die drei Werte von range(...) bedeuten:
range(start, stop, schritt)
start: erster Wertstop: Grenze, die nicht mehr enthalten istschritt: Veränderung von einem Wert zum nächsten
Da die Schrittweite -1 beträgt, zählt die Schleife rückwärts.
Eine for-Schleife ist allerdings nicht auf Zahlen beschränkt. Sie kann
allgemein die Elemente eines iterierbaren Objekts (Iterable) durchlaufen.
Später werden wir sie vor allem für Sammlungen wie Listen und Dictionaries
verwenden.
Schleifen mit break und continue steuern
Mit break beendest Du die aktuelle Schleife sofort:
while True:
befehl = input("> ")
if befehl == "ende":
break
print(f"Du hast {befehl} eingegeben.")
print("Das Spiel wurde beendet.")
Die Bedingung von while True ist immer wahr. Ohne break würde die Schleife
deshalb immer weiterlaufen.
Sobald der Spieler ende eingibt, wird break ausgeführt und Python setzt das
Programm nach der Schleife fort.
Mit continue überspringst Du den restlichen Code des aktuellen Durchlaufs und
beginnst mit dem nächsten:
for zahl in range(1, 6):
if zahl == 3:
continue
print(zahl)
Die Ausgabe lautet:
1
2
4
5
Beim Wert 3 führt Python continue aus. Die print-Anweisung dieses
Durchlaufs wird deshalb übersprungen.
Der Dungeon, Schritt 3
Jetzt bauen wir aus den bisherigen Grundlagen einen einfachen Game-Loop.
Öffne dungeon.py und ersetze den bisherigen Inhalt durch folgenden Code:
# Dungeon – Teil 3: Entscheidungen und Game-Loop
print("Du stehst vor dem rostigen Tor eines vergessenen Verlieses.")
print("Ein kalter Luftzug weht Dir entgegen.")
name = input("Wie heißt Du, Abenteurer? ")
gold = int(input("Wie viele Goldmünzen bringst Du mit? "))
hp = 100
max_hp = 100
print()
print(f"Willkommen, {name}!")
print(f"HP: {hp}/{max_hp} | Gold: {gold}")
print()
print("Du stehst in einer dunklen Halle.")
print("Gänge führen nach Norden und Osten.")
print("Verfügbare Befehle: norden, osten, status, ende")
while True:
befehl = input("\n> ").strip().lower()
if befehl == "ende":
print("Du verlässt das Verlies. Bis zum nächsten Mal.")
break
elif befehl == "norden":
print("Du gehst nach Norden und erreichst eine verschlossene Tür.")
elif befehl == "osten":
print("Du schleichst nach Osten und überraschst einen Goblin.")
schaden = 25
hp = max(hp - schaden, 0)
print(f"Der Goblin trifft Dich. Du verlierst {schaden} Lebenspunkte.")
print(f"HP: {hp}/{max_hp}")
if hp == 0:
print("Du sinkst zu Boden. Dein Abenteuer endet hier.")
break
elif befehl == "status":
print(f"{name} | HP: {hp}/{max_hp} | Gold: {gold}")
if hp <= 25:
print("Dein Zustand ist kritisch!")
elif hp < max_hp:
print("Du bist verletzt, kannst aber weiterkämpfen.")
else:
print("Du bist unverletzt.")
else:
print("Das verstehe ich nicht.")
print("Verfügbare Befehle: norden, osten, status, ende")
Führe das Programm aus:
python dungeon.py
Ein möglicher Durchlauf sieht so aus:
Du stehst vor dem rostigen Tor eines vergessenen Verlieses.
Ein kalter Luftzug weht Dir entgegen.
Wie heißt Du, Abenteurer? Karl
Wie viele Goldmünzen bringst Du mit? 50
Willkommen, Karl!
HP: 100/100 | Gold: 50
Du stehst in einer dunklen Halle.
Gänge führen nach Norden und Osten.
Verfügbare Befehle: norden, osten, status, ende
> osten
Du schleichst nach Osten und überraschst einen Goblin.
Der Goblin trifft Dich. Du verlierst 25 Lebenspunkte.
HP: 75/100
> status
Karl | HP: 75/100 | Gold: 50
Du bist verletzt, kannst aber weiterkämpfen.
> norden
Du gehst nach Norden und erreichst eine verschlossene Tür.
> ende
Du verlässt das Verlies. Bis zum nächsten Mal.
Was im Game-Loop passiert
Der Kern unseres Spiels ist diese Schleife:
while True:
befehl = input("\n> ").strip().lower()
while True startet eine Schleife, deren Bedingung immer wahr ist. Bei jedem
Durchlauf wartet input(...) auf einen neuen Befehl. Beendet wird die Schleife
erst durch eines unserer break.
Die beiden String-Methoden bereiten die Eingabe für den Vergleich auf:
.strip()
.lower()
strip() entfernt Leerzeichen und andere Whitespace-Zeichen am Anfang und Ende.
lower() wandelt Großbuchstaben in Kleinbuchstaben um.
Dadurch werden beispielsweise diese Eingaben gleich behandelt:
osten
OSTEN
Osten
Anschließend prüft die if/elif/else-Kette, welchen Befehl der Spieler
eingegeben hat.
Beim Befehl osten verändert sich der Player State:
hp = max(hp - schaden, 0)
Zuerst wird der Schaden von den Lebenspunkten abgezogen. max(...) gibt
anschließend den größeren der beiden Werte zurück. Dadurch kann hp hier nicht
unter 0 fallen.
Hat der Abenteurer keine Lebenspunkte mehr, beendet break den Game-Loop:
if hp == 0:
print("Du sinkst zu Boden. Dein Abenteuer endet hier.")
break
Der Befehl status enthält ein verschachteltes if: Innerhalb des bereits
ausgewählten elif-Blocks wird eine weitere Bedingung geprüft.
elif befehl == "status":
print(f"{name} | HP: {hp}/{max_hp} | Gold: {gold}")
if hp <= 25:
print("Dein Zustand ist kritisch!")
So kann der Dungeon zuerst auf den Befehl reagieren und anschließend abhängig von den aktuellen Lebenspunkten eine passende Meldung ausgeben.
Stolperfallen
-
=statt==verwenden: Ein einzelnes=weist einen Wert zu. Für einen Vergleich benötigst Du==. -
Den Doppelpunkt vergessen: Nach
if,elif,else,whileundformuss ein Doppelpunkt stehen. -
Code falsch einrücken: Die Einrückung bestimmt, welche Anweisungen zu einem Block gehören. Verwende üblicherweise vier Leerzeichen und mische Tabs und Leerzeichen nicht.
-
Bedingungen in der falschen Reihenfolge prüfen: Eine allgemeinere Bedingung kann eine speziellere abfangen. Prüfe beispielsweise
hp <= 0vorhp <= 25. -
Eine Endlosschleife bauen: Eine
while-Schleife endet nur, wenn ihre Bedingung irgendwann als falsch ausgewertet oder die Schleife anderweitig beendet wird. Beiwhile Truebrauchst Du dafür in unserem Beispielbreak. -
breakaußerhalb einer Schleife verwenden:breakfunktioniert nur innerhalb einerwhile- oderfor-Schleife. -
Groß- und Kleinschreibung beim Input übersehen: Ohne
.lower()wären"osten"und"OSTEN"zwei unterschiedliche Strings.
Übungen
1. Einen Heiltrank verwenden
Erweitere den Game-Loop um den Befehl heilen. Er soll dem Abenteurer
20 Lebenspunkte zurückgeben, aber niemals mehr als max_hp.
Lösung
Füge vor dem abschließenden `else` einen weiteren `elif`-Block ein:elif befehl == "heilen":
heilung = 20
hp = min(hp + heilung, max_hp)
print("Du trinkst einen Heiltrank.")
print(f"HP: {hp}/{max_hp}")
2. Einen Countdown programmieren
Schreibe eine for-Schleife, die von 3 bis 1 herunterzählt und anschließend
"Los!" ausgibt.
Lösung
for zahl in range(3, 0, -1):
print(zahl)
print("Los!")
Vertiefung
Für das Verzweigen anhand von Werten bietet Python seit Version 3.10 mit
match und case eine weitere Möglichkeit, die je nach Problem übersichtlicher
sein kann als eine längere if/elif-Kette:
match/case: Strukturelles Pattern Matching
Im nächsten Teil
Unsere Räume bestehen momentan noch aus einzelnen if- und elif-Blöcken. Mit
jedem neuen Raum und Befehl würde der Game-Loop dadurch länger und
unübersichtlicher.
In Teil 4 lernst Du deshalb Sammlungen kennen: Listen und Dictionaries. Mit ihnen beschreiben wir Räume, Ausgänge und ein richtiges Inventar als Daten, statt jeden möglichen Weg fest in den Game-Loop zu schreiben.
0 Kommentare
Noch keine Kommentare. Sei der/die Erste!
Anmelden um einen Kommentar zu hinterlassen.