Atlas: Deploy-Buendel vor Staustufen-Sprint

- Logistik: Musik-Player Playlist-Modus (5 Gruppen, 20 Tracks)
- Heli: End-Screen auf .ggs-endscreen, Mission-Bilder, Voice-Lines, Briefing-Audio
- Logistik: Layout-Tausch Auftraege+Fahrzeuge links, Karte rechts
- Logistik: Tier-1-Staedte ausgebaut, Auto-Timescale-Badge
- Logistik: Roadnet/Railnet Dijkstra-Routing, Balance-Updates
- Atlas: 5 Atlas-Inbox-Nachrichten (Cards-Pattern, DALL-E-Key, Musik-Playlists)
- Status-Updates Heli + Logistik

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 01:05:13 +02:00
parent f811437a35
commit 79ac9dad84
773 changed files with 17482 additions and 541 deletions
+169
View File
@@ -0,0 +1,169 @@
# 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.