# Balance-Korridor (Regeln R-1, R-2, R-3) **Stand:** 2026-04-24 **Gilt für:** Logistik Europa (Modul 11), Vorlage für andere Sim-Module Dieses Dokument formalisiert den Balance-Anspruch („jedes Level muss man gewinnen UND verlieren können") als drei Regeln und beschreibt eine mechanische Methode, sie zu prüfen. --- ## 1. Anspruch > **Ein Level ist balanciert, wenn:** > 1. Der/die Bearbeiter*in **Zeit zum Nachdenken** hat, bevor sie ins > Minus rutscht (R-1 Runway). > 2. Mit gutem Spiel **gewinnen kann** (R-2 Winnable). > 3. Mit schlechtem oder keinem Spiel **verlieren kann** (R-3 Loseable). > > Keine der drei Bedingungen darf systematisch verfehlt werden — sonst > ist das Level entweder Frustquelle (kann nur verlieren) oder Pseudo- > Lernspiel (kann nur gewinnen, keine Konsequenz). --- ## 2. Regel R-1 — Startbudget-Runway Bereits in [`level-progression.md` §2](level-progression.md) hergeleitet. Hier nur die Formel: ``` startBudget ≥ 1.5 × ( rentalCostPerDay × vehicleCount + idleCostPerHour × vehicleCount × 12 ) ``` **Interpretation:** Anfangsbudget reicht für 1.5 Tage Operating ohne Einnahmen. Gibt Puffer für Fehltrip + strategische Entscheidung. --- ## 3. Regel R-2 — Winnable > Bei **optimalem oder mindestens guten** Spiel muss der Level > spätestens beim **dritten Versuch** mit positivem End-Saldo gegenüber > `minTargetEarnings` enden. **Formal (Median über 5 Seeds):** - L1: `runLevel(1, *, naive)` → `successful: true` AND `endBalance − startBudget ≥ +1.000 €` - L1: `runLevel(1, *, greedy)` → `successful: true` AND `endBalance − startBudget ≥ +2.000 €` - L2: `runLevel(2, *, greedy)` → `successful: true` AND `endBalance − startBudget ≥ 0` - L2: `runLevel(2, *, optimal)` → `successful: true` AND `endBalance − startBudget ≥ +5.000 €` - L3: `runLevel(3, *, optimal)` → `successful: true` AND `endBalance − startBudget ≥ 0` (Werte aus `balance-matrix.md` §3 übernommen.) **Was wir gerade messen können:** - L1: ✓ naive, greedy, optimal laufen — alle prüfbar - L2: ✓ greedy + optimal laufen — prüfbar - L3: ✓ optimal läuft (Best-Net-Heuristik seit 2026-04-24) — prüfbar → `optimal` ist keine echte globale Optimierung (VRP-TW ist NP-hart), sondern eine **Best-Net-Heuristik**: pro Tick wird die (Contract, Vehicle)- Paarung mit maximalem erwarteten Netto ausgewählt (reward × 1.15 − pickup-fare − delivery-fare − erwartete Verspätungsstrafe). Dominiert greedy in allen drei Leveln und reicht als Proxy für „gutes Spiel". --- ## 4. Regel R-3 — Loseable > **Untätigkeit oder grobes Fehlspiel** muss zuverlässig zum Verlieren > führen, sonst ist das Level keine Lernsituation. **Formal (Median über 5 Seeds):** - L1: `runLevel(1, *, noop)` → `successful: false` AND `endBalance < minTargetEarnings` - L2: `runLevel(2, *, noop)` → `successful: false` - L3: `runLevel(3, *, noop)` → `successful: false` - L2: `runLevel(2, *, naive)` → `successful: false` (zusätzlich gefordert: schlechte Disposition reicht nicht) - L3: `runLevel(3, *, naive)` → `successful: false` - L3: `runLevel(3, *, greedy)` → `successful: false` ODER `knapp negativ` **Implizite Anforderung:** Auch ohne Untätigkeit muss der **Schweregrad mit Level steigen**. L3 darf nicht durch greedy lösbar sein (sonst ist es nur ein L2-Klon). --- ## 5. Aktuelle Verifikation (Stand 2026-04-24) ### R-1 (mathematisch) | Level | Required ≥ | Hat | Verdikt | |-------|-----------|-----|---------| | L1 | 0 | 8.000 | ✅ | | L2 | 1.170 | 5.000 | ✅ | | L3 | 4.650 | **5.000** *(nach Fix vom 2026-04-24)* | ✅ | ### R-2 / R-3 (per Headless-Runner — siehe [headless-runner.html](headless-runner.html)) ``` Status: VOLLSTAENDIG - noop, naive, greedy, optimal laufen alle - Korridor-Check-Button in headless-runner.html pruft R-1 + R-2 + R-3 ueber alle 60 Durchlaeufe (3 Lvl × 4 Strategien × 5 Seeds) ``` Konkrete Runs noch ausständig — beim Server-/Browser-Test mit [headless-runner.html](http://localhost/geograsim/App/sims/logistik/headless-runner.html) „Balance-Korridor-Check"-Button drücken (kommt mit dem Patch dieses Dokuments). --- ## 6. Methode zur Sicherstellung („was tun, wenn ein Level neu konfiguriert wird") ### 6a. Pre-Deploy-Check (vor jeder Level-Param-Änderung) 1. **R-1 mit Taschenrechner**: Formel oben rechnen, muss ≥ erfüllt sein. Engine-seitig schon eingebaut: `_validateRuleR1` in `loadContent` loggt `console.warn` bei Verletzung. 2. **R-2/R-3 via Headless-Runner**: `headless-runner.html` öffnen, „Balance-Korridor-Check" drücken. Ergebnis-Tabelle vergleichen mit Soll-Korridor (siehe §3 + §4). 3. **Bei Verletzung**: Param ändern (üblicherweise `startBudget`, `minTargetEarnings`, `eventProbabilityMultiplier`), erneut prüfen. 4. **Erst dann committen**. ### 6b. Continuous Verification (perspektivisch, sobald Atlas freigibt) - Test-Suite-Script (Node.js): `npm run balance-check` führt `LogistikRunner.runMatrix({levels:[1,2,3], strategies:[...], seeds:[1..5]})` und vergleicht gegen Korridor. Exit-Code 0 = pass, 1 = fail. - CI-Hook beim Push: blockiert Merge, wenn Korridor nicht erreicht. - Voraussetzung: Node-Engine-Export (engine.js läuft schon UMD-konform). ### 6c. Manueller Sanity-Check (ergänzend) Reine Zahlen reichen nicht — der „Spielspaß" ist nicht messbar. Nach jedem Param-Change zusätzlich: - 1× Live-Test im Browser pro Level mit naive Spielstil (mehrere Fehltrips). - 1× Test mit gezielt-strategischem Spielstil. - Fühlt sich der Schwierigkeitsgrad richtig an, oder kommt Frust auf? Die mechanischen Regeln R-1/R-2/R-3 sind **notwendig, aber nicht hinreichend**. --- ## 7. Offene Punkte ### Kurzfristig (vor dem Schul-Pilot) - **`optimal`-Strategie** als Best-Net-Heuristik implementiert (2026-04-24, headless-runner.js, 120 Zeilen). Kriterium pro Tick: max `reward × 1.15 − pickup-fare − delivery-fare − erwartete Strafe`, dann feasible Zuweisungen in Sortierreihenfolge feuern. - **„Balance-Korridor-Check"-Button** in `headless-runner.html` einbauen (erledigt, prueft R-1/R-2/R-3 mechanisch). ### Mittelfristig - **Node-Test-Script** mit Exit-Code für CI. - **Per-Modul-Generalisierung**: das Korridor-Pattern in `App/docs/integration-konzept.md` als Plattform-Vertrag dokumentieren, damit jedes Modul (Klima, Heli, …) die gleiche Disziplin hat. ### Langfristig - **Stochastische Robustheit**: Korridor nicht nur über 5 Seeds prüfen, sondern Konfidenzintervall (z.B. 95 % über 100 Seeds). Aktuell nicht nötig — die Engine ist deterministisch und 5 Seeds geben uns schon eine gute Stichprobe.