Lehrer-View-Uebersicht: Sterne- + Prozent-Formeln je Sim dokumentiert

- Globale Erklaer-Box: wie der Zeilen-% entsteht (live.php extractScore:
  Score sonst Sterne/5x100) + Uneinheitlichkeiten (0-3 vs 0-5 Sterne,
  rohe score-Werte, Weltkueche pro Gericht, Logistik sendet nichts) +
  Vorschlag 'ein System' (% = Wahrheit, Sterne abgeleitet, gleiche Schwellen).
- Pro Sim ein Bewertungs-Block mit exakter Sterne-Formel + Prozent-Herkunft
  (aus dem Sterne-Audit der Game-Files) inkl. Warnhinweisen.
- Tourismustal: Gaeste-Spalte auf gruen (Gesamtgaeste = Spielfaktor).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 01:24:05 +02:00
parent 691387c4d8
commit bf579310ed
+103 -1
View File
@@ -51,6 +51,18 @@
.note li{margin:.15rem 0;line-height:1.4} .note li{margin:.15rem 0;line-height:1.4}
.note code{background:#efe8d5;border-radius:3px;padding:0 4px;font-size:.72rem;color:#7a5a1a} .note code{background:#efe8d5;border-radius:3px;padding:0 4px;font-size:.72rem;color:#7a5a1a}
.allgreen{margin:.6rem 1.1rem 1rem;background:#f0f7f1;border:1px solid #cfe6d2;border-left:4px solid #5a8a5e;border-radius:8px;padding:.55rem .85rem;font-size:.76rem;color:#3a6b3e} .allgreen{margin:.6rem 1.1rem 1rem;background:#f0f7f1;border:1px solid #cfe6d2;border-left:4px solid #5a8a5e;border-radius:8px;padding:.55rem .85rem;font-size:.76rem;color:#3a6b3e}
.scorebox{margin:.2rem 1.1rem 1rem;background:#eef3f7;border:1px solid #d3e0e8;border-left:4px solid #4a7c8a;border-radius:8px;padding:.7rem .9rem;font-size:.78rem;color:#2f4a58}
.scorebox h4{font-size:.8rem;color:#2f5866;margin-bottom:.45rem;display:flex;align-items:center;gap:.4rem}
.scorebox .srow{display:grid;grid-template-columns:78px 1fr;gap:.5rem;margin:.28rem 0;align-items:start}
.scorebox .srow .lab{font-weight:700;color:#3a6072}
.scorebox code{background:#dde8ee;border-radius:3px;padding:0 4px;font-size:.72rem;color:#294a58;font-family:'Courier New',monospace}
.scorebox .flag{display:block;margin-top:.5rem;font-size:.73rem;color:#8a3a2a;background:#fbeee9;border:1px solid #ecc9bd;border-radius:6px;padding:.35rem .55rem}
.scorebox .flag b{color:#a5341f}
.gbox{background:#fff;border-radius:12px;box-shadow:0 1px 4px rgba(0,0,0,.04);padding:1.1rem 1.3rem;margin-bottom:1.2rem;border-left:4px solid #4a7c8a}
.gbox h2{font-size:1rem;color:#1f4b37;font-weight:800;margin-bottom:.5rem}
.gbox p{font-size:.82rem;line-height:1.5;color:#4a4a4a;margin-bottom:.5rem}
.gbox code{background:#eef3f5;border-radius:3px;padding:0 4px;font-size:.75rem;color:#294a58;font-family:'Courier New',monospace}
.gbox .rec{background:#f0f7f1;border:1px solid #cfe6d2;border-radius:8px;padding:.6rem .8rem;font-size:.8rem;color:#2f5e39;margin-top:.5rem}
.foot{font-size:.72rem;color:#8a8a8a;text-align:center;margin-top:2rem} .foot{font-size:.72rem;color:#8a8a8a;text-align:center;margin-top:2rem}
</style> </style>
</head> </head>
@@ -80,6 +92,14 @@
</div> </div>
</div> </div>
<div class="gbox">
<h2>So entstehen Prozent &amp; Sterne — und warum das heute uneinheitlich ist</h2>
<p><b>Der Zeilen-Prozentwert</b> in „Ergebnisse/Aktuell" entsteht in <code>live.php · extractScore</code>: liefert die Sim einen eigenen <b>0100-Score</b>, wird der genommen; sonst aus den Sternen: <code>% = Sterne / 5 × 100</code>.</p>
<p><b>Die Sterne</b> berechnet jede App am Ende selbst — aus unterschiedlichen Kennzahlen und Schwellen (je Sim unten dokumentiert). Deshalb bedeuten 4★ heute nicht überall dasselbe.</p>
<p><b>Uneinheitlichkeiten:</b> Busfahrt · Fluggesellschaft · Kofferdetektiv liefern nur <b>03 Sterne</b> statt 05. Busfahrt/Fluggesellschaft senden als <code>score</code> rohe Punkte (nicht 0100 → Zeilen-% verzerrt). Weltküche wertet <b>pro Gericht</b> statt pro Durchgang. <b>Logistik überträgt weder Sterne noch Score</b>. Ein echter 0100-Live-Score existiert nur bei Klima, Fluss, Heli, Kofferdetektiv, Tourismusregion (abgeleitet Tourismustal).</p>
<div class="rec"><b>Vorschlag (ein System):</b> Jede App liefert genau <b>eine Funktion → Leistungs-% (0100)</b> als Wahrheit (grün→rot-Balken). Sterne werden daraus mit <b>denselben globalen Schwellen für alle</b> abgeleitet (z. B. ≥90→5★ · ≥75→4 · ≥55→3 · ≥35→2 · sonst 1). Dann bedeuten Sterne überall dasselbe und % ↔ Sterne sind konsistent.</div>
</div>
<div class="toc" id="toc"></div> <div class="toc" id="toc"></div>
<div id="content"></div> <div id="content"></div>
<p class="foot">Alle Werte sind Beispieldaten zur Ansicht. Render-Logik gespiegelt aus <code>teacher.html · renderLive()</code>. Grün/Grau ist Atlas' Vorschlag — bitte prüfen &amp; korrigieren.</p> <p class="foot">Alle Werte sind Beispieldaten zur Ansicht. Render-Logik gespiegelt aus <code>teacher.html · renderLive()</code>. Grün/Grau ist Atlas' Vorschlag — bitte prüfen &amp; korrigieren.</p>
@@ -393,7 +413,7 @@ var GREEN = {
heli: ['missionId','planIndex','planCorrect','planAttempts','startScore','landingScore','totalStars','failed'], heli: ['missionId','planIndex','planCorrect','planAttempts','startScore','landingScore','totalStars','failed'],
kofferdetektiv: ['progressPct','score','cases_solved','hints_revealed','wrong_guesses_total'], kofferdetektiv: ['progressPct','score','cases_solved','hints_revealed','wrong_guesses_total'],
sonnensystem: ['completed','progressPct','achievementsUnlocked'], sonnensystem: ['completed','progressPct','achievementsUnlocked'],
tourismustal: ['scene','year','money','satisfaction','nature','goalsDone','buildings'], tourismustal: ['scene','year','money','guestsToday','satisfaction','nature','goalsDone','buildings'],
tourismusregion: ['mapId','wave','budget','revenue','avgStars','env','goalsDone'], tourismusregion: ['mapId','wave','budget','revenue','avgStars','env','goalsDone'],
logistik: ['levelId','balance','ordersDelivered','ordersLate','progressPct'], logistik: ['levelId','balance','ordersDelivered','ordersLate','progressPct'],
}; };
@@ -428,6 +448,74 @@ var GREY_REASON = {
ordersOpen:'offene Aufträge im Moment', ordersOpen:'offene Aufträge im Moment',
}; };
/* ============================================================
3b) Bewertung je Sim — wie Sterne UND Prozent zustandekommen.
Quelle: Sterne-Audit der Game-Files (Formeln/Schwellen 1:1).
============================================================ */
var SCORING = {
farmer: {
stars:'<b>05</b> aus <code>totalScore</code> (0100, gewichtet: Konto 25% · Trefferquote 20% · CO₂ 15% · Krankheiten 10% · Sorten 10% · Länder 10% · Klimazonen 10%). Schwellen: <code>≥85→5 · ≥70→4 · ≥50→3 · ≥30→2 · sonst 1</code>.',
pct:'Kein 0100-Live-Score → Zeilen-% = <code>Sterne/5×100</code> (im Ergebnis liegt zusätzlich <code>data.score</code>).',
},
klima: {
stars:'<b>05</b>: Basis <code>2★</code> bei Sieg, dann <code>+1</code> je Temp&lt;17° · Temp&lt;16,3° · Budget&gt;200 · (Flut&lt;20% &amp; Bev.&gt;90% Start). Deckel: Temp≥17°→max 3★, ≥18,5°→max 1★.',
pct:'Eigener 0100-Score = <code>TempScore(035)+FlutScore(025)+BudgetScore(020)+BevScore(020)</code>. Live-Score identisch → Zeilen-% = dieser Score.',
},
fluss: {
stars:'<b>05</b> aus Score: <code>≥85→5 · ≥70→4 · ≥55→3 · ≥35→2 · sonst 1</code>.',
pct:'Score 0100 = <code>Ø(Biodiv, Wirtschaft, Hochwasserschutz) 5×Siedlungsverluste</code>. Live-Score vorhanden → Zeilen-% = Score.',
},
energiemanager: {
stars:'<b>05</b> aus <code>Quote = ausgeglichene Blöcke / gesamt</code>: <code>≥1,0→5 · ≥0,87→4 · ≥0,66→3 · ≥0,50→2 · sonst 1</code>. Blackout-Deckel: 1×→max 3★, ≥2×→max 2★.',
pct:'Kein 0100-Live-Score → Zeilen-% = <code>Sterne/5×100</code>.',
},
'eu-werkstatt': {
stars:'<b>05</b> aus <code>firstTryRate = saubere Erstversuche / Schritte</code>: <code>≥1,0→5 · ≥0,85→4 · ≥0,65→3 · ≥0,40→2 · sonst 1</code>.',
pct:'Kein 0100-Live-Score → Zeilen-% = <code>Sterne/5×100</code>.',
},
weltkueche: {
stars:'<b>05 pro Gericht</b> aus Fehlern: <code>0→5 · ≤1→4 · ≤3→3 · ≤6→2 · sonst 1</code>.',
pct:'Live-<code>score</code> ist eine <b>rohe Punktezahl</b> (nicht 0100) → Zeilen-% aktuell unklar.',
flags:['Wird <b>pro Gericht</b> gesendet, nicht pro Durchgang.','„Fehler in %" (Fehler ÷ Aktionen) gehört genau hierher — vergleichbar statt roher, gericht-abhängiger Zahl.'],
},
busfahrt: {
stars:'<b>nur 03</b> aus <code>Ratio = Topo-Punkte / (Aufträge×3)</code>: <code>≥0,85→3 · ≥0,55→2 · ≥0,30→1 · sonst 0</code>.',
pct:'Gesendeter <code>score</code> = rohe Topo-Punkte (nicht 0100).',
flags:['03 statt 05 Sterne.','score ist keine 0100-Zahl → Zeilen-% verzerrt.'],
},
fluggesellschaft: {
stars:'<b>nur 03</b> aus <code>Ratio = Topo-Punkte / (Flüge×3)</code>: <code>≥0,85→3 · ≥0,55→2 · ≥0,30→1 · sonst 0</code>.',
pct:'Gesendeter <code>score</code> = rohe Topo-Punkte (nicht 0100).',
flags:['03 statt 05 Sterne.','score ist keine 0100-Zahl → Zeilen-% verzerrt.'],
},
heli: {
stars:'<b>05</b> = <code>round((PlanSterne + Start + Landung) / 3)</code>. PlanSterne aus Timing (Ø≥1,6→5 …) bzw. Klickgenauigkeit; Chefpilot-Übernahme → 0.',
pct:'Live-Score 0100 = <code>Sterne/5×100</code> (submit <code>score = Sterne×20</code>) → Zeilen-% = das.',
},
kofferdetektiv: {
stars:'<b>nur 03</b> aus <code>q = score100/100</code>: <code>≥0,7→3 · ≥0,45→2 · ≥0,2→1 · sonst 0</code>.',
pct:'<code>score100 = Punkte / (Fälle×100) × 100</code> (je Fall 100 P, 7/Hinweis, 15/Fehltipp, 20/Timeout). Live-Score = score100 → Zeilen-% = das.',
flags:['03 statt 05 Sterne.'],
},
sonnensystem: {
stars:'<b>15</b> aus <code>Quote = Erstversuch-richtig / gesamt</code>: <code>≥0,85→5 · ≥0,68→4 · ≥0,50→3 · ≥0,30→2 · sonst 1</code> (Minimum 1, nie 0).',
pct:'Kein 0100-Live-Score (nur <code>levelWon</code>+Fortschritt; <code>scoreQuote</code> im data) → Zeilen-% = <code>Sterne/5×100</code>.',
},
tourismustal: {
stars:'<b>05</b> = <code>min(5, erreichte Ziele + (Sieg?1:0))</code>.',
pct:'Score 0100 = <code>erreichte Ziele / gesamt × 100</code>; kein Live-0100 → Zeilen-% = data.score bzw. Sterne/5×100.',
},
tourismusregion: {
stars:'<b>05</b> = <code>round(Ø Besucher-Bewertung)</code> (avgStars 05).',
pct:'Score 0100 = gewichtet: <code>Bewertung 35% · Wertschöpfung 25% · Nachhaltigkeit 20% · Lenkung 10% · Finanzen 10%</code>. Live <code>avgStars</code> → Zeilen-% = Score.',
},
logistik: {
stars:'<b>05</b> aus Endkontostand: <code>≤0→0 · ≥16000→5 · ≥13000→4 · ≥10500→3 · ≥8500→2 · sonst 1</code>.',
pct:'Kein Score/Stern wird ans Backend gesendet.',
flags:['Sterne &amp; Score werden <b>NICHT übertragen</b> — im Lehrer-Cockpit erscheint für Logistik kein Stern/Prozent. Eigene Endpoints <code>/api/assessment</code> + <code>/api/logistik-sessions</code>.'],
},
};
/* ============================================================ /* ============================================================
4) Testdaten je Sim (3 Schüler:innen: stark · schwach · mittel) 4) Testdaten je Sim (3 Schüler:innen: stark · schwach · mittel)
============================================================ */ ============================================================ */
@@ -522,6 +610,17 @@ var TEST = {
var _LIVE_PAUSE_SEC = 90; var _LIVE_PAUSE_SEC = 90;
function _liveIsActive(ls){ return ls.last_seen_ms && (NOW - ls.last_seen_ms) <= _LIVE_PAUSE_SEC*1000; } function _liveIsActive(ls){ return ls.last_seen_ms && (NOW - ls.last_seen_ms) <= _LIVE_PAUSE_SEC*1000; }
function renderScoring(id){
var sc = SCORING[id];
if (!sc) return '';
var h = '<div class="scorebox"><h4>🎯 So entsteht die Bewertung</h4>';
h += '<div class="srow"><span class="lab">Sterne</span><span>'+sc.stars+'</span></div>';
h += '<div class="srow"><span class="lab">Prozent</span><span>'+sc.pct+'</span></div>';
(sc.flags||[]).forEach(function(f){ h += '<div class="flag">⚠ '+f+'</div>'; });
h += '</div>';
return h;
}
function renderSim(meta){ function renderSim(meta){
var fields = LIVE_PRIMARY_FIELDS[meta.id] || []; var fields = LIVE_PRIMARY_FIELDS[meta.id] || [];
var rows = TEST[meta.id] || []; var rows = TEST[meta.id] || [];
@@ -596,6 +695,9 @@ function renderSim(meta){
}); });
h += '</tbody></table></div>'; h += '</tbody></table></div>';
// Bewertung: wie Sterne + Prozent entstehen
h += renderScoring(meta.id);
// Nach-Abschluss-Hinweis // Nach-Abschluss-Hinweis
if (greyKeys.length){ if (greyKeys.length){
h += '<div class="note"><b>Nach Abschluss NICHT relevant (nur live):</b><ul>'; h += '<div class="note"><b>Nach Abschluss NICHT relevant (nur live):</b><ul>';