`;
}
_generateQuestions() {
this._questions = [];
const questionCount = Math.min(this._config.questionCount, this._vocabulary.length);
const selectedVocab = this._shuffleArray([...this._vocabulary]).slice(0, questionCount);
selectedVocab.forEach((vocab, index) => {
this._questions.push({
id: index,
vocabulary: vocab,
options: this._generateOptions(vocab),
correctAnswer: null, // Will be set based on quiz direction
userAnswer: null,
timeSpent: 0,
answered: false
});
});
}
_generateOptions(correctVocab) {
const options = [];
const otherVocab = this._vocabulary.filter(v => v !== correctVocab);
const shuffledOthers = this._shuffleArray(otherVocab);
// Add correct answer
options.push(correctVocab);
// Add incorrect options
for (let i = 0; i < this._config.optionsCount - 1 && i < shuffledOthers.length; i++) {
options.push(shuffledOthers[i]);
}
return this._shuffleArray(options);
}
_showQuizDirectionChoice() {
const content = document.getElementById('quiz-content');
content.innerHTML = `
Choose Quiz Direction
How would you like to be tested?
`;
}
_startQuiz(direction) {
this._quizDirection = direction;
this._currentQuestion = 0;
this._score = 0;
// Set correct answers based on direction
this._questions.forEach(question => {
if (direction === 'en-to-translation') {
question.correctAnswer = question.vocabulary.translation;
} else {
question.correctAnswer = question.vocabulary.english;
}
});
this._showQuestion();
}
_showQuestion() {
if (this._currentQuestion >= this._questions.length) {
this._showResults();
return;
}
const question = this._questions[this._currentQuestion];
const content = document.getElementById('quiz-content');
// Determine question text based on direction
const questionText = this._quizDirection === 'en-to-translation'
? question.vocabulary.english
: question.vocabulary.translation;
content.innerHTML = `
Question ${this._currentQuestion + 1} of ${this._questions.length}
${this._config.timeLimit}
${questionText}
${this._generateOptionHTML(question)}
`;
this._startQuestionTimer();
this._questionStartTime = Date.now();
}
_generateOptionHTML(question) {
return question.options.map((vocab, index) => {
const optionText = this._quizDirection === 'en-to-translation'
? vocab.translation
: vocab.english;
// Store the Chinese word and pronunciation for TTS
const chineseWord = vocab.english; // In our data structure, english is the Chinese word
const pronunciation = vocab.pronunciation || '';
return `
${optionText}
${pronunciation ? `
[${pronunciation}]
` : ''}
`;
}).join('');
}
_startQuestionTimer() {
this._timeRemaining = this._config.timeLimit;
this._timer = setInterval(() => {
this._timeRemaining--;
this._updateTimer();
if (this._timeRemaining <= 0) {
this._handleTimeout();
}
}, 1000);
}
_updateTimer() {
const timerValue = document.getElementById('timer-value');
const timerCircle = document.getElementById('timer-circle');
if (timerValue) {
timerValue.textContent = this._timeRemaining;
}
if (timerCircle) {
timerCircle.className = 'timer-circle';
if (this._timeRemaining <= 5) {
timerCircle.classList.add('warning');
} else if (this._timeRemaining > 15) {
timerCircle.classList.add('safe');
}
}
}
_setupEventListeners() {
// Direction choice listeners
this._config.container.addEventListener('click', (event) => {
if (event.target.matches('.direction-btn')) {
const direction = event.target.dataset.direction;
this._startQuiz(direction);
}
if (event.target.matches('.quiz-option')) {
this._handleAnswerClick(event.target);
}
if (event.target.matches('.next-question-btn')) {
this._nextQuestion();
}
if (event.target.matches('.restart-btn')) {
this._restartQuiz();
}
});
// Exit button
const exitButton = this._config.container.querySelector('#exit-quiz');
if (exitButton) {
exitButton.addEventListener('click', () => {
this._eventBus.emit('game:exit-request', { instanceId: this.name }, this.name);
});
}
}
_handleAnswerClick(optionElement) {
if (this._isAnswering || optionElement.classList.contains('disabled')) {
return;
}
this._isAnswering = true;
const question = this._questions[this._currentQuestion];
const selectedAnswer = optionElement.dataset.value;
const isCorrect = selectedAnswer === question.correctAnswer;
// Clear timer
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
// Record answer
question.userAnswer = selectedAnswer;
question.answered = true;
question.timeSpent = this._questionStartTime ? Date.now() - this._questionStartTime : 0;
// Update score
if (isCorrect) {
const timeBonus = Math.max(0, this._timeRemaining * 2);
this._score += 100 + timeBonus;
}
// Play TTS and show pronunciation
if (isCorrect) {
// For correct answer, play the clicked option
const word = optionElement.dataset.word;
const pronunciation = optionElement.dataset.pronunciation;
if (word) {
this._playAudio(word);
if (pronunciation) {
const pronunciationElement = optionElement.querySelector('.option-pronunciation');
if (pronunciationElement) {
pronunciationElement.style.display = 'block';
this._highlightPronunciation(optionElement);
}
}
}
} else {
// For incorrect answer, find and play the correct option's TTS
const correctOption = this._findCorrectOption(question.correctAnswer);
if (correctOption) {
const word = correctOption.dataset.word;
const pronunciation = correctOption.dataset.pronunciation;
if (word) {
this._playAudio(word);
if (pronunciation) {
const pronunciationElement = correctOption.querySelector('.option-pronunciation');
if (pronunciationElement) {
pronunciationElement.style.display = 'block';
this._highlightPronunciation(correctOption);
}
}
}
}
}
// Show feedback
this._showAnswerFeedback(isCorrect, question);
this._updateStats();
// Emit answer event
this._eventBus.emit('quiz:answer', {
gameId: 'quiz-game',
instanceId: this.name,
questionNumber: this._currentQuestion + 1,
isCorrect,
score: this._score,
timeSpent: question.timeSpent
}, this.name);
}
_findCorrectOption(correctAnswer) {
const optionsContainer = document.getElementById('quiz-options');
if (!optionsContainer) return null;
const options = optionsContainer.querySelectorAll('.quiz-option');
for (const option of options) {
if (option.dataset.value === correctAnswer) {
return option;
}
}
return null;
}
_handleTimeout() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
const question = this._questions[this._currentQuestion];
question.answered = true;
question.timeSpent = this._config.timeLimit * 1000;
this._showAnswerFeedback(false, question, true);
this._updateStats();
}
_showAnswerFeedback(isCorrect, question, timeout = false) {
const optionsContainer = document.getElementById('quiz-options');
const feedbackContainer = document.getElementById('quiz-feedback');
// Disable all options
optionsContainer.querySelectorAll('.quiz-option').forEach(option => {
option.classList.add('disabled');
const optionValue = option.dataset.value;
if (optionValue === question.correctAnswer) {
option.classList.add('correct');
} else if (optionValue === question.userAnswer) {
option.classList.add('incorrect');
}
});
// Show feedback message
let feedbackMessage;
if (timeout) {
feedbackMessage = `⏰ Time's up! The correct answer was: ${question.correctAnswer}`;
} else if (isCorrect) {
feedbackMessage = `🎉 Correct! +${100 + Math.max(0, this._timeRemaining * 2)} points`;
} else {
feedbackMessage = `❌ Incorrect. The correct answer was: ${question.correctAnswer}`;
}
feedbackContainer.innerHTML = `