// === GRAMMAR DISCOVERY GAME === // Interactive game for discovering and learning grammar patterns class GrammarDiscovery { constructor({ container, content, onScoreUpdate, onGameEnd }) { this.container = container; this.content = content; this.onScoreUpdate = onScoreUpdate; this.onGameEnd = onGameEnd; this.score = 0; // ROTATION SYSTEM FOR FOCUSED CONCEPT LEARNING this.rotationSteps = [ 'explanation-basic', // 1. Explication de base (langue originale) 'examples-simple', // 2. Exemples simples 'exercise-basic', // 3. Exercices de base 'explanation-detailed', // 4. Explication détaillée 'examples-complex', // 5. Exemples complexes 'exercise-intermediate', // 6. Exercices intermédiaires 'summary', // 7. Résumé du concept 'exercise-global' // 8. Exercice global final ]; this.currentStep = 0; this.grammarConcept = null; // Single focused concept (user selected) this.conceptData = {}; this.stepProgress = {}; this.availableConcepts = []; // All available grammar concepts this.conceptSelected = false; // Whether user has chosen a concept this.injectCSS(); this.extractAvailableConcepts(); this.init(); } injectCSS() { if (document.getElementById('grammar-discovery-styles')) return; const styleSheet = document.createElement('style'); styleSheet.id = 'grammar-discovery-styles'; styleSheet.textContent = ` .grammar-discovery { display: flex; flex-direction: column; height: 100%; font-family: 'Arial', sans-serif; } .grammar-hud { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; display: flex; justify-content: space-between; align-items: center; border-radius: 10px 10px 0 0; } .grammar-phase { font-size: 18px; font-weight: bold; display: flex; align-items: center; gap: 10px; } .phase-icon { font-size: 24px; } .grammar-content { flex: 1; display: flex; flex-direction: column; padding: 20px; background: linear-gradient(145deg, #f8f9ff, #e6e9ff); overflow-y: auto; } .rule-card { background: white; border-radius: 15px; padding: 25px; margin-bottom: 20px; box-shadow: 0 8px 32px rgba(102, 126, 234, 0.1); border: 2px solid transparent; transition: all 0.3s ease; } .rule-card.active { border-color: #667eea; transform: translateY(-2px); box-shadow: 0 12px 40px rgba(102, 126, 234, 0.2); } .rule-title { font-size: 24px; font-weight: bold; color: #4c51bf; margin-bottom: 15px; display: flex; align-items: center; gap: 10px; } .rule-explanation { font-size: 16px; line-height: 1.6; color: #4a5568; margin-bottom: 20px; background: #f7fafc; padding: 15px; border-radius: 8px; border-left: 4px solid #667eea; } .examples-section { margin-top: 20px; } .example-item { background: #ffffff; border: 2px solid #e2e8f0; border-radius: 12px; padding: 20px; margin-bottom: 15px; transition: all 0.3s ease; cursor: pointer; } .example-item:hover { border-color: #667eea; transform: translateX(5px); } .example-item.revealed { border-color: #48bb78; background: linear-gradient(135deg, #f0fff4, #c6f6d5); } .chinese-text { font-size: 22px; font-weight: bold; color: #2d3748; margin-bottom: 8px; } .english-text { font-size: 18px; color: #4a5568; margin-bottom: 8px; } .pronunciation { font-size: 16px; color: #718096; font-style: italic; margin-bottom: 10px; } .explanation-text { font-size: 14px; color: #667eea; background: #edf2f7; padding: 10px; border-radius: 6px; display: none; } .example-item.revealed .explanation-text { display: block; animation: fadeIn 0.5s ease; } .discovery-controls { display: flex; gap: 15px; margin-top: 20px; justify-content: center; } .discover-btn { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; padding: 12px 25px; border-radius: 25px; font-size: 16px; font-weight: bold; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); } .discover-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4); } .discover-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } .practice-question { background: white; border-radius: 15px; padding: 25px; margin-bottom: 20px; box-shadow: 0 8px 32px rgba(102, 126, 234, 0.1); } .question-text { font-size: 20px; color: #2d3748; margin-bottom: 20px; line-height: 1.6; } .options-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 20px; } .option-btn { background: white; border: 2px solid #e2e8f0; border-radius: 12px; padding: 15px; font-size: 16px; cursor: pointer; transition: all 0.3s ease; text-align: center; } .option-btn:hover { border-color: #667eea; background: #f7fafc; } .option-btn.correct { border-color: #48bb78; background: linear-gradient(135deg, #f0fff4, #c6f6d5); color: #22543d; } .option-btn.incorrect { border-color: #f56565; background: linear-gradient(135deg, #fed7d7, #feb2b2); color: #742a2a; } .feedback { background: #f7fafc; border-radius: 10px; padding: 15px; margin-top: 15px; border-left: 4px solid #667eea; display: none; } .feedback.show { display: block; animation: slideIn 0.3s ease; } .progress-bar { background: #e2e8f0; height: 6px; border-radius: 3px; margin: 10px 0; overflow: hidden; } .progress-fill { background: linear-gradient(90deg, #667eea, #764ba2); height: 100%; border-radius: 3px; transition: width 0.5s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideIn { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } } .concept-selector { background: white; border-radius: 15px; padding: 30px; margin: 20px 0; box-shadow: 0 8px 32px rgba(102, 126, 234, 0.1); text-align: center; } .selector-title { font-size: 24px; font-weight: bold; color: #4c51bf; margin-bottom: 20px; } .selector-description { font-size: 16px; color: #4a5568; margin-bottom: 25px; line-height: 1.6; } .concept-dropdown { width: 100%; max-width: 400px; padding: 15px; font-size: 16px; border: 2px solid #e2e8f0; border-radius: 10px; background: white; margin-bottom: 20px; cursor: pointer; transition: all 0.3s ease; } .concept-dropdown:hover { border-color: #667eea; } .concept-dropdown:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } .concept-preview { background: #f7fafc; border-radius: 10px; padding: 20px; margin: 20px 0; text-align: left; display: none; } .concept-preview.show { display: block; animation: fadeIn 0.3s ease; } .preview-title { font-size: 18px; font-weight: bold; color: #2d3748; margin-bottom: 10px; } .preview-explanation { font-size: 14px; color: #4a5568; margin-bottom: 15px; } .preview-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; font-size: 12px; color: #718096; } .stat-item { background: white; padding: 8px; border-radius: 6px; text-align: center; } .phase-complete { text-align: center; padding: 40px; background: linear-gradient(135deg, #f0fff4, #c6f6d5); border-radius: 15px; margin: 20px 0; } .complete-icon { font-size: 48px; margin-bottom: 20px; } .complete-title { font-size: 24px; font-weight: bold; color: #22543d; margin-bottom: 15px; } .tts-controls { display: flex; gap: 10px; align-items: center; margin-top: 10px; } .tts-btn { background: #667eea; color: white; border: none; border-radius: 20px; padding: 8px 15px; cursor: pointer; font-size: 14px; transition: all 0.2s ease; } .tts-btn:hover { background: #5a67d8; transform: scale(1.05); } `; document.head.appendChild(styleSheet); } extractAvailableConcepts() { if (!this.content || !this.content.grammar) { console.error('No grammar content found for Grammar Discovery game'); return; } // GET ALL AVAILABLE CONCEPTS for selection this.availableConcepts = Object.entries(this.content.grammar).map(([key, conceptData]) => ({ id: key, title: conceptData.title, explanation: conceptData.explanation, data: conceptData })); console.log(`🎯 Found ${this.availableConcepts.length} grammar concepts available for selection`); } selectConcept(conceptId) { const selectedConcept = this.availableConcepts.find(c => c.id === conceptId); if (!selectedConcept) { console.error('Concept not found:', conceptId); return; } this.grammarConcept = conceptId; this.conceptData = selectedConcept.data; this.conceptSelected = true; console.log(`🎯 Selected concept: ${this.grammarConcept}`); // ORGANIZE CONTENT BY DIFFICULTY LEVELS this.organizeConceptContent(); // Start the rotation cycle this.startRotationCycle(); } organizeConceptContent() { const concept = this.conceptData; // BASIC EXAMPLES (first 2-3 simple ones) this.simpleExamples = []; this.complexExamples = []; if (concept.examples) { this.simpleExamples = concept.examples.slice(0, 3); this.complexExamples = concept.examples.slice(3); } // Get examples from detailed explanation sections if (concept.detailedExplanation) { Object.values(concept.detailedExplanation).forEach(section => { if (section.examples) { // First 2 go to simple, rest to complex const sectionSimple = section.examples.slice(0, 2); const sectionComplex = section.examples.slice(2); this.simpleExamples.push(...sectionSimple); this.complexExamples.push(...sectionComplex); } }); } // ORGANIZE EXERCISES BY DIFFICULTY this.basicExercises = []; this.intermediateExercises = []; this.globalExercises = []; if (this.content.fillInBlanks) { this.content.fillInBlanks.forEach(exercise => { // Accept all fillInBlanks for focused grammar lesson content const isGrammarLesson = this.content.type === 'grammar_course'; const isRelevant = isGrammarLesson || exercise.grammarFocus === this.grammarConcept || exercise.grammarFocus === 'completion' || exercise.grammarFocus === 'change-of-state'; if (isRelevant) { // Determine difficulty by sentence complexity if (exercise.sentence.length < 15) { this.basicExercises.push(exercise); } else { this.intermediateExercises.push(exercise); } } }); } if (this.content.corrections) { this.content.corrections.forEach(correction => { // Accept all corrections for focused grammar lesson content const isGrammarLesson = this.content.type === 'grammar_course'; const isRelevant = isGrammarLesson || correction.grammarFocus === this.grammarConcept; if (isRelevant) { this.intermediateExercises.push({ type: 'correction', question: 'Which sentence is correct?', options: [correction.correct, correction.incorrect], correctAnswer: correction.correct, explanation: correction.explanation }); } }); } // Global exercises combine multiple concepts this.globalExercises = [...this.basicExercises, ...this.intermediateExercises]; this.globalExercises = this.shuffleArray(this.globalExercises).slice(0, 5); console.log(`📊 Content organized: - Simple examples: ${this.simpleExamples.length} - Complex examples: ${this.complexExamples.length} - Basic exercises: ${this.basicExercises.length} - Intermediate exercises: ${this.intermediateExercises.length} - Global exercises: ${this.globalExercises.length}`); } init() { this.container.innerHTML = `
🎯 Select Grammar Concept
Score: 0
`; this.showConceptSelector(); } showConceptSelector() { if (this.availableConcepts.length === 0) { console.error('No concepts available for selection'); return; } const contentDiv = document.getElementById('grammar-content'); contentDiv.innerHTML = `
🎯 Choose Grammar Concept
Select which grammar concept you want to focus on for intensive study with our 8-step rotation system.
`; // Store reference for global access window.currentGrammarGame = this; } previewConcept(conceptId) { const previewDiv = document.getElementById('concept-preview'); const startBtn = document.getElementById('start-btn'); if (!conceptId) { previewDiv.classList.remove('show'); startBtn.disabled = true; return; } const concept = this.availableConcepts.find(c => c.id === conceptId); if (!concept) return; // Calculate stats for this concept this.grammarConcept = conceptId; this.conceptData = concept.data; this.organizeConceptContent(); previewDiv.innerHTML = `
${concept.title}
${concept.explanation}
${this.simpleExamples.length}
Simple Examples
${this.complexExamples.length}
Complex Examples
${this.basicExercises.length}
Basic Exercises
${this.intermediateExercises.length}
Intermediate Exercises
${this.globalExercises.length}
Final Test Questions
`; previewDiv.classList.add('show'); startBtn.disabled = false; } startSelectedConcept() { const dropdown = document.getElementById('concept-dropdown'); const selectedConceptId = dropdown.value; if (!selectedConceptId) { alert('Please select a grammar concept first!'); return; } // Update UI to show rotation progress document.getElementById('step-progress').style.display = 'block'; document.getElementById('phase-icon').textContent = '📚'; document.getElementById('phase-text').textContent = 'Basic Explanation'; this.selectConcept(selectedConceptId); } startRotationCycle() { this.currentStep = 0; this.showCurrentStep(); } showCurrentStep() { const stepType = this.rotationSteps[this.currentStep]; const stepNumber = this.currentStep + 1; document.getElementById('current-step').textContent = stepNumber; // Update phase icon and text based on step const phaseInfo = this.getPhaseInfo(stepType); document.getElementById('phase-icon').textContent = phaseInfo.icon; document.getElementById('phase-text').textContent = phaseInfo.text; // Store reference for global access window.currentGrammarGame = this; // Show content for current step switch (stepType) { case 'explanation-basic': this.showBasicExplanation(); break; case 'examples-simple': this.showSimpleExamples(); break; case 'exercise-basic': this.showBasicExercises(); break; case 'explanation-detailed': this.showDetailedExplanation(); break; case 'examples-complex': this.showComplexExamples(); break; case 'exercise-intermediate': this.showIntermediateExercises(); break; case 'summary': this.showSummary(); break; case 'exercise-global': this.showGlobalExercises(); break; } } getPhaseInfo(stepType) { const phaseMap = { 'explanation-basic': { icon: '📚', text: 'Basic Explanation' }, 'examples-simple': { icon: '💡', text: 'Simple Examples' }, 'exercise-basic': { icon: '✏️', text: 'Basic Practice' }, 'explanation-detailed': { icon: '🔍', text: 'Detailed Explanation' }, 'examples-complex': { icon: '🧩', text: 'Complex Examples' }, 'exercise-intermediate': { icon: '💪', text: 'Intermediate Practice' }, 'summary': { icon: '📝', text: 'Summary' }, 'exercise-global': { icon: '🏆', text: 'Final Test' } }; return phaseMap[stepType] || { icon: '❓', text: 'Unknown' }; } nextStep() { this.currentStep++; if (this.currentStep >= this.rotationSteps.length) { this.completeRotation(); } else { this.showCurrentStep(); } } completeRotation() { const contentDiv = document.getElementById('grammar-content'); contentDiv.innerHTML = `
🎉
Grammar Concept Mastered!

You've completed the full rotation for: ${this.conceptData.title}

Final Score: ${this.score}

`; this.onGameEnd(this.score); } // === ROTATION STEP IMPLEMENTATIONS === showBasicExplanation() { const concept = this.conceptData; const contentDiv = document.getElementById('grammar-content'); contentDiv.innerHTML = `
📚 ${concept.title}
${concept.explanation}
${concept.mainRules ? `

🎯 Key Rules:

` : ''}
`; } showSimpleExamples() { const contentDiv = document.getElementById('grammar-content'); contentDiv.innerHTML = `
💡 Simple Examples
${this.simpleExamples.map((example, index) => `
${example.chinese}
${example.english}
${example.pronunciation || ''}
${example.explanation || example.breakdown || ''}
`).join('')}
`; // Auto-play first example if (this.simpleExamples.length > 0) { setTimeout(() => { this.speakChinese(this.simpleExamples[0].chinese); }, 1000); } } showBasicExercises() { if (this.basicExercises.length === 0) { this.nextStep(); return; } this.currentExerciseSet = this.basicExercises; this.currentExerciseIndex = 0; this.showExercise('basic'); } showDetailedExplanation() { const concept = this.conceptData; const contentDiv = document.getElementById('grammar-content'); let detailsHtml = ''; if (concept.detailedExplanation) { detailsHtml = Object.entries(concept.detailedExplanation).map(([key, section]) => `

🔍 ${section.title}

${section.explanation}

${section.pattern ? `
Pattern: ${section.pattern}
` : ''}
`).join(''); } contentDiv.innerHTML = `
🔍 Detailed Explanation
${detailsHtml} ${concept.commonMistakes ? `

⚠️ Common Mistakes:

${concept.commonMistakes.map(mistake => `
❌ ${mistake.wrong}
✅ ${mistake.correct}
${mistake.explanation}
`).join('')}
` : ''}
`; } showComplexExamples() { const contentDiv = document.getElementById('grammar-content'); contentDiv.innerHTML = `
🧩 Complex Examples
${this.complexExamples.map((example, index) => `
${example.chinese}
${example.english}
${example.pronunciation || ''}
${example.explanation || example.breakdown || ''}
`).join('')}
`; } showIntermediateExercises() { if (this.intermediateExercises.length === 0) { this.nextStep(); return; } this.currentExerciseSet = this.intermediateExercises; this.currentExerciseIndex = 0; this.showExercise('intermediate'); } showSummary() { const concept = this.conceptData; const contentDiv = document.getElementById('grammar-content'); contentDiv.innerHTML = `
📝 Summary: ${concept.title}

🎯 What You've Learned:

Basic Concept:
${concept.explanation}
${concept.mainRules ? `
Key Rules:
${concept.mainRules.map(rule => `• ${rule}`).join('
')}
` : ''} ${concept.practicePoints ? `
Practice Points:
${concept.practicePoints.map(point => `• ${point}`).join('
')}
` : ''}
`; } showGlobalExercises() { if (this.globalExercises.length === 0) { this.completeRotation(); return; } this.currentExerciseSet = this.globalExercises; this.currentExerciseIndex = 0; this.showExercise('global'); } // === UNIFIED EXERCISE SYSTEM === showExercise(type) { const exercise = this.currentExerciseSet[this.currentExerciseIndex]; if (!exercise) { this.nextStep(); return; } const contentDiv = document.getElementById('grammar-content'); const typeInfo = { 'basic': { title: '✏️ Basic Practice', color: '#48bb78' }, 'intermediate': { title: '💪 Intermediate Practice', color: '#3182ce' }, 'global': { title: '🏆 Final Test', color: '#805ad5' } }; const info = typeInfo[type] || typeInfo['basic']; if (exercise.type === 'correction') { contentDiv.innerHTML = `
${info.title}
${exercise.question}
${exercise.options.map(option => ` `).join('')}
Explanation: ${exercise.explanation}
Exercise ${this.currentExerciseIndex + 1} of ${this.currentExerciseSet.length}
`; } else { // Fill in the blank contentDiv.innerHTML = `
${info.title}
Fill in the blank: ${exercise.sentence}
${exercise.options.map(option => ` `).join('')}
Explanation: ${exercise.explanation}
Exercise ${this.currentExerciseIndex + 1} of ${this.currentExerciseSet.length}
`; } } selectAnswer(selected, correct, exerciseType) { const buttons = document.querySelectorAll('.option-btn'); const feedback = document.getElementById('feedback'); buttons.forEach(btn => { btn.disabled = true; if (btn.textContent.trim() === correct) { btn.classList.add('correct'); } else if (btn.textContent.trim() === selected && selected !== correct) { btn.classList.add('incorrect'); } }); // Scoring based on exercise type if (selected === correct) { const points = exerciseType === 'global' ? 30 : (exerciseType === 'intermediate' ? 20 : 15); this.score += points; } else { this.score = Math.max(0, this.score - 5); } this.onScoreUpdate(this.score); document.getElementById('score-value').textContent = this.score; feedback.classList.add('show'); setTimeout(() => { this.currentExerciseIndex++; if (this.currentExerciseIndex >= this.currentExerciseSet.length) { // Finished this exercise set this.nextStep(); } else { // Show next exercise in set this.showExercise(exerciseType); } }, 2500); } restart() { this.score = 0; this.currentStep = 0; this.currentExerciseIndex = 0; this.conceptSelected = false; this.grammarConcept = null; this.conceptData = {}; // Reset UI to concept selector document.getElementById('score-value').textContent = '0'; document.getElementById('phase-icon').textContent = '🎯'; document.getElementById('phase-text').textContent = 'Select Grammar Concept'; document.getElementById('step-progress').style.display = 'none'; this.onScoreUpdate(0); this.showConceptSelector(); } // TTS Functions speakChinese(text) { if (window.SettingsManager && window.SettingsManager.speak) { window.SettingsManager.speak(text, { lang: 'zh-CN', rate: 0.8 }); } } speakEnglish(text) { if (window.SettingsManager && window.SettingsManager.speak) { window.SettingsManager.speak(text, { lang: 'en-US', rate: 0.9 }); } } // Utility Functions shuffleArray(array) { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; } restart() { this.score = 0; this.currentPhase = 'discovery'; this.currentRule = 0; this.currentExampleIndex = 0; this.currentPracticeIndex = 0; this.practiceQuestions = this.shuffleArray(this.practiceQuestions); document.getElementById('phase-text').innerHTML = ` 🔍 Discovery Phase `; document.getElementById('score-value').textContent = '0'; this.onScoreUpdate(0); this.startDiscovery(); } start() { // Game starts automatically in constructor } destroy() { // Cleanup const styleSheet = document.getElementById('grammar-discovery-styles'); if (styleSheet) { styleSheet.remove(); } if (window.currentGrammarGame === this) { delete window.currentGrammarGame; } } } // Export to global window.GameModules = window.GameModules || {}; window.GameModules.GrammarDiscovery = GrammarDiscovery;