"""Programmier-Aufgaben. Das Modell liefert eine Python-Funktion, die gegen feste Testfaelle laeuft. Bestanden heisst: alle Testfaelle gruen. Die Aufgaben sind absichtlich so gewaehlt, dass die naive Loesung durchfaellt — Sonderfaelle (leere Eingabe, Gleichstand, Ueberlappung an der Kante) sind Teil der Tests. Sonst bestehen alle Modelle alles und die Tabelle sagt nichts. """ TASKS = [ dict( id="code01", titel="Intervalle zusammenfassen", funktion="merge_intervalle", prompt="Schreibe eine Python-Funktion `merge_intervalle(intervalle)`. " "Eingabe ist eine Liste von (start, ende)-Tupeln. Gib eine nach Start " "sortierte Liste zurueck, in der sich ueberlappende oder direkt " "aneinandergrenzende Intervalle zusammengefasst sind. " "(1,3) und (3,5) grenzen aneinander und werden zu (1,5). " "Leere Eingabe ergibt eine leere Liste. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ ("merge_intervalle([])", []), ("merge_intervalle([(1,3),(2,6),(8,10)])", [(1, 6), (8, 10)]), ("merge_intervalle([(1,3),(3,5)])", [(1, 5)]), ("merge_intervalle([(5,7),(1,2)])", [(1, 2), (5, 7)]), ("merge_intervalle([(1,10),(2,3)])", [(1, 10)]), ], ), dict( id="code02", titel="Verschachteltes dict flach machen", funktion="flatten", prompt="Schreibe eine Python-Funktion `flatten(d, sep='.')`. Sie macht ein " "beliebig tief verschachteltes Dictionary flach, indem sie die " "Schluessel mit sep verbindet. Ein leeres Unter-Dictionary " "verschwindet ersatzlos. Listen werden NICHT aufgeloest, sondern " "als Wert uebernommen. Gib nur den Code aus, ohne Erklaerung.", tests=[ ("flatten({'a':1})", {"a": 1}), ("flatten({'a':{'b':{'c':2}}})", {"a.b.c": 2}), ("flatten({'a':{'b':1},'c':2})", {"a.b": 1, "c": 2}), ("flatten({'a':{}})", {}), ("flatten({'a':[1,2]})", {"a": [1, 2]}), ("flatten({'a':{'b':1}}, sep='/')", {"a/b": 1}), ], ), dict( id="code03", titel="Roemische Zahlen lesen", funktion="roemisch_zu_int", prompt="Schreibe eine Python-Funktion `roemisch_zu_int(s)`, die eine " "roemische Zahl als String in eine ganze Zahl umwandelt. " "Subtraktionsregel beachten: IV ist 4, IX ist 9, XL ist 40, " "CM ist 900. Gib nur den Code aus, ohne Erklaerung.", tests=[ ("roemisch_zu_int('III')", 3), ("roemisch_zu_int('IV')", 4), ("roemisch_zu_int('IX')", 9), ("roemisch_zu_int('LVIII')", 58), ("roemisch_zu_int('MCMXCIV')", 1994), ("roemisch_zu_int('MMXXVI')", 2026), ], ), dict( id="code04", titel="Wortfrequenz mit Gleichstand", funktion="top_woerter", prompt="Schreibe eine Python-Funktion `top_woerter(text, n)`. Sie gibt die " "n haeufigsten Woerter als Liste von (wort, anzahl)-Tupeln zurueck, " "absteigend nach Anzahl. Gross- und Kleinschreibung wird ignoriert. " "Bei gleicher Anzahl entscheidet die alphabetische Reihenfolge. " "Als Wort gilt jede Folge aus Buchstaben und Ziffern. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ ("top_woerter('a b a', 1)", [("a", 2)]), ("top_woerter('b a', 2)", [("a", 1), ("b", 1)]), ("top_woerter('Der der DER hund', 2)", [("der", 3), ("hund", 1)]), ("top_woerter('', 3)", []), ("top_woerter('x y z', 10)", [("x", 1), ("y", 1), ("z", 1)]), ], ), dict( id="code05", titel="Klammern pruefen", funktion="klammern_ok", prompt="Schreibe eine Python-Funktion `klammern_ok(s)`, die True liefert, " "wenn alle runden, eckigen und geschweiften Klammern im String korrekt " "geschachtelt und geschlossen sind, sonst False. Andere Zeichen werden " "ignoriert. Ein leerer String ist gueltig. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ ("klammern_ok('')", True), ("klammern_ok('()')", True), ("klammern_ok('([{}])')", True), ("klammern_ok('(]')", False), ("klammern_ok('([)]')", False), ("klammern_ok('(')", False), ("klammern_ok('a(b)c[d]')", True), ], ), dict( id="code06", titel="Suche im rotierten Feld", funktion="suche_rotiert", prompt="Schreibe eine Python-Funktion `suche_rotiert(arr, ziel)`. Das Feld arr " "ist aufsteigend sortiert, aber um eine unbekannte Stelle rotiert " "(zum Beispiel [4,5,6,7,0,1,2]). Gib den Index von ziel zurueck oder -1, " "wenn es fehlt. Die Laufzeit soll logarithmisch sein. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ ("suche_rotiert([4,5,6,7,0,1,2], 0)", 4), ("suche_rotiert([4,5,6,7,0,1,2], 3)", -1), ("suche_rotiert([1], 1)", 0), ("suche_rotiert([], 5)", -1), ("suche_rotiert([1,2,3,4,5], 5)", 4), ("suche_rotiert([5,1,2,3,4], 5)", 0), ], ), dict( id="code07", titel="Werktage zwischen zwei Daten", funktion="werktage", prompt="Schreibe eine Python-Funktion `werktage(von, bis)`. Beide Argumente " "sind Strings im Format 'JJJJ-MM-TT'. Gib die Anzahl der Werktage " "(Montag bis Freitag) zurueck, einschliesslich beider Randtage. " "Ist bis vor von, gib 0 zurueck. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ # 2026-08-15 ist ein Samstag, 2026-08-17 ein Montag. ("werktage('2026-08-17','2026-08-21')", 5), ("werktage('2026-08-15','2026-08-16')", 0), ("werktage('2026-08-14','2026-08-17')", 2), ("werktage('2026-08-17','2026-08-17')", 1), ("werktage('2026-08-20','2026-08-10')", 0), ], ), dict( id="code08", titel="LRU-Zwischenspeicher", funktion="LRU", prompt="Schreibe eine Python-Klasse `LRU` mit `__init__(self, groesse)`, " "`get(self, schluessel)` und `put(self, schluessel, wert)`. " "Sie verhaelt sich wie ein LRU-Cache: get liefert den Wert oder None " "und zaehlt als Benutzung; put fuegt ein und verdraengt bei " "Ueberschreitung den am laengsten unbenutzten Eintrag. " "Ein put auf einen vorhandenen Schluessel zaehlt ebenfalls als Benutzung. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ ("c=LRU(2); c.put('a',1); c.put('b',2); ERG=c.get('a')", 1), # Nach drei puts in einen Zweier-Cache fliegt 'a' — nicht 'b'. ("c=LRU(2); c.put('a',1); c.put('b',2); c.put('c',3); ERG=c.get('a')", None), # 'a' wird durch das get frisch -> 'b' muss fliegen, nicht 'a'. ("c=LRU(2); c.put('a',1); c.put('b',2); c.get('a'); c.put('c',3); ERG=c.get('b')", None), ("c=LRU(2); c.put('a',1); c.put('b',2); c.get('a'); c.put('c',3); ERG=c.get('a')", 1), ("c=LRU(1); c.put('a',1); c.put('a',9); ERG=c.get('a')", 9), ], ), dict( id="code09", titel="Wiederholung nach Fehlschlag", funktion="wiederhole", prompt="Schreibe eine Python-Funktion `wiederhole(fn, versuche=3)`. Sie ruft " "fn ohne Argumente auf und gibt dessen Ergebnis zurueck. Wirft fn eine " "Exception, wird erneut versucht, hoechstens `versuche` Mal insgesamt. " "Schlaegt auch der letzte Versuch fehl, wird die letzte Exception " "weitergereicht. Baue KEINE echte Wartezeit ein. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ ("ERG = wiederhole(lambda: 42)", 42), # Scheitert zweimal, gelingt beim dritten Versuch. ("z=[0]\n" "def f():\n" " z[0]+=1\n" " if z[0]<3: raise ValueError('noch nicht')\n" " return 7\n" "ERG = wiederhole(f)", 7), # Scheitert immer -> die Exception muss durchschlagen. ("def g(): raise KeyError('x')\n" "try:\n" " wiederhole(g)\n" " ERG = 'keine exception'\n" "except KeyError:\n" " ERG = 'KeyError'\n", "KeyError"), # versuche=1 heisst genau ein Versuch, kein zweiter. ("z=[0]\n" "def h():\n" " z[0]+=1\n" " raise RuntimeError()\n" "try:\n" " wiederhole(h, versuche=1)\n" "except RuntimeError:\n" " pass\n" "ERG = z[0]", 1), ], ), dict( id="code10", titel="CSV sortieren und als JSON", funktion="csv_nach_json", prompt="Schreibe eine Python-Funktion `csv_nach_json(text, spalte)`. Eingabe " "ist der Inhalt einer CSV-Datei als String, getrennt durch Semikolon, " "mit Kopfzeile. Sortiere die Datenzeilen aufsteigend nach der genannten " "Spalte — numerisch, falls alle Werte dieser Spalte Zahlen sind, sonst " "alphabetisch. Gib das Ergebnis als JSON-String zurueck: eine Liste von " "Objekten mit den Spaltennamen als Schluessel. " "Gib nur den Code aus, ohne Erklaerung.", tests=[ ("__import__('json').loads(csv_nach_json('a;b\\n2;x\\n10;y\\n','a'))", [{"a": "2", "b": "x"}, {"a": "10", "b": "y"}]), ("__import__('json').loads(csv_nach_json('a;b\\nzz;1\\naa;2\\n','a'))", [{"a": "aa", "b": "2"}, {"a": "zz", "b": "1"}]), ("__import__('json').loads(csv_nach_json('a;b\\n','a'))", []), ], ), ]