Defekte Ausdrücke
Ziel
Ich verstehe, in welcher Form falsch benutzte Ausdrücke in Code zu Defekten führen, und habe einen solchen Defekt in fremdem Code erfolgreich gefunden.
Arbeitsschritte
Eine Heranführung an Ausdrucksdefekte
Ausdrucksdefekte sind eine generalisierte Form von Variablendefekten. An und für sich ist eine Variable schon ein Ausdruck, aber Variablendefekte sind so geläufig, dass man sie als eigene Klasse sehen kann und in der Aufgabe Falsch benutzte Variable behandelt werden. Ausdrucksdefekte decken alle anderen Fälle ab, in denen Ausdrücke falsch benutzt werden. Die Ursache solcher Defekte liegt nicht daran, dass der Algorithmus falsch wäre, sondern dass der Programmierer beim Nachdenken in diesem Moment nicht korrekt gearbeitet hat.
Der einfachste Fall von Ausdrucksdefekten ist, den falschen Operator benutzt zu haben, beispielsweise wenn man zu einem Integer 2 addieren möchte:
1 2 |
|
Das wirkt vielleicht so dämlich, dass man glaubt, es könne einem nie passieren, aber bei anderen Operatoren sieht das analoge Problem gleich viel subtiler aus:
1 2 |
|
Dieses Beispiel ist mit ziemlicher Sicherheit nicht das, was der Autor eigentlich schreiben wollte.
Wenn min_value
kleiner als max_value
(wie es sich natürlich gehört), wird der Ausdruck unerfüllbar.
Manchmal ist es aber auch nicht klar, ob der Algorithmus schlecht gebaut ist oder ein Verschreiber vorliegt. In solchen Fällen kann es hilfreich sein, naheliegende Kommentare zu sichten, wie beispielsweise bei diesem Verschreiber:
1 2 3 |
|
Hier passt der Code nicht zum Kommentar und ist wahrscheinlich falsch. Näheres zu Logikdefekten erfahren Sie in der Aufgabe Logikdefekte.
Die logischen Operatoren and
und or
sind häufige Quellen von Defekten,
bei denen der falsche Operator in einem Ausdruck gewählt worden ist.
Das obere Beispiel hätte beispielsweise so aussehen können:
1 2 |
|
Alternativ hätte auch das and
richtig sein können und die beiden Vergleichsoperatoren waren vertauscht:
1 2 |
|
Im ersten Fall hat die if
-Bedingung geprüft, ob die Zählung außerhalb des gültigen Bereichs liegt.
Dagegen hat die if
-Bedinging im zweiten Fall geprüft, ob die Zählung innerhalb des gültigen Bereichs liegt.
Hier müsste man prüfen, ob >=
und <=
nicht eher die richtigen Operatoren gewesen wären, aber
das ist ein Thema für die Aufgabe Off-by-1-Defekte.
Oft bleibt unklar, warum der Code falsch ist (stellen sollte man sich diese Frage durchaus!), aber in jedem Fall muss er korrigiert werden.
Ihre Aufgabe
Im Folgenden sollen Sie einen Code debuggen, der einen Ausdrucksdefekt beinhaltet. Es handelt sich um einige Funktionen aus dem Spiel "Go Fish". Zusammen mit den Funktionen aus Defekte durch falsche Anordnung von Anweisungen und Falsch benutzte Variable erhalten Sie die grundlegenden Funktionen des Spiels. In dieser Aufgabe geht es erstmal darum, die Funktionen zu untersuchen, mit denen man eine Karte aus einem Deck zieht und diese in seine Hand legt. Erhält man vier Karten desselben Rangs, also beispielsweise 4 Asse, legt man diese Karten ab.
Karten werden anhand ihres Rangs und ihrer Farbe identifiziert.
Dabei ist der Rang ein Element aus der Liste
["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
(auf Englisch: 2 to 10, Jack, Queen, King, Ace;
auf Deutsch: 2 bis 10, Bube, Dame, König, Ass)
und die Farbe ein Element aus der Liste
["spades", "hearts", "diamonds", "clubs"]
(auf Deutsch: Pik, Herz, Karo, Kreuz).
Ein Deck ist eine Liste mit 52 Elementen.
Jedes Element im Deck ist ein Tupel der Form (Rang, Farbe)
.
Eine Hand von Karten ist ein repräsentiert mit einem Wörterbuch.
Dieses bildet für die Karten, die der Spieler hat, Ränge auf eine Liste von Farben ab.
Wenn also z. B. ein Spieler die "Pik 3" und "Herz 3" in seiner Hand hält, aber keine weiteren 3er-Karten,
dann sieht das Wörterbuch so aus: {"3": ["spades", "hearts"]}
.
Ein Schlüssel sollte keine leeren Listen beinhalten;
wenn keine Karte des gegebenen Rangs existiert, dann existiert dieser Rang nicht im Wörterbuch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
|
Übernehmen Sie diesen Code nach Defekte-in-Ausdrücken.py
.
Hier sind einige Vorschläge, um an den Code heranzutreten:
deck
undplayer_hand
sind im obigen Code nicht definiert.
Wählen Sie geeignete Werte für diese beiden Datenstrukturen, damit Ihr Vorgehen reproduzierbar ist.
Stellen Sie sicher, dass beide Datenstrukturen der Form entsprechen, die über dem Code angegeben ist.- Der Typ des Rückgabewerts der Funktion
get_card()
sollte ein Tupel sein.
Prüfen Sie, ob das wirklich der Fall ist (sofern die Argumente fürget_card()
die richtigen Typen haben). - Höchstwahrscheinlich ist das Wörterbuch
player_hand
die komplizierteste Datenstruktur in diesem Programm.
Untersuchen Sie alle Stellen, an denen es benutzt oder modifiziert wird, um sicherzustellen, dassplayer_hand
richtig benutzt wird und konsistent bleibt. - In Zeile 14 wird eine zufällige Zahl erzeugt. Welche möglichen Werte erwarten Sie hier?
- Welcher Menge von Eingaben in
draw_card()
stellt sicher, dass der gesamte Code abgedeckt wird?
Stellen Sie sicher, dass die Bedingung desif
in Zeile 37 wahr und auch falsch abgedeckt sein soll.
Hinweis (nur bei Bedarf): Lösungshinweise
Gehe die Funktion draw_card()
mit den folgenden Parametern durch.
(In allen Fällen hat DECK der Einfachheit halber nur eine Karte, die Herz 3;
in dieser Situation ist die zufällig ausgewählte Karte immer dieselbe).
Erste Eingabe
Die Karte aus dem Deck passt nicht zum Rang der Karten in der Hand:
1 2 |
|
Hinweis (nur bei Bedarf): Zweite Eingabe
Die Karte aus dem Deck passt zum vorhandenen Rang in der Hand:
1 2 3 |
|
Hinweis (nur bei Bedarf): Dritte Eingabe
Die Karte aus dem Deck ist die vierte Karte des Rangs, sodass dieser Rang abgelegt wird.
1 2 3 |
|
- Defekt gefunden? Prima. Dann jetzt bitte in
Defekte-in-Ausdrücken.py
korrigieren. - Machen sie einen Commit
Defekte-in-Ausdrücken.py corrected
, der nur genau diese modifizierte Datei enthält. - 1
git -P show HEAD
Abgabe
Geben Sie ein Kommandoprotokoll ab, das genau nur die Eingaben und Ausgaben der obigen Kommandos 1, 2, … enthält. Entfernen Sie vor Abgabe eventuelle Fehlversuche und sonstige zusätzliche Kommandos aus dem Protokoll.
Der Defekt steckt in Zeile 40 if len(player_hand) == 4:
.
Der Code prüft, ob vier Karten auf der Hand des Spielers sind, unabhängig von deren Rang.
Es muss aber geprüft werden, ob alle vier Karten eines Rangs auf der Hand des Spielers sind,
also if len(hand[player_hand]) == 4:
.