-
-
Perfekt zugeordnet!
-
Du hast alle 5 Paare fehlerfrei zusammengeführt.
-
+
+
+
+
+
Perfekt zugeordnet!
+
Du hast alle 5 Paare fehlerfrei zusammengeführt.
+
+
+
+
+
@@ -1877,10 +1904,6 @@
let isQuestionAnswered = false;
let currentQuizMode = 'highlighted';
- // Matcher Game State
- let matcherSelectedPhrase = null;
- let matcherSelectedTerm = null;
- let matcherMatchedCount = 0;
let currentMatcherPairs = [];
// Glossary State
@@ -2917,19 +2940,68 @@
repeatBtn.classList.add('hidden');
}
}
- // MATCHER GAME
+ // ==========================================
+ // PHRASEN-MATCHER GAME ENGINE ("Falsch ist falsch")
+ // ==========================================
+ let matcherFilter = 'highlighted'; // 'highlighted' (bevorzugt) | 'all' | 'zusatz'
+ let matcherSelectedPhrase = null;
+ let matcherSelectedTerm = null;
+ let matcherCorrectCount = 0;
+ let matcherFailedCount = 0;
+
+ function setMatcherFilter(filter) {
+ matcherFilter = filter;
+ ['matcherFilterKernBtn', 'matcherFilterAllBtn', 'matcherFilterZusatzBtn'].forEach(id => {
+ const el = document.getElementById(id);
+ if (el) el.className = 'px-2.5 sm:px-3 py-1.5 rounded-lg text-slate-600 hover:text-slate-900 transition font-semibold';
+ });
+
+ const activeMap = {
+ 'highlighted': 'matcherFilterKernBtn',
+ 'all': 'matcherFilterAllBtn',
+ 'zusatz': 'matcherFilterZusatzBtn'
+ };
+ const activeEl = document.getElementById(activeMap[filter]);
+ if (activeEl) {
+ activeEl.className = 'px-2.5 sm:px-3 py-1.5 rounded-lg bg-white text-indigo-700 shadow-sm font-bold transition';
+ }
+
+ initMatcherGame();
+ }
+
function initMatcherGame() {
matcherSelectedPhrase = null;
matcherSelectedTerm = null;
- matcherMatchedCount = 0;
+ matcherCorrectCount = 0;
+ matcherFailedCount = 0;
document.getElementById('matchScore').innerText = '0';
- document.getElementById('matcherWinBanner').classList.add('hidden');
+ document.getElementById('matchFailScore').innerText = '0';
+ document.getElementById('matcherResultBanner').classList.add('hidden');
- const shuffled = [...STILMITTEL_DATA].sort(() => Math.random() - 0.5).slice(0, 5);
+ let pool = STILMITTEL_DATA;
+ if (matcherFilter === 'highlighted') {
+ pool = STILMITTEL_DATA.filter(x => x.highlighted);
+ } else if (matcherFilter === 'zusatz') {
+ pool = STILMITTEL_DATA.filter(x => !x.highlighted);
+ }
+ if (pool.length < 5) pool = [...STILMITTEL_DATA];
+
+ const shuffled = [...pool].sort(() => Math.random() - 0.5).slice(0, 5);
currentMatcherPairs = shuffled;
- const phrases = shuffled.map(x => ({ id: x.id, text: x.examples[0] })).sort(() => Math.random() - 0.5);
- const terms = shuffled.map(x => ({ id: x.id, name: x.term })).sort(() => Math.random() - 0.5);
+ // Pick randomly from all 10 examples for rich variation
+ const phrases = shuffled.map(x => ({
+ id: x.id,
+ term: x.term,
+ text: x.examples[Math.floor(Math.random() * x.examples.length)],
+ resolved: false
+ })).sort(() => Math.random() - 0.5);
+
+ const terms = shuffled.map(x => ({
+ id: x.id,
+ name: x.term,
+ resolved: false
+ })).sort(() => Math.random() - 0.5);
const phrasesContainer = document.getElementById('matcherPhrasesContainer');
const termsContainer = document.getElementById('matcherTermsContainer');
@@ -2938,93 +3010,163 @@
termsContainer.innerHTML = '';
phrases.forEach(p => {
- const btn = document.createElement('div');
- btn.className = 'match-phrase-card p-4 bg-white rounded-2xl border-2 border-slate-200 text-sm font-serif italic text-slate-800 cursor-pointer hover:border-indigo-400 hover:bg-slate-50 transition shadow-sm select-none';
- btn.innerText = `„${p.text}“`;
- btn.onclick = () => selectMatcherPhrase(p.id, btn);
- phrasesContainer.appendChild(btn);
+ const card = document.createElement('div');
+ card.id = `match-phrase-${p.id}`;
+ card.className = 'match-phrase-card p-4 bg-white rounded-2xl border-2 border-slate-200 text-sm font-serif italic text-slate-800 cursor-pointer hover:border-indigo-400 hover:bg-slate-50 transition shadow-sm select-none flex items-start justify-between gap-2';
+
+ const cleanSpeechText = p.text.replace(/'/g, "\\'").replace(/"/g, '"');
+ card.innerHTML = `
+
„${p.text}“
+
+ `;
+ card.onclick = () => selectMatcherPhrase(p.id, card, p.term, p.text);
+ phrasesContainer.appendChild(card);
});
terms.forEach(t => {
- const btn = document.createElement('div');
- btn.className = 'match-term-card p-4 bg-white rounded-2xl border-2 border-slate-200 text-sm font-sans font-bold text-slate-800 cursor-pointer hover:border-indigo-400 hover:bg-slate-50 transition shadow-sm select-none flex items-center justify-between';
- btn.innerHTML = `
${t.name}`;
- btn.onclick = () => selectMatcherTerm(t.id, btn);
- termsContainer.appendChild(btn);
+ const card = document.createElement('div');
+ card.id = `match-term-${t.id}`;
+ card.className = 'match-term-card p-4 bg-white rounded-2xl border-2 border-slate-200 text-sm font-sans font-bold text-slate-800 cursor-pointer hover:border-indigo-400 hover:bg-slate-50 transition shadow-sm select-none flex items-center justify-between';
+ card.innerHTML = `
${t.name}`;
+ card.onclick = () => selectMatcherTerm(t.id, card, t.name);
+ termsContainer.appendChild(card);
});
}
- function selectMatcherPhrase(id, el) {
- if (el.classList.contains('opacity-40')) return;
+ function selectMatcherPhrase(id, el, term, text) {
+ if (el.classList.contains('pointer-events-none')) return;
document.querySelectorAll('.match-phrase-card').forEach(c => {
- if (!c.classList.contains('opacity-40')) {
- c.classList.remove('border-indigo-600', 'bg-indigo-50');
+ if (!c.classList.contains('pointer-events-none')) {
+ c.classList.remove('border-indigo-600', 'bg-indigo-50', 'ring-2', 'ring-indigo-300');
c.classList.add('border-slate-200');
}
});
- matcherSelectedPhrase = { id, el };
+ matcherSelectedPhrase = { id, el, term, text };
el.classList.remove('border-slate-200');
- el.classList.add('border-indigo-600', 'bg-indigo-50');
+ el.classList.add('border-indigo-600', 'bg-indigo-50', 'ring-2', 'ring-indigo-300');
playTone('flip');
checkMatcherMatch();
}
- function selectMatcherTerm(id, el) {
- if (el.classList.contains('opacity-40')) return;
+ function selectMatcherTerm(id, el, name) {
+ if (el.classList.contains('pointer-events-none')) return;
document.querySelectorAll('.match-term-card').forEach(c => {
- if (!c.classList.contains('opacity-40')) {
- c.classList.remove('border-indigo-600', 'bg-indigo-50');
+ if (!c.classList.contains('pointer-events-none')) {
+ c.classList.remove('border-indigo-600', 'bg-indigo-50', 'ring-2', 'ring-indigo-300');
c.classList.add('border-slate-200');
}
});
- matcherSelectedTerm = { id, el };
+ matcherSelectedTerm = { id, el, name };
el.classList.remove('border-slate-200');
- el.classList.add('border-indigo-600', 'bg-indigo-50');
+ el.classList.add('border-indigo-600', 'bg-indigo-50', 'ring-2', 'ring-indigo-300');
playTone('flip');
checkMatcherMatch();
}
function checkMatcherMatch() {
- if (matcherSelectedPhrase && matcherSelectedTerm) {
- if (matcherSelectedPhrase.id === matcherSelectedTerm.id) {
- playTone('success');
- const pEl = matcherSelectedPhrase.el;
- const tEl = matcherSelectedTerm.el;
+ if (!matcherSelectedPhrase || !matcherSelectedTerm) return;
- pEl.className = 'p-4 bg-emerald-50 border-2 border-emerald-400 text-sm font-serif italic text-emerald-900 rounded-2xl opacity-40 pointer-events-none transition';
- tEl.className = 'p-4 bg-emerald-50 border-2 border-emerald-400 text-sm font-sans font-bold text-emerald-900 rounded-2xl opacity-40 pointer-events-none transition flex items-center justify-between';
- tEl.innerHTML += `
`;
+ const pObj = matcherSelectedPhrase;
+ const tObj = matcherSelectedTerm;
+ const isMatch = pObj.id === tObj.id;
- matcherMatchedCount++;
- document.getElementById('matchScore').innerText = matcherMatchedCount;
+ if (isMatch) {
+ // Richtig zugeordnet!
+ playTone('success');
+ matcherCorrectCount++;
+ document.getElementById('matchScore').innerText = matcherCorrectCount;
- matcherSelectedPhrase = null;
- matcherSelectedTerm = null;
+ // Phrase dauerhaft als RICHTIG sperren
+ pObj.el.className = 'p-4 bg-emerald-50 border-2 border-emerald-500 text-sm font-serif italic text-emerald-950 rounded-2xl transition shadow-sm pointer-events-none flex items-start justify-between gap-2';
+ pObj.el.innerHTML = `
+
„${pObj.text}“
+
+ Richtig
+
+ `;
- if (matcherMatchedCount === 5) {
- playTone('win');
- document.getElementById('matcherWinBanner').classList.remove('hidden');
- }
- } else {
- playTone('error');
- const pEl = matcherSelectedPhrase.el;
- const tEl = matcherSelectedTerm.el;
+ // Begriff dauerhaft als RICHTIG sperren
+ tObj.el.className = 'p-4 bg-emerald-50 border-2 border-emerald-500 text-sm font-sans font-bold text-emerald-950 rounded-2xl transition shadow-sm pointer-events-none flex items-center justify-between';
+ tObj.el.innerHTML = `
${tObj.name}`;
- pEl.classList.add('border-rose-500', 'bg-rose-50');
- tEl.classList.add('border-rose-500', 'bg-rose-50');
+ addXP(20, 'Matcher Paar gelöst');
+ matcherSelectedPhrase = null;
+ matcherSelectedTerm = null;
+ } else {
+ // "FALSCH IST FALSCH!" - Ein Fehlversuch verbrennt dieses Zitat unwiderruflich!
+ playTone('error');
+ matcherFailedCount++;
+ document.getElementById('matchFailScore').innerText = matcherFailedCount;
- setTimeout(() => {
- pEl.classList.remove('border-rose-500', 'bg-rose-50', 'border-indigo-600', 'bg-indigo-50');
- tEl.classList.remove('border-rose-500', 'bg-rose-50', 'border-indigo-600', 'bg-indigo-50');
- pEl.classList.add('border-slate-200');
- tEl.classList.add('border-slate-200');
- matcherSelectedPhrase = null;
- matcherSelectedTerm = null;
- }, 350);
+ // Phrase DAUERHAFT als FALSCH sperren und Lösung aufdecken
+ pObj.el.className = 'p-4 bg-rose-50 border-2 border-rose-500 text-sm font-serif italic text-rose-950 rounded-2xl transition shadow-sm pointer-events-none space-y-1.5';
+ pObj.el.innerHTML = `
+
„${pObj.text}“
+
+
+ Lösung: ${pObj.term}
+
+ `;
+
+ // Begriff blinkt kurz rot auf und wird dann wieder neutral freigegeben (für andere Zitate)
+ tObj.el.classList.add('border-rose-500', 'bg-rose-50');
+ setTimeout(() => {
+ tObj.el.classList.remove('border-rose-500', 'bg-rose-50', 'border-indigo-600', 'bg-indigo-50', 'ring-2', 'ring-indigo-300');
+ tObj.el.classList.add('border-slate-200');
+ }, 450);
+
+ // Als Schwachstelle speichern für gezieltes Nachlernen
+ if (!quizMistakes.includes(pObj.id)) {
+ quizMistakes.push(pObj.id);
+ localStorage.setItem('rhetorik_quiz_mistakes', JSON.stringify(quizMistakes));
+ updateQuizMistakesBadge();
}
+
+ matcherSelectedPhrase = null;
+ matcherSelectedTerm = null;
+ }
+
+ // Prüfen, ob alle 5 Paare versucht wurden (richtig + falsch = 5)
+ if (matcherCorrectCount + matcherFailedCount === 5) {
+ setTimeout(finishMatcherRound, 500);
}
}
+ function finishMatcherRound() {
+ const banner = document.getElementById('matcherResultBanner');
+ const title = document.getElementById('matcherResultTitle');
+ const subtitle = document.getElementById('matcherResultSubtitle');
+ const icon = document.getElementById('matcherResultIcon');
+ const weakBtn = document.getElementById('matcherWeakspotsBtn');
+
+ banner.classList.remove('hidden', 'bg-emerald-600', 'bg-indigo-600', 'bg-slate-900', 'bg-rose-600');
+
+ if (matcherCorrectCount === 5) {
+ playTone('win');
+ banner.classList.add('bg-emerald-600');
+ icon.innerHTML = '
';
+ title.innerText = 'Perfekt zugeordnet! 🏆';
+ subtitle.innerText = 'Alle 5 Paare auf Anhieb fehlerfrei erkannt. Keine Fehler gemacht!';
+ addXP(60, 'Matcher fehlerfrei');
+ weakBtn.classList.add('hidden');
+ } else if (matcherCorrectCount >= 3) {
+ playTone(matcherCorrectCount >= 4 ? 'win' : 'flip');
+ banner.classList.add('bg-indigo-600');
+ icon.innerHTML = '
';
+ title.innerText = `Runde beendet: ${matcherCorrectCount} von 5 richtig!`;
+ subtitle.innerText = `Falsch ist falsch: ${matcherFailedCount} Fehler gemacht. Die verpassten Begriffe wurden in deine Schwachstellen übernommen.`;
+ weakBtn.classList.remove('hidden');
+ } else {
+ playTone('error');
+ banner.classList.add('bg-slate-900');
+ icon.innerHTML = '
';
+ title.innerText = `Ergebnis: ${matcherCorrectCount} von 5 Paaren richtig`;
+ subtitle.innerText = `Falsch ist falsch: ${matcherFailedCount} Fehlversuche. Wiederhole die Begriffe gezielt im Schwachstellen-Trainer oder Glossar.`;
+ weakBtn.classList.remove('hidden');
+ }
+ }
// GLOSSAR & SUCHE
function setGlossaryFilter(filter) {
currentGlossaryFilter = filter;
diff --git a/www/sw.js b/www/sw.js
index 0d79865..7082007 100644
--- a/www/sw.js
+++ b/www/sw.js
@@ -1,4 +1,4 @@
-const CACHE_NAME = 'rhetorikmaster-v9';
+const CACHE_NAME = 'rhetorikmaster-v10';
const STATIC_ASSETS = [
'/',
'/index.html',