// === MODULE QUIZ GAME ===
class QuizGame {
constructor(options) {
this.container = options.container;
this.content = options.content;
this.onScoreUpdate = options.onScoreUpdate || (() => {});
this.onGameEnd = options.onGameEnd || (() => {});
// Game state
this.vocabulary = [];
this.currentQuestion = 0;
this.totalQuestions = 10;
this.score = 0;
this.correctAnswers = 0;
this.currentQuestionData = null;
this.hasAnswered = false;
// Extract vocabulary
this.vocabulary = this.extractVocabulary(this.content);
this.init();
}
init() {
// Check if we have enough vocabulary
if (!this.vocabulary || this.vocabulary.length < 4) {
console.error('Not enough vocabulary for Quiz Game');
this.showInitError();
return;
}
// Adjust total questions based on available vocabulary
this.totalQuestions = Math.min(this.totalQuestions, this.vocabulary.length);
this.createGameInterface();
this.generateQuestion();
}
showInitError() {
this.container.innerHTML = `
❌ Error loading
This content doesn't have enough vocabulary for Quiz Game.
The game needs at least 4 vocabulary items.
`;
}
extractVocabulary(content) {
let vocabulary = [];
console.log('📝 Extracting vocabulary from:', content?.name || 'content');
// Use raw module content if available
if (content.rawContent) {
console.log('📦 Using raw module content');
return this.extractVocabularyFromRaw(content.rawContent);
}
// Modern format with contentItems
if (content.contentItems && Array.isArray(content.contentItems)) {
console.log('🆕 ContentItems format detected');
const vocabItems = content.contentItems.filter(item => item.type === 'vocabulary');
if (vocabItems.length > 0) {
vocabulary = vocabItems[0].items || [];
}
}
// Legacy format with vocabulary array
else if (content.vocabulary && Array.isArray(content.vocabulary)) {
console.log('📚 Vocabulary array format detected');
vocabulary = content.vocabulary;
}
return this.finalizeVocabulary(vocabulary);
}
extractVocabularyFromRaw(rawContent) {
console.log('🔧 Extracting from raw content:', rawContent.name || 'Module');
let vocabulary = [];
// Check vocabulary object format (key-value pairs)
if (rawContent.vocabulary && typeof rawContent.vocabulary === 'object' && !Array.isArray(rawContent.vocabulary)) {
vocabulary = Object.entries(rawContent.vocabulary).map(([english, translation]) => ({
english: english,
french: translation
}));
console.log(`📝 ${vocabulary.length} vocabulary pairs extracted from object`);
}
// Check vocabulary array format
else if (rawContent.vocabulary && Array.isArray(rawContent.vocabulary)) {
vocabulary = rawContent.vocabulary;
console.log(`📚 ${vocabulary.length} vocabulary items extracted from array`);
}
return this.finalizeVocabulary(vocabulary);
}
finalizeVocabulary(vocabulary) {
// Filter and validate vocabulary
vocabulary = vocabulary.filter(item =>
item &&
item.english &&
(item.french || item.translation || item.chinese)
).map(item => ({
english: item.english,
french: item.french || item.translation || item.chinese
}));
if (vocabulary.length === 0) {
console.error('❌ No valid vocabulary found');
// Demo vocabulary as fallback
vocabulary = [
{ english: "cat", french: "chat" },
{ english: "dog", french: "chien" },
{ english: "house", french: "maison" },
{ english: "car", french: "voiture" },
{ english: "book", french: "livre" },
{ english: "water", french: "eau" },
{ english: "food", french: "nourriture" },
{ english: "friend", french: "ami" }
];
console.warn('🚨 Using demo vocabulary');
}
// Shuffle vocabulary for random questions
vocabulary = vocabulary.sort(() => Math.random() - 0.5);
console.log(`✅ Quiz Game: ${vocabulary.length} vocabulary items finalized`);
return vocabulary;
}
createGameInterface() {
this.container.innerHTML = `
1 / ${this.totalQuestions}
Score: 0
Choose the correct translation!
`;
this.setupEventListeners();
}
setupEventListeners() {
document.getElementById('next-btn').addEventListener('click', () => this.nextQuestion());
document.getElementById('restart-btn').addEventListener('click', () => this.restart());
}
generateQuestion() {
if (this.currentQuestion >= this.totalQuestions) {
this.gameComplete();
return;
}
this.hasAnswered = false;
// Get current vocabulary item
const correctAnswer = this.vocabulary[this.currentQuestion];
// Generate 3 wrong answers from other vocabulary items
const wrongAnswers = this.vocabulary
.filter(item => item !== correctAnswer)
.sort(() => Math.random() - 0.5)
.slice(0, 3)
.map(item => item.french);
// Combine and shuffle all options
const allOptions = [correctAnswer.french, ...wrongAnswers].sort(() => Math.random() - 0.5);
this.currentQuestionData = {
question: correctAnswer.english,
correctAnswer: correctAnswer.french,
options: allOptions
};
this.renderQuestion();
this.updateProgress();
}
renderQuestion() {
const { question, options } = this.currentQuestionData;
// Update question text
document.getElementById('question-text').innerHTML = `
What is the translation of "${question}"?
`;
// Clear and generate options
const optionsArea = document.getElementById('options-area');
optionsArea.innerHTML = '';
options.forEach((option, index) => {
const optionButton = document.createElement('button');
optionButton.className = 'quiz-option';
optionButton.textContent = option;
optionButton.addEventListener('click', () => this.selectAnswer(option, optionButton));
optionsArea.appendChild(optionButton);
});
// Hide next button
document.getElementById('next-btn').style.display = 'none';
}
selectAnswer(selectedAnswer, buttonElement) {
if (this.hasAnswered) return;
this.hasAnswered = true;
const isCorrect = selectedAnswer === this.currentQuestionData.correctAnswer;
// Disable all option buttons and show results
const allOptions = document.querySelectorAll('.quiz-option');
allOptions.forEach(btn => {
btn.disabled = true;
if (btn.textContent === this.currentQuestionData.correctAnswer) {
btn.classList.add('correct');
} else if (btn === buttonElement && !isCorrect) {
btn.classList.add('wrong');
} else if (btn !== buttonElement && btn.textContent !== this.currentQuestionData.correctAnswer) {
btn.classList.add('disabled');
}
});
// Update score and feedback
if (isCorrect) {
this.correctAnswers++;
this.score += 10;
this.showFeedback('✅ Correct! Well done!', 'success');
} else {
this.score = Math.max(0, this.score - 5);
this.showFeedback(`❌ Wrong! Correct answer: "${this.currentQuestionData.correctAnswer}"`, 'error');
}
this.updateScore();
// Show next button or finish
if (this.currentQuestion < this.totalQuestions - 1) {
document.getElementById('next-btn').style.display = 'block';
} else {
setTimeout(() => this.gameComplete(), 2000);
}
}
nextQuestion() {
this.currentQuestion++;
this.generateQuestion();
}
updateProgress() {
const progressFill = document.getElementById('progress-fill');
const progressPercent = ((this.currentQuestion + 1) / this.totalQuestions) * 100;
progressFill.style.width = `${progressPercent}%`;
document.getElementById('question-counter').textContent =
`${this.currentQuestion + 1} / ${this.totalQuestions}`;
}
updateScore() {
document.getElementById('score-display').textContent = `Score: ${this.score}`;
this.onScoreUpdate(this.score);
}
gameComplete() {
const accuracy = Math.round((this.correctAnswers / this.totalQuestions) * 100);
// Bonus for high accuracy
if (accuracy >= 90) {
this.score += 50; // Excellence bonus
} else if (accuracy >= 70) {
this.score += 20; // Good performance bonus
}
this.updateScore();
this.showFeedback(
`🎉 Quiz completed! ${this.correctAnswers}/${this.totalQuestions} correct (${accuracy}%)`,
'success'
);
setTimeout(() => {
this.onGameEnd(this.score);
}, 3000);
}
showFeedback(message, type = 'info') {
const feedbackArea = document.getElementById('feedback-area');
feedbackArea.innerHTML = `${message}
`;
}
start() {
console.log('❓ Quiz Game: Starting');
this.showFeedback('Choose the correct translation for each word!', 'info');
}
restart() {
console.log('🔄 Quiz Game: Restarting');
this.reset();
this.start();
}
reset() {
this.currentQuestion = 0;
this.score = 0;
this.correctAnswers = 0;
this.hasAnswered = false;
this.currentQuestionData = null;
// Re-shuffle vocabulary
this.vocabulary = this.vocabulary.sort(() => Math.random() - 0.5);
this.generateQuestion();
this.updateScore();
}
destroy() {
this.container.innerHTML = '';
}
}
// Module registration
window.GameModules = window.GameModules || {};
window.GameModules.QuizGame = QuizGame;