Defekte durch falsche Anordnung von Anweisungen
Ziel
Ich verstehe, in welcher Form Lokalisierungsdefekte meinen Code mangelhaft werden lassen, und habe einen solchen Defekt in fremdem Code erfolgreich gefunden.
Arbeitsschritte
Der in dieser Aufgabe zu bearbeitende Code gehört zum Spiel "Go Fish". Ein erster Code hierzu wird in der Aufgabe Defekte Ausdrücke besprochen. Es ist nicht nötig diese Aufgabe vorher bearbeitet zu haben, da die beiden Probleme keinen Code teilen. Allerdings liefert die Bearbeitung der ersten Aufgabe etwas mehr Kontext über das ganze Programm.
Eine Heranführung an Lokalisierungsdefekte
Als Lokalisierungsdefekt werden Defekte bezeichnet, bei dem sich Code in der falschen Reihenfolge innerhalb des Programms befindet. Ein Beispiel ist es, wenn die Initialisierung einer Variable innerhalb einer Schleife anstatt außerhalb stattfindet:
1 2 3 |
|
Ein weiteres Beispiel für einen Lokalisierungsdefekt ist es, wenn die Reihenfolge der Anweisungen nicht mit der gewünschten Reihenfolge der Operationen übereinstimmt. Häufig werden versehentlich zwei Instruktionen vertauscht. Der folgende Code versucht ein Element aus einer Liste auf 0 zu setzen, nachdem es den Wert zu einer Summe hinzugefügt hat. Leider sind die beiden Instruktionen vertauscht:
1 2 |
|
Eine arithmetische Operation kann auch zwei vertauschte Ausdrücke besitzen, wie man an diesem Beispiel sieht, bei dem versucht wird die Hypotenuse eines Dreiecks zu berechnen:
1 2 3 |
|
Die bisherigen Beispiele erkennt man noch relativ leicht als falsch. Schwieriger wird es, wenn verschachtelte Blöcke im Spiel sind und Anweisungen zwar in der optisch richtigen Reihenfolge, aber leider im falschen Block stehen:
1 2 3 4 5 6 7 |
|
In diesem Fall sollte der return
-Ausdruck wahrscheinlich eine Ebene tiefer liegen
(die Funktion soll also nur zurückkehren, wenn string_done
wahr ist, aber nicht nur, weil
found_blank
wahr ist).
Natürlich könnte dieser Code auch ebenso richtig sein.
Es ist nur wichtig zu begreifen, dass solche Defekte sehr leicht zu übersehen sind.
Lokalisierungsdefekte können auch so aussehen, dass ganz fremde Code-Zeilen hinzugefügt worden sind:
1 2 3 4 |
|
Diese überflüssige Anweisung könnte ein Überbleibsel eines früheren Algorithmus sein, ein Fehler beim Kopieren und Einfügen oder einfach ein Fehler des Programmierers.
Ihre Aufgabe
In dieser Aufgabe sollen Sie einen Code debuggen, der einen Lokalisierungsdefekt beinhaltet. Die Funktion beinhaltet einen weiteren Teil des Spiels "Go Fish", das in der Aufgabe Defekte Ausdrücke eingeführt worden ist. Sie prüft, ob er Gegenspieler Karten von einem bestimmten Rang besitzt. Wenn dem so ist, werden diese Karten in die Hand des Spielers transferiert. Wenn dies dazu führt, dass der Spieler vier Karten desselben Rangs auf der Hand hält, werden diese Karten von der Hand des Spielers abgeworfen.
Falls Sie die Aufgabe Defekte Ausdrücke nicht bearbeitet haben, ist hier eine kurze Erinnerung über die Datenstrukturen des Spiels "Go Fish", die auch in dieser Aufgabe benutzt werden:
- 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). - Eine Hand ist ein Wörterbuch.
In jedem Element des Wörterbuchs ist der Schlüssel ein Rang und sein Wert eine Liste von dazugehörigen Farben, die der Spieler in seiner Hand hält. Wenn also z. B. ein Spieler die "Pik 3" und "Herz 3" in seiner Hand hält, aber keine weiteren 3er-Karten, dann lautet der Wörterbucheintrag{"3": ["spades", "hearts"]}
. Ein Schlüssel sollte keine leeren Listen beinhalten; wenn keine Karte des gegebenen Rangs existiert, dann existiert kein Wert für diesen Schlüssel.
Die Funktion check_card()
nimmt vier Parameter:
- den Namen des Spielers als String (wird nur genutzt, um beim Ablegen sagen zu können, wer denn überhaupt ablegt),
- die Hand des Spielers,
- den Rang, der in der Hand des Gegenspielers geprüft werden soll und
- die Hand des Gegenspielers.
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 |
|
Hier sind einige Vorschläge, um an den Code heranzutreten:
- Besitzt der Code implizierte
else
-Ausdrücke?
Welche Eingaben würden dazu führen, dass diese ausgeführt werden? - Der Kommentar in Zeile 18 ist einer der wenigen Kommentare im Hauptalgorithmus,
der auf einen nicht offensichtlichen Aspekt des Codes hinweist.
Ist der Kommentar richtig? - Da die Anweisung in Zeile 23 in einem echten "Go Fish"-Spiel normalerweise nicht ausgeführt würde
(man kann nicht nach einem bestimmten Rang fragen, wenn man nicht bereits eine Karte dieses
Rangs auf der Hand hat), ist es ein riskanter Code.
Er wurde vielleicht nie getestet, aber jemand, der diese Funktion von irgendwo anders aufruft,
könnte annehmen, dass sie funktioniert.
Es ist also ein guter Bereich, um nach einem Defekt zu suchen.
Hinweis (nur bei Bedarf): Lösungshinweis
Durchlaufen Sie den Code mit den folgenden Parametern:
Erste Eingabe
Der Gegenspieler hat eine Karte des gefragten Rangs:
1 2 3 4 5 |
|
Hinweis (nur bei Bedarf): Zweite Eingabe
Der Gegenspieler besitzt keine Karte des gefragten Rangs:
1 2 3 4 |
|
Hinweis (nur bei Bedarf): Dritte Eingabe
Der Gegenspieler besitzt zwei Karten des Rangs und der Spieler hält nach dem Transfer alle vier Karten des Rangs.
1 2 3 4 5 |
|
Hinweis (nur bei Bedarf): Vierte Eingabe
Der Gegenspieler besitzt Karten vom gefragten Rang, aber der Spieler besitzt keine Karten von diesem Rang (das ist ein Regelverstoß und sollte in einem echten Spiel von "Go Fish" nicht passieren)
1 2 3 4 |
|
- Defekt gefunden? Prima. Dann jetzt bitte in
Anordnungsdefekte.py
korrigieren. - Machen sie einen Commit
Anordnungsdefekte.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.
Die Zeilen 29 bis 31 sind falsch indentiert.
return True
muss in allen Fällen ausgeführt werden, in denen das if
von Zeile 16 wahr ist.
Die Lösung ist, dass die drei Zeilen eine Ebene vorgezogen werden müssen.
Erklärung: Eine Karte des angegebenen Ranges befindet sich in der Hand des Gegners, was dazu führt, dass sie auf die Hand des Spielers übertragen wird; dies ist die definierte Situation, in der die Funktion True zurückgeben sollte.