{
"llm" : {
"feedback" : "# Exercise: parking\n\n### Correctness\n- `GroupCard`: Der Fall „mehr als 20 Personen“ ist laut Aufgabenstellung **nicht erlaubt**, in deiner Implementierung wird er aber stillschweigend mit dem 2.00 CHF/h-Tarif abgerechnet.\n- `GroupCard`: Für „bis 5 Personen“ muss der Tarif 1.60 CHF/h gelten; bei `persons <= 0` würdest du aktuell ebenfalls 1.60 CHF/h anwenden, obwohl eine Personenanzahl ≤ 0 inhaltlich keinen Sinn ergibt (mindestens validieren oder behandeln).\n- `FlatRateCard`: Du speicherst Parkzeit (`totalTime`) und erhöhst sie in `park`, aber `cost()` ignoriert sie komplett; falls die Aufgabe erwartet, dass `park()`/`reset()` semantisch sinnvoll sind (auch wenn Pauschale), ist das so inkonsistent umgesetzt.\n\n### Suggestion\n- Überlege dir für `GroupCard`, wie du den Konstruktor-Parameter `persons` so prüfst, dass Werte **> 20** nicht akzeptiert werden (z.B. direkt im Konstruktor reagieren).\n- Denke darüber nach, ob du bei `persons <= 0` ebenfalls eine klare Entscheidung treffen willst (ähnlich wie bei „> 20“), statt es einfach in „bis 5“ hineinfallen zu lassen.\n- Bei der `FlatRateCard`: Entscheide dich bewusst, ob du Parkzeit überhaupt tracken willst. Wenn es eine Monatsflatrate ist, könnte `park()` zwar erlaubt sein, aber dann sollte `reset()`/Zeittracking entweder konsequent weggelassen oder zumindest begründet/neutral gehalten werden (damit die Methoden nicht „so tun als ob“ ohne Effekt).\n\n### Code Style\n- `GroupCard`: `HOURLY_RATE` ist deklariert, aber nirgends verwendet → entfernen oder wirklich nutzen.\n- `GroupCard`: `persons` sollte `private final` sein, wenn es nach der Konstruktion nicht mehr verändert wird.\n- `FlatRateCard`: `totalTime` ist effektiv ungenutzt (weil `cost()` konstant ist) → entweder entfernen oder so einsetzen, dass es zur restlichen Logik passt.\n\n\n# Exercise: labyrinth\n\n### Correctness\n- In `TryStraightFirst` erfüllst du die geforderte Entscheidungslogik nicht: Wenn vorne blockiert ist, soll *links oder rechts* versucht werden und wenn *gar nichts* geht, soll die Figur umdrehen. Dein Code probiert effektiv nur „rechts“, und wenn das nicht geht, drehst du lediglich wieder zurück zur ursprünglichen Richtung (kein „rechtsum kehrt“ als Fallback), und „links“ wird nie als echte Alternative getestet.\n- `BacktrackingAlgorithm` kann beim „Offset-Kalibrieren“ in einen bereits besuchten Nachbarfeld trotzdem hineinlaufen: Du berechnest `nextPos` zwar und prüfst `visited`, aber diese Prüfung passiert erst **nach** dem Probe-Schritt/Zurück-Schritt-Block. Das heißt: selbst wenn das Feld vor dir schon besucht ist, machst du u.U. trotzdem die Probe-Bewegung (sobald `offset == null`), was gegen die Idee „besuchte Knoten nicht erneut betreten“ arbeitet und bei manchen Labyrinthen unnötige Zyklen/Animationen erzeugen kann.\n- `BacktrackingAlgorithm`: Wenn `solve(...)` am Ende `false` liefert (kein Ziel gefunden), wird das Ergebnis in `navigate` ignoriert. Dann bleibt die Figur irgendwo stehen und `LabyrinthGame` wirft danach „Ziel nicht gefunden.“. Für die Aufgabe „findet ein Ziel“ ist das Verhalten ok, aber es ist ein Hinweis, dass dein Algorithmus evtl. nicht garantiert jedes Level löst (und du erkennst es selbst nicht innerhalb des Algorithmus).\n\n### Suggestion\n- Für `TryStraightFirst`: Bau die Abfragen pro Schleifendurchlauf so auf, dass du wirklich drei Fälle sauber abdeckst: (1) vorne frei → vorwärts, (2) sonst eine Seite testen (links und rechts als Alternativen, Reihenfolge ist deine Wahl) und dabei entsprechend drehen+gehen, (3) wenn weder vorne noch links noch rechts frei ist → explizit um 180° drehen. Achte darauf, dass du nach einem erfolglosen Seitentest die Blickrichtung wieder korrekt für den nächsten Test/Fallback ausrichtest.\n- Für `BacktrackingAlgorithm`: Überlege, an welcher Stelle du entscheiden willst „dieses Nachbarfeld ist schon besucht“ — idealerweise **bevor** du irgendeinen Schritt (auch einen Probe-Schritt) machst. Du kannst die Richtung/Koordinatenlogik so strukturieren, dass du erst das potenzielle Ziel-Feld identifizierst und nur dann wirklich läufst, wenn es sinnvoll ist.\n- Für `BacktrackingAlgorithm`: Wenn du willst, dass dein Algorithmus selbst klar signalisiert „unlösbar“, dann nutze den Rückgabewert von `solve` in `navigate` (z.B. um kontrolliert zu stoppen oder eine aussagekräftigere Exception zu werfen), statt ihn zu ignorieren.\n\n### Code Style\n- In `BacktrackingAlgorithm` mischst du vollqualifizierte Typnamen (`java.util.Map`, `java.util.HashMap`) mit Imports (`Set`, `HashSet`). Entscheide dich für eine Variante (Imports sind üblich) und bleib konsistent.\n- `dirOffsets` ist als `Map<Integer, int[]>` ok, aber `int[]` ist wenig selbsterklärend. Lesbarkeit steigt, wenn du für Offsets eine kleine Struktur/Record oder zumindest benannte Variablen/Helper verwendest.\n- Dein `visited`-Key als zusammengesetzter String `\"row,col\"` funktioniert, ist aber unnötig fehleranfällig/ineffizient. Stilistisch sauberer ist eine kleine Koordinatenklasse/Record oder ein kodierter int-Schlüssel (z.B. `row * cols + col`) – ohne dass du die Lösungsidee ändern musst.\n\n\n# Exercise: swissmap\n\n### Correctness\n- Deine `main`-Methode in `SwissMapApp` hat die Signatur `void main()`. So wird sie als Einstiegspunkt normalerweise nicht gefunden; gefordert ist eine `main`-Methode, die wirklich als Programmstart dient.\n- In `Lake.draw` und `Mountain.draw` verwendest du feste Skalierungsfaktoren (`0.3`) beim `drawImage(...)`. Die Aufgabe verlangt, dass die Darstellung mit der Fenstergrösse mitskaliert (analog zur Karte), d. h. die Objektgrösse sollte an die Map-Skalierung gekoppelt sein.\n- `ModeButton` implementiert zwar `Hoverable`, aber `onMouseEnter`/`onMouseExit` machen nichts; damit erfüllst du den Teil „nicht nur Drawable und Hoverable, sondern auch Clickable … als Knopf … angezeigt“ nur teilweise, weil das Hover-Verhalten als Teil der Aufgabe explizit vorgesehen ist (z. B. visuelles Feedback / Beschreibung beim Darüberfahren).\n\n### Suggestion\n- Schau dir an, welche Methodensignatur Java als Programmeinstieg akzeptiert (Stichwort: `public static ...` und Parameter). Vergleiche das mit deiner aktuellen `main`.\n- Überlege, wie `SwissMap.scale(gui)` in `SwissMap.draw` genutzt wird, und wie du eine ähnliche Idee für die Icon-Grösse von Seen/Bergen einsetzen kannst, damit sie beim Resizen konsistent mitwachsen/-schrumpfen.\n- Nutze in `ModeButton` ein ähnliches Muster wie bei City/Lake/Mountain: beim Hover einen Zustand setzen (z. B. `hovered`) und diesen dann in `draw` auswerten, um z. B. Farbe/Rahmen/Text zu verändern.\n\n### Code Style\n- Variablennamen wie `Karte` sind in Java unüblich (gross/Deutsch). Nimm lieber lowerCamelCase und konsistente Sprache (z. B. `swissMap`, `map`).\n- In `City`, `Lake`, `Mountain` und `ModeButton` verwendest du mehrfach vollqualifizierte Klassennamen (`new ch.trick17.gui.component.Rectangle(...)`) obwohl du `Shape` bereits importierst; importiere `Rectangle` direkt, dann wird der Code lesbarer.\n- `hovered` wird in allen drei Klassen gleich implementiert; wenn ihr später mehr Features bekommt, könnte sich eine kleine Hilfsstruktur oder ein gemeinsames Muster lohnen, damit du Logik nicht dreifach pflegen musst.\n\n\n# Exercise: visualizer\n\n### Correctness\n- In `VisualizerApp` ist `main()` nicht als Java-Entry-Point deklariert (nicht `public static void main(String[] args)`), dadurch startet das Programm in einer normalen Java-Ausführung nicht wie erwartet.\n- Beim Prozessor-Datensatz soll laut Aufgabe für die y-Achse eine logarithmische Achse verwendet werden, aber als y-Wert selbst die effektive Geschwindigkeit (clockRate * cores). Du gibst aktuell bereits `log10(clockRateKhz * cores)` als `y()` zurück; damit ist die Achse effektiv doppelt “logarithmiert” (bzw. die Log-Skalierung ist ins Datenmodell statt in die Darstellung gewandert).\n- In der Prozessor-Detailbeschreibung soll auch die “effektive Rechengeschwindigkeit” (clock rate * cores) ersichtlich sein; aktuell zeigst du Taktfrequenz und Cores getrennt, aber nicht das Produkt (zumindest nicht explizit als Wert).\n- In der Prozessor-Detailbeschreibung sollen MHz- und kHz-Werte als ganze Zahlen und GHz-Werte als Kommazahlen erscheinen; bei GHz formatierst du immer mit einer Nachkommastelle (`%.1f`). Das führt z.B. bei exakt 2.0 GHz zu `2.0 GHz` statt einer “passenden” Darstellung (je nach Erwartung aus den Screenshots).\n\n### Suggestion\n- Schau dir an, wie Java eine Klasse als Startpunkt erkennt: Welche Signatur muss `main` haben, damit sie beim Starten automatisch aufgerufen wird?\n- Überlege, wo “logarithmische y-Achse” hingehört: Soll das Datenobjekt bereits geloggte Werte liefern, oder soll es lineare Werte liefern und der Visualizer (bzw. die Achsen-Transformation) übernimmt die Log-Skalierung?\n- Für die Prozessoren: Wenn du im Tooltip “effektive Rechengeschwindigkeit” zeigen willst, hilft es, zusätzlich einen Wert zu berechnen, der genau dieses Produkt darstellt, und ihn in einer verständlichen Einheit/Notation auszugeben.\n- Bei der GHz-Formatierung: Prüfe, ob du Nachkommastellen wirklich immer erzwingen willst, oder ob du die Darstellung abhängig davon machen kannst, ob es eine “glatte” Zahl ist bzw. ob die Screenshots eher “2 GHz” vs. “2.5 GHz” nahelegen.\n\n### Code Style\n- Die Konstanten `DUMMY_DOUBLE` und `DUMMY_STRING` in `Visualizer` sind nach deiner Umstellung unbenutzt und können entfernt werden, um Ablenkung zu vermeiden.\n- In `Processor.description()` benutzt du `java.util.Locale.US` inline; ein `import` (oder ein klarer Kommentar, warum du US-Locale erzwingst) würde die Lesbarkeit erhöhen und die Intention klarer machen.\n",
"status" : "SUCCESS"
}
}