{
"llm" : {
"feedback" : "# Exercise: address\n\n### Correctness\n- Bei `zipCode` prüfst du zwar die Vierstelligkeit, aber nicht explizit die Anforderung „positiv“ (die Aufgabe nennt beides als Invariante).\n\n### Suggestion\n- Überlege dir, welche Werte laut deiner aktuellen Bedingung für `zipCode` erlaubt sind, und ob damit wirklich *jede* Verletzung von „positiv“ ausgeschlossen ist. Passe die Validierung so an, dass beide Regeln („positiv“ und „vierstellig“) klar abgedeckt sind.\n\n### Code Style\n- In `format()` könntest du direkt auf die Felder zugreifen statt über Getter zu gehen (innerhalb der eigenen Klasse ist das üblich), oder konsequent überall Getter nutzen – wichtig ist Konsistenz.\n- Fehlermeldungen sind verständlich, aber uneinheitlich formatiert (z.B. „zipCode“ vs. „Street/City“). Einheitliche Sprache/Begriffe erleichtern späteres Debugging.\n\n\n# Exercise: timespan\n\n### Correctness\n- Im Konstruktor ist die Precondition für „Zeitspannen sind nie negativ (totalMinutes ≥ 0)“ nicht korrekt formuliert: Durch `(minutes >= 0 && hours >= 0) || hours * 60 + minutes >= 0` akzeptierst du Fälle mit negativen Minuten (z.B. `hours=1, minutes=-30`), obwohl `totalMinutes` dann zwar nicht negativ ist, aber du danach `this.minutes = -30` setzen kannst und damit `getMinutes` < 0 ist.\n- Im Konstruktor stellst du die Invariante `0 ≤ getMinutes ≤ 59` nicht sicher, weil du nur `minutes >= 60` korrigierst, aber negative `minutes` nicht normalisierst.\n- In `add(...)` erlaubst du effektiv auch „Verkürzen“, solange `hours*60 + minutes` nicht negativ ist. Das verletzt die geforderte Precondition „totalMinutes ≥ old(totalMinutes)“ (also die Änderung darf nicht negativ sein). Beispiel: `add(0, -10)` wird bei dir nicht verhindert.\n- In `add(...)` sorgst du zwar für `getMinutes >= 0` durch die zweite while-Schleife, aber dadurch kann `this.hours--` passieren; damit kann `totalMinutes` sinken (Verkürzung) und sogar negativ werden, obwohl das laut Invarianten verboten ist.\n\n### Suggestion\n- Überlege im Konstruktor: Welche einzige Bedingung beschreibt „nicht negativ“ wirklich am besten—bezogen auf die gesamte Zeitspanne (nicht getrennt nach hours/minutes)? Prüfe dann, ob deine Normalisierung `getMinutes` immer in den Bereich 0..59 bringt, auch bei negativen Minuten.\n- Für `add(...)`: Die Precondition bezieht sich auf „nur verlängern“—das heißt, die *hinzugefügte* Zeit muss als Gesamtheit ≥ 0 sein. Prüfe also nicht nur „nicht negativ insgesamt?“, sondern ob die Addition überhaupt eine Verkürzung darstellen kann.\n- Wenn du `minutes` nach der Addition normalisierst: Achte darauf, dass deine Normalisierung nicht durch „Stunden runterzählen“ einen Zustand erzeugt, der die Nicht-Negativität oder das Nicht-Verkürzen unterläuft. Normalisierung sollte die Gesamtminuten nicht verändern, nur die Darstellung.\n\n### Code Style\n- Verwende für die gleiche Logik (Normalisierung von Minuten) möglichst eine zentrale Stelle/Strategie, statt ähnliche while-Schleifen in Konstruktor und `add(...)` unterschiedlich zu behandeln (das reduziert Fehlerquellen).\n- Die Bedingung im Konstruktor ist schwer lesbar und redundant (zwei unterschiedliche Kriterien mit `||`). Eine klarere, einheitliche Precondition macht das Verhalten verständlicher.\n- `IllegalArgumentException()` ohne Nachricht erschwert das Debugging; eine kurze Fehlermeldung (welche Bedingung verletzt wurde) wäre hilfreicher.\n\n\n# Exercise: asteroids\n\n### Correctness\n- Du hast nur Teil (a) umgesetzt; die geforderten Erweiterungen (Asteroid-Klasse mit Typ/Grösse, Asteroiden spawnen/entfernen, Kollisionserkennung + Game-Over) fehlen komplett.\n- In (a) verlangte die Aufgabe zusätzliche Attribute für die Spielfeldbegrenzung **und** eine Klasseninvariante, die die Position einschränkt; du nutzt stattdessen nur lokale Variablen `maxX/maxY` in `move()` und definierst keine Invariante.\n- Deine Begrenzung berücksichtigt nicht, dass `drawImageCentered` die Position als **Bildzentrum** verwendet: Wenn du `x` auf `0` bzw. `512` clampst, ist das Raumschiff teilweise ausserhalb des sichtbaren Bereichs (gleiches gilt für `y` bei `0`/`768`).\n\n### Suggestion\n- Überlege dir, welche Werte `x` und `y` minimal/maximal haben dürfen, wenn das Raumschiff als Kreis (oder als Bild mit Radius) vollständig sichtbar bleiben soll; diese Grenzen sind typischerweise nicht `0..WIDTH`, sondern um einen Radius/halbe Bildgrösse verschoben.\n- Die Spielfeldgrenzen sollten als Felder im `Falcon` (oder als Konstanten/Parameter) vorhanden sein, damit du daraus eine Invariante formulieren kannst (z.B. “nach Konstruktor und nach jedem Move gilt …”); prüfe dann, wo du diese Invariante sicherstellen willst (Clamp/Begrenzen nach dem Bewegen).\n- Arbeite die Teile (b)-(d) schrittweise ab: erst eine `Asteroid`-Klasse mit `move/draw`, dann mehrere Asteroiden verwalten (Array/Listen, Spawn-Logik, Entfernen), danach pro Frame Kollisionen prüfen und bei Treffer die Spielschleife beenden und Game-Over zeichnen.\n\n### Code Style\n- Die Zahlen `512` und `768` als “Magic Numbers” in `Falcon.move()` sind unglücklich: du hast sie schon als `WIDTH/HEIGHT` in `AsteroidsGame`; vermeide doppelte, hart codierte Werte (besser übergeben oder als gemeinsame Konstanten nutzen).\n- `maxX/maxY` als lokale Variablen in `move()` sind eher “versteckte” Konfiguration; als Attribute/Konstanten ist klarer, wofür sie stehen und du kannst sie konsistent im ganzen Objekt verwenden.\n\n\n# Exercise: bosses\n\n### Correctness\n- `findCommonSuperiorWith`: Du prüfst die Gleichheit (`if (a == b)`) erst nachdem `b` bereits auf `b.getBoss()` gesetzt wurde. Dadurch kann ein gemeinsamer Vorgesetzter übersehen werden, wenn `other` selbst (oder ein aktueller `b`) bereits gleich `a` ist.\n- `findCommonSuperiorWith`: Falls es keinen gemeinsamen Vorgesetzten gibt, soll `null` zurückgegeben werden, du gibst am Ende aber `a` zurück (das ist dann zwar `null`, aber nur weil die Schleife so endet). Das ist funktional ok, aber in Kombination mit dem vorherigen Logikpunkt kann es passieren, dass du `null` zurückgibst, obwohl es einen gemeinsamen Vorgesetzten gäbe.\n\n### Suggestion\n- Überlege im inneren `while (b != null)` in welcher Reihenfolge du (1) vergleichen und (2) zu `b.getBoss()` weitergehen solltest, damit auch der Fall abgedeckt ist, dass `a` direkt `other` ist (oder direkt einem aktuell betrachteten `b` entspricht).\n- Prüfe deine Methode mit den im Text genannten Beispielen, insbesondere `sara.findCommonSuperiorWith(headOfSales)` und `sara.findCommonSuperiorWith(sara)`, und beobachte dabei, ob der Vergleich “zu spät” passiert.\n\n### Code Style\n- In `findCommonSuperiorWith` ist `if (this==other)` optional, weil die allgemeine Logik das auch abdecken kann; das extra Special-Case macht den Code etwas länger/zweigeteilter.\n- In `isSuperiorOf` veränderst du den Parameter `other` innerhalb der Methode. Lesbarer ist oft, dafür eine lokale Variable zu verwenden (z.B. `current`), damit klar bleibt, dass du “hochläufst” und nicht das Original-Argument “umdefinierst”.\n\n\n# Exercise: smarthome\n\n### Correctness\n- In `turnNextRoomBright()` ist die Bedingung in der `while`-Schleife in der falschen Reihenfolge: Du greifst auf `rooms[i]` zu, bevor du geprüft hast, ob `i` überhaupt noch im gültigen Bereich liegt. Das kann bei einem Haus, in dem alle Räume bereits “full bright” sind, zu einem `ArrayIndexOutOfBoundsException` führen.\n\n### Suggestion\n- Schau dir in der `while`-Bedingung an, welche Teilausdrücke Java zuerst auswertet (Short-Circuit bei `&&`). Stelle sicher, dass die Index-Grenze (`i < ...`) geprüft wird, bevor du `rooms[i]` verwendest.\n\n### Code Style\n- Das `HashMap lampMap` inkl. Aufbau im Konstruktor und `getLampByName` wirkt für die Aufgabenstellung unnötig und macht die Klasse komplexer; ausserdem ist das Feld nicht `private final`.\n- `findBedrooms()` vergrössert das Array bei jedem Treffer (mit `System.arraycopy`), was unnötig viel Aufwand ist; für prog1 ist meist ein “maximal grosses Array + Zähler” einfacher und effizienter.\n- `fullBright(Room room)` könnte als `private` markiert werden, da es eine reine Hilfsmethode der Klasse ist und nicht Teil der geforderten öffentlichen API.\n",
"status" : "SUCCESS"
}
}