From 34bcef5da8695ca4858778c7a4c7c9dba2a03e78 Mon Sep 17 00:00:00 2001 From: schmop Date: Sun, 31 May 2026 18:51:40 +0200 Subject: [PATCH] =?UTF-8?q?Gegen=20blindes=20Durchtippen:=20vierte=20Antwo?= =?UTF-8?q?rtm=C3=B6glichkeit=20+=20kurze=20Denkpause=20nach=20falscher=20?= =?UTF-8?q?Antwort?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/game/AnswerButtons.svelte | 43 +++++++++++++++----- src/lib/game/tasks.test.ts | 4 +- src/lib/game/tasks.ts | 4 +- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/lib/components/game/AnswerButtons.svelte b/src/lib/components/game/AnswerButtons.svelte index 48e3ac3..71fd647 100644 --- a/src/lib/components/game/AnswerButtons.svelte +++ b/src/lib/components/game/AnswerButtons.svelte @@ -9,9 +9,13 @@ let wrongValue = $state(null); let lockedCorrect = $state(null); + // Kurze Denkpause nach falscher Antwort: Knöpfe sind ~0,9s gesperrt und gedimmt. + // Kein Punktverlust — macht blindes Durchtippen nur langsamer als Nachdenken. + let coolingDown = $state(false); + let cooldownTimer: ReturnType | null = null; function handle(value: number) { - if (disabled || lockedCorrect !== null) return; + if (disabled || coolingDown || lockedCorrect !== null) return; if (value === correctAnswer) { lockedCorrect = value; onAnswer(value); @@ -19,21 +23,34 @@ } else { wrongValue = value; onAnswer(value); - setTimeout(() => { - if (wrongValue === value) wrongValue = null; - }, 380); + coolingDown = true; + if (cooldownTimer) clearTimeout(cooldownTimer); + cooldownTimer = setTimeout(() => { + coolingDown = false; + wrongValue = null; + }, 900); } } - // Reset bei Aufgabenwechsel + // Reset NUR bei echtem Aufgabenwechsel. Der Effekt feuert über den choices-Prop auch + // bei jeder Falsch-Antwort (die den game-Store ändert) — daher per Referenzvergleich + // absichern, sonst würde die Denkpause sofort wieder aufgehoben. + let prevChoices: number[] | null = null; $effect(() => { - void choices; // dependency - lockedCorrect = null; - wrongValue = null; + if (choices !== prevChoices) { + prevChoices = choices; + lockedCorrect = null; + wrongValue = null; + coolingDown = false; + if (cooldownTimer) { + clearTimeout(cooldownTimer); + cooldownTimer = null; + } + } }); -
+
{#each choices as value (value)} @@ -66,12 +83,16 @@ color: var(--c-text); border-radius: 22px; box-shadow: 0 6px 0 #b9c4dc; - transition: transform 0.08s ease, background 0.15s ease, box-shadow 0.08s ease; + transition: transform 0.08s ease, background 0.15s ease, box-shadow 0.08s ease, opacity 0.2s ease; } .answer:active:not(:disabled) { transform: translateY(4px); box-shadow: 0 2px 0 #b9c4dc; } + /* Während der Denkpause die übrigen Knöpfe sanft dimmen (der falsche bleibt rot sichtbar). */ + .answers.cooling .answer:not(.wrong) { + opacity: 0.45; + } .answer.wrong { animation: shake 0.36s ease; background: #ffd0d0; diff --git a/src/lib/game/tasks.test.ts b/src/lib/game/tasks.test.ts index 9a9ab86..73e3788 100644 --- a/src/lib/game/tasks.test.ts +++ b/src/lib/game/tasks.test.ts @@ -29,10 +29,10 @@ describe('buildTask', () => { } }); - it('returns 3 choices for every target', () => { + it('returns 4 choices for every target', () => { for (const target of TARGETS) { const task = buildTask(target, 1); - expect(task.choices.length).toBe(3); + expect(task.choices.length).toBe(4); } }); }); diff --git a/src/lib/game/tasks.ts b/src/lib/game/tasks.ts index 3984ceb..a2ff6b4 100644 --- a/src/lib/game/tasks.ts +++ b/src/lib/game/tasks.ts @@ -3,7 +3,7 @@ // Eine Aufgabe für Zielzahl T besteht aus: // given: vorgegebene Zerlegungszahl in [0..T] (inkl. der trivialen 0/T-Zerlegung) // answer: T - given (das Kind muss diese tippen) -// choices: 3 große Buttons (richtige Antwort + 2 Distraktoren), gemischt +// choices: 4 große Buttons (richtige Antwort + 3 Distraktoren), gemischt // // Aufgabenfolge pro Spieldurchlauf: ein "Beutel" (TaskDeck) zieht alle möglichen // Vorgaben ohne Zurücklegen, mischt nach dem Leeren neu und verhindert direkte @@ -21,7 +21,7 @@ export type Task = { export const TARGETS: Target[] = [4, 5, 6, 7, 8, 9, 10]; -const DESIRED_CHOICES = 3; +const DESIRED_CHOICES = 4; function shuffle(arr: T[]): T[] { const a = arr.slice();