EU-Werkstatt: Probierzuege (Karten rausziehen) erfassen + Sterne ehrlicher

Bisher konnte man Karten in Slots einsetzen und wieder herausziehen, bis
alle voll waren — erst dann wurde ausgewertet. Dieses Herumprobieren war
unsichtbar und senkte die Sterne nicht (5 Sterne trotz Trial-and-Error).

- game.html: reshufflesByStep/totalReshuffles; manuelles Herausziehen einer
  platzierten Karte zaehlt als Probierzug. Ein Schritt gilt nur ohne
  Probierzuege als 'sauber auf Anhieb' -> Sterne (firstTryHits/steps) und
  Treffsicher-Achievement spiegeln Trial-and-Error jetzt. Endbild zeigt
  '🔄 N Probierzuege'; Live-State + Submit tragen die Zahlen.
- teacher.html: needsHelp eu-werkstatt auch bei vielen Probierzuegen;
  '🔄 Probier'-Spalte in Aktuell; Run-Karte: Gesamt-Probierzuege +
  pro Schritt ('🔄 nach Probieren' statt 'auf Anhieb').

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-24 13:33:44 +02:00
parent 7de71b0e83
commit 8ec005f889
2 changed files with 40 additions and 9 deletions
+25 -5
View File
@@ -4036,6 +4036,8 @@ const state = {
muelleimerCount: 0,
attemptsByStep: [], // Index = stepIndex, Wert = Anzahl Versuche
detoursByStep: [], // Index = stepIndex, Wert = [{label, cardId?}, ...] — Mülleimer-Picks
reshufflesByStep: [], // Index = stepIndex, Wert = Anzahl manuell wieder herausgezogener Karten (Probierzüge)
totalReshuffles: 0,
startedAt: 0,
};
@@ -4293,9 +4295,19 @@ function resetTracking() {
state.muelleimerCount = 0;
state.attemptsByStep = [];
state.detoursByStep = [];
state.reshufflesByStep = [];
state.totalReshuffles = 0;
state.startedAt = Date.now();
}
// Probierzug: Schüler:in zieht eine bereits platzierte Karte wieder aus dem
// Slot. Zeichen von Unsicherheit/Trial-and-Error — zählt pro Schritt und
// verhindert, dass der Schritt als „sauber auf Anhieb" gewertet wird.
function registerReshuffle() {
state.reshufflesByStep[state.stepIndex] = (state.reshufflesByStep[state.stepIndex] || 0) + 1;
state.totalReshuffles++;
}
/* =========================================================
AKTUELLEN SCHRITT RENDERN
========================================================= */
@@ -4370,7 +4382,7 @@ function renderPickStep(area, step) {
// Slot-Klick = Karte rauswerfen
document.getElementById('slot-0').addEventListener('click', () => {
if (state.answered) return;
if (state.slotState[0].cardId) clearSlot(0);
if (state.slotState[0].cardId) { registerReshuffle(); clearSlot(0); }
});
}
@@ -4399,7 +4411,7 @@ function renderSentenceStep(area, step) {
step.slots.forEach((_, i) => {
document.getElementById(`slot-${i}`).addEventListener('click', () => {
if (state.answered) return;
if (state.slotState[i].cardId) clearSlot(i);
if (state.slotState[i].cardId) { registerReshuffle(); clearSlot(i); }
});
});
@@ -4720,7 +4732,9 @@ function evaluateStep() {
// === Tracking ===
state.totalAttempts++;
state.attemptsByStep[state.stepIndex] = (state.attemptsByStep[state.stepIndex] || 0) + 1;
if (correct && state.attemptsByStep[state.stepIndex] === 1) {
// Sauberer Erstversuch NUR ohne Probierzüge (Karten rein-/rausgezogen) auf
// diesem Schritt — sonst war es Trial-and-Error, kein „auf Anhieb".
if (correct && state.attemptsByStep[state.stepIndex] === 1 && !state.reshufflesByStep[state.stepIndex]) {
state.firstTryHits++;
}
@@ -4956,6 +4970,7 @@ function showEnd() {
<div class="stats-row">
<span><strong>${state.firstTryHits}</strong>/${stepsTotal} auf Anhieb richtig</span>
<span><strong>${state.totalAttempts}</strong> Versuche</span>
${state.totalReshuffles > 0 ? `<span>🔄 <strong>${state.totalReshuffles}</strong> Probierzüge</span>` : ''}
${state.muelleimerCount > 0 ? `<span><strong>${state.muelleimerCount}×</strong> im Mülleimer</span>` : ''}
</div>
`;
@@ -5017,6 +5032,8 @@ function showEnd() {
muelleimerCount: state.muelleimerCount,
attemptsByStep: state.attemptsByStep,
detoursByStep: state.detoursByStep,
reshufflesByStep: state.reshufflesByStep,
totalReshuffles: state.totalReshuffles,
difficulty: state.difficulty,
newAchievements,
},
@@ -5275,13 +5292,14 @@ window.GGS_LIVE_STATE = function () {
var stepIdx = state.stepIndex || 0;
var currentStep = (state.scenario && state.scenario.steps) ? state.scenario.steps[stepIdx] : null;
var attemptsThisStep = (state.attemptsByStep && state.attemptsByStep[stepIdx]) || 0;
var reshufflesThisStep = (state.reshufflesByStep && state.reshufflesByStep[stepIdx]) || 0;
var secondsElapsed = state.startedAt ? Math.round((Date.now() - state.startedAt) / 1000) : 0;
// Health-Ampel (für die Lehrer-Live-Übersicht der nächsten Phase)
var health = 'good';
if (screen === 'play') {
if (state.muelleimerCount >= 3 || attemptsThisStep >= 3) health = 'struggling';
else if (state.muelleimerCount >= 1 || attemptsThisStep >= 2) health = 'ok';
if (state.muelleimerCount >= 3 || attemptsThisStep >= 3 || reshufflesThisStep >= 4) health = 'struggling';
else if (state.muelleimerCount >= 1 || attemptsThisStep >= 2 || reshufflesThisStep >= 2) health = 'ok';
} else if (screen === 'end') {
health = 'good';
} else {
@@ -5315,6 +5333,8 @@ window.GGS_LIVE_STATE = function () {
totalAttempts: state.totalAttempts || 0,
muelleimerCount: state.muelleimerCount || 0,
attemptsThisStep: attemptsThisStep,
reshuffles: state.totalReshuffles || 0,
reshufflesThisStep: reshufflesThisStep,
secondsElapsed: secondsElapsed,
achievementsUnlocked: Object.keys(ach).length,
achievementsTotal: (typeof ACHIEVEMENTS !== 'undefined') ? ACHIEVEMENTS.length : 6,