Zum Inhalt springen

Aufgabe 10 - Spielfiguren

Zu Zen-Modus wechseln

Vererbung mit Verhalten: Sie bauen Spielfiguren für ein kleines rundenbasiertes Kampfspiel. Anders als in der Mediathek unterscheiden sich die Subklassen hier nicht nur in Daten, sondern in Verhalten, das überschrieben und erweitert wird. Am Ende stoßen Sie planmäßig an die Grenze der Vererbung und bereiten damit die Folgeübung vor (siehe Kapitel Vererbung).

  • Kapitel Vererbung, insbesondere Überschreiben, super() und die Prüffragen für gute Hierarchien.
  • Aufgabe 09 abgeschlossen.
  • Sie entwerfen eine Hierarchie aus einer Verhaltensbeschreibung und setzen sie um.
  • Sie überschreiben Methoden gezielt und begründen, welche Methode überschrieben wird.
  • Sie erkennen Anforderungen, an denen einfache Vererbung scheitert.
  • Reproduktion: eine vorgegebene Basisklasse implementieren (Teil A).
  • Reorganisation und Transfer: Verhaltensregeln in überschriebene Methoden übersetzen und im polymorphen Kampfablauf anwenden (Teile B und C).
  • Reflexion, Problemlösung und Urteilsbildung: die Grenzen des Entwurfs analysieren, Alternativen skizzieren und bewerten (Teil D).

Die Übung ist auf etwa zwei Stunden ausgelegt. Teil D ist der Expertenteil.

  1. Implementieren Sie Character mit name, health (Start 100) und strength sowie den Methoden attack(target) (zieht dem Ziel strength Punkte ab), take_damage(points), is_defeated() und __str__ (Name und aktuelle Punkte).
  2. Lassen Sie zwei Basisfiguren einige Runden aufeinander einschlagen und geben Sie den Verlauf aus. Erst wenn das läuft, kommen Subklassen dazu.
  1. Knight(Character): hat zusätzlich armor und erleidet nur halben Schaden. Überschreiben Sie dafür take_damage, nicht attack. Begründen Sie im Kommentar, warum das die richtige Stelle ist (wer ist für den erlittenen Schaden zuständig, der Angreifer oder der Getroffene?).
  2. Mage(Character): hat mana (Start 50); attack kostet 10 Mana und verursacht doppelten Schaden; ohne ausreichendes Mana ein gewöhnlicher Schlag über super().attack(target).
  3. Healer(Character): kann zusätzlich heal(target) (+20 Punkte, Obergrenze 100).
  4. Kontrolle: Keine Subklasse wiederholt Code der Basisklasse; alles Geerbte bleibt geerbt, super() wird überall dort verwendet, wo Basisverhalten erweitert statt ersetzt wird.
  1. Simulieren Sie einen rundenbasierten Kampf 2 gegen 2 (Teamzusammenstellung frei) bis ein Team besiegt ist, mit lesbarer Rundenausgabe.
  2. Verbindliche Entwurfsregel: Die Kampfschleife behandelt alle Figuren einheitlich als Character. Typspezifisches Verhalten entsteht ausschließlich durch überschriebene Methoden; isinstance-Abfragen in der Schleife sind nicht zulässig. Markieren Sie im Code, wo die Schleife von diesem Verzicht profitiert.
  3. Bauen Sie eine einfache Zugregel für den Heiler ein (etwa: heilt den schwächsten Verbündeten, wenn dieser unter 40 Punkten liegt, sonst greift er an), ohne die Regel aus Punkt 2 zu verletzen. Hinweis: Die Entscheidung darf in einer überschriebenen Methode take_turn(allies, enemies) liegen, die die Basisklasse mit Standardverhalten (angreifen) vorgibt.
  1. Neue Anforderung: ein Paladin, der Ritter und Heiler zugleich ist (halber Schaden und Heilfähigkeit). Versuchen Sie eine Lösung innerhalb Ihrer Hierarchie und dokumentieren Sie, woran sie krankt (Codeverdopplung? Mehrfachvererbung samt ihrer Probleme? Eine künstliche Zwischenklasse?).
  2. Diskutieren Sie schriftlich in fünf bis acht Sätzen: Warum skaliert die Lösung “für jede Kombination eine Subklasse” nicht? Wie viele Klassen bräuchten Sie bei vier frei kombinierbaren Fähigkeiten?
  3. Skizzieren Sie (nur als Text oder Diagramm, ohne Implementierung) den Alternativentwurf: Fähigkeiten als eigene Objekte, die eine Figur hat statt ist. Genau dieser Entwurf wird in Aufgabe 11 gebaut.
  4. Prüfen Sie abschließend Ihre bestehende Hierarchie gegen das Substitutionsprinzip aus dem Kapitel: Gibt es eine Stelle, an der eine Subklasse Erwartungen an Character verletzt? Begründen Sie Ihr Urteil.
  1. Warum gehört die Rüstungslogik in take_damage und nicht in attack?
  2. Was bewirkt super().attack(target) im Magier, wenn das Mana nicht reicht?
  3. Warum verbietet die Arena-Regel isinstance-Abfragen in der Kampfschleife? Was würde bei einer fünften Figurenart passieren?
  4. Formulieren Sie das Substitutionsprinzip in einem eigenen Satz.
  5. Ab wann ist “für jede Variante eine Subklasse” der falsche Weg? Nennen Sie das Erkennungszeichen aus Teil D.

arena.py mit Hierarchie und Kampfsimulation sowie die schriftliche Diskussion und Skizze aus Teil D.