From 44ce6636c06d4a157edc056959ae31e04e0a8fd8 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Mon, 19 Jan 2026 19:35:41 +0100 Subject: [PATCH] Refactor answer checking logic in VocabService to support multiple exercise types - Updated the _checkAnswer method to handle both multiple choice and gap fill exercises more effectively. - Enhanced the extraction of correct answers and alternatives based on exercise type, improving accuracy in answer validation. - Added JSON parsing for answer and question data to ensure compatibility with various input formats. - Improved fallback mechanisms for answer checking to accommodate different data structures. --- backend/services/vocabService.js | 77 +++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/backend/services/vocabService.js b/backend/services/vocabService.js index dd24dc5..2ca650e 100644 --- a/backend/services/vocabService.js +++ b/backend/services/vocabService.js @@ -1285,7 +1285,7 @@ export default class VocabService { } // Überprüfe Antwort (vereinfachte Logik - kann je nach Übungstyp erweitert werden) - const isCorrect = this._checkAnswer(exercise.answerData, userAnswer, exercise.exerciseTypeId); + const isCorrect = this._checkAnswer(exercise.answerData, exercise.questionData, userAnswer, exercise.exerciseTypeId); // Speichere Fortschritt const [progress, created] = await VocabGrammarExerciseProgress.findOrCreate({ @@ -1321,11 +1321,36 @@ export default class VocabService { const answerData = typeof exercise.answerData === 'string' ? JSON.parse(exercise.answerData) : exercise.answerData; + const questionData = typeof exercise.questionData === 'string' + ? JSON.parse(exercise.questionData) + : exercise.questionData; - const correctAnswer = Array.isArray(answerData.correct) - ? answerData.correct[0] - : answerData.correct; - const alternatives = answerData.alternatives || []; + let correctAnswer = null; + let alternatives = []; + + // Für Multiple Choice: Extrahiere die richtige Antwort aus dem Index + if (exercise.exerciseTypeId === 2 && answerData.correctAnswer !== undefined) { + const options = questionData?.options || []; + const correctIndex = answerData.correctAnswer; + if (options[correctIndex] !== undefined) { + correctAnswer = options[correctIndex]; + } + // Alternativen sind alle anderen Optionen + alternatives = options.filter((opt, idx) => idx !== correctIndex); + } + // Für Gap Fill: Extrahiere aus answers Array + else if (exercise.exerciseTypeId === 1 && answerData.answers) { + correctAnswer = Array.isArray(answerData.answers) + ? answerData.answers.join(', ') + : answerData.answers; + } + // Fallback: Versuche correct oder correctAnswer + else { + correctAnswer = Array.isArray(answerData.correct) + ? answerData.correct[0] + : (answerData.correct || answerData.correctAnswer); + alternatives = answerData.alternatives || []; + } return { correct: isCorrect, @@ -1336,28 +1361,50 @@ export default class VocabService { }; } - _checkAnswer(answerData, userAnswer, exerciseTypeId) { + _checkAnswer(answerData, questionData, userAnswer, exerciseTypeId) { // Vereinfachte Antwortprüfung - kann je nach Übungstyp erweitert werden - if (!answerData || !userAnswer) return false; + if (!answerData || userAnswer === undefined || userAnswer === null) return false; - // Für Multiple Choice: Prüfe ob userAnswer eine der richtigen Antworten ist + // Parse JSON strings + const parsedAnswerData = typeof answerData === 'string' ? JSON.parse(answerData) : answerData; + const parsedQuestionData = typeof questionData === 'string' ? JSON.parse(questionData) : questionData; + + // Für Multiple Choice: Prüfe ob userAnswer (Index) mit correctAnswer (Index) übereinstimmt if (exerciseTypeId === 2) { // multiple_choice - const correctAnswers = Array.isArray(answerData.correct) ? answerData.correct : [answerData.correct]; - return correctAnswers.includes(userAnswer); + const correctIndex = parsedAnswerData.correctAnswer !== undefined + ? parsedAnswerData.correctAnswer + : (parsedAnswerData.correct !== undefined ? parsedAnswerData.correct : null); + if (correctIndex === null) return false; + // userAnswer ist der Index (0, 1, 2, ...) + return Number(userAnswer) === Number(correctIndex); } // Für Lückentext: Normalisiere und vergleiche if (exerciseTypeId === 1) { // gap_fill const normalize = (str) => String(str || '').trim().toLowerCase(); - const correctAnswers = Array.isArray(answerData.correct) ? answerData.correct : [answerData.correct]; - const normalizedUserAnswer = normalize(userAnswer); - return correctAnswers.some(correct => normalize(correct) === normalizedUserAnswer); + const correctAnswers = parsedAnswerData.answers || parsedAnswerData.correct || []; + const correctAnswersArray = Array.isArray(correctAnswers) ? correctAnswers : [correctAnswers]; + + // userAnswer ist ein Array von Antworten + if (Array.isArray(userAnswer)) { + if (userAnswer.length !== correctAnswersArray.length) return false; + return userAnswer.every((ans, idx) => { + const correct = correctAnswersArray[idx]; + return normalize(ans) === normalize(correct); + }); + } else { + // Fallback: Einzelne Antwort + const normalizedUserAnswer = normalize(userAnswer); + return correctAnswersArray.some(correct => normalize(correct) === normalizedUserAnswer); + } } // Für andere Typen: einfacher String-Vergleich (kann später erweitert werden) const normalize = (str) => String(str || '').trim().toLowerCase(); - const correctAnswers = Array.isArray(answerData.correct) ? answerData.correct : [answerData.correct]; - return correctAnswers.some(correct => normalize(correct) === normalize(userAnswer)); + const correctAnswers = parsedAnswerData.correct || parsedAnswerData.correctAnswer || []; + const correctAnswersArray = Array.isArray(correctAnswers) ? correctAnswers : [correctAnswers]; + const normalizedUserAnswer = normalize(userAnswer); + return correctAnswersArray.some(correct => normalize(correct) === normalizedUserAnswer); } async getGrammarExerciseProgress(hashedUserId, lessonId) {