document.addEventListener('DOMContentLoaded', function () { // Элементы DOM const startScreen = document.getElementById('start-screen'); const quizScreen = document.getElementById('quiz-screen'); const resultScreen = document.getElementById('result-screen'); const reviewScreen = document.getElementById('review-screen'); const startBtn = document.getElementById('start-btn'); const prevBtn = document.getElementById('prev-btn'); const checkBtn = document.getElementById('check-btn'); const nextBtn = document.getElementById('next-btn'); const submitBtn = document.getElementById('submit-btn'); const restartBtn = document.getElementById('restart-btn'); const reviewBtn = document.getElementById('review-btn'); const backToResultsBtn = document.getElementById('back-to-results-btn'); const questionElement = document.getElementById('question'); const optionsContainer = document.getElementById('options-container'); const selectionInfo = document.getElementById('selection-info'); const selectedCountElement = document.getElementById('selected-count'); const totalOptionsElement = document.getElementById('total-options'); const feedbackContainer = document.getElementById('feedback-container'); const correctFeedback = document.getElementById('correct-feedback'); const partialFeedback = document.getElementById('partially-feedback'); const incorrectFeedback = document.getElementById('incorrect-feedback'); const partialCorrectCount = document.getElementById('partial-correct-count'); const totalCorrectCount = document.getElementById('total-correct-count'); const correctAnswersText = document.getElementById('correct-answers-text'); const progressBar = document.querySelector('.progress-bar'); const progressText = document.getElementById('progress-text'); const scoreElement = document.getElementById('score'); const percentageElement = document.getElementById('percentage'); const correctCountElement = document.getElementById('correct-count'); const partialCountElement = document.getElementById('partial-count'); const incorrectCountElement = document.getElementById('incorrect-count'); const reviewContainer = document.getElementById('review-container'); // Переменные состояния let questions = []; let shuffledQuestions = []; let currentQuestionIndex = 0; let userAnswers = []; // Массив массивов выбранных индексов let questionStatus = []; // Статус ответа на каждый вопрос: 'unanswered', 'correct', 'partial', 'incorrect' let score = 0; let letters = ['а', 'б', 'в', 'г', 'д', 'е']; // Загрузка вопросов из JSON async function loadQuestions() { try { const response = await fetch('questions.json'); if (!response.ok) { throw new Error('Не удалось загрузить вопросы'); } questions = await response.json(); console.log('Вопросы загружены:', questions.length); } catch (error) { console.error('Ошибка загрузки вопросов:', error); createDemoQuestions(); } } // Создание демо-вопросов, если файл не найден function createDemoQuestions() { questions = [ { "text": "Составляющие мультимедиа могут быть разбиты на основные группы?", "options": [ { "text": "Текстовая, визуальная и звуковая информация.", "correct": false }, { "text": "Текстовая, визуальная, звуковая информация и данные.", "correct": true }, { "text": "Текстовая, визуальная, звуковая информация, данные и графическая информация.", "correct": false }, { "text": "Только текстовая и визуальная информация.", "correct": false } ] }, { "text": "С точки зрения передачи мультимедиа могут быть классифицированы на?", "options": [ { "text": "Передаваемые в реальном времени.", "correct": true }, { "text": "Передаваемые в on-line.", "correct": false }, { "text": "Передаваемые в не реальном времени.", "correct": true }, { "text": "Только передаваемые по запросу.", "correct": false } ] } ]; console.log('Созданы демо-вопросы с множественным выбором'); } // Инициализация теста function initializeQuiz() { // Перемешиваем вопросы shuffledQuestions = [...questions]; shuffleArray(shuffledQuestions); // Перемешиваем варианты ответов в каждом вопросе shuffledQuestions.forEach(question => { shuffleArray(question.options); // Находим индексы правильных ответов после перемешивания question.correctOptionIndices = []; question.options.forEach((option, index) => { if (option.correct) { question.correctOptionIndices.push(index); } }); // Сохраняем текст правильных ответов для отображения question.correctAnswersText = question.correctOptionIndices .map(idx => `${letters[idx]}) ${question.options[idx].text}`) .join('; '); }); // Инициализируем массивы userAnswers = new Array(shuffledQuestions.length).fill(null).map(() => []); questionStatus = new Array(shuffledQuestions.length).fill('unanswered'); // Сбрасываем индекс текущего вопроса и счет currentQuestionIndex = 0; score = 0; // Обновляем UI updateProgress(); showQuestion(); } // Перемешивание массива (алгоритм Фишера-Йетса) function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } // Показать вопрос function showQuestion() { const question = shuffledQuestions[currentQuestionIndex]; questionElement.textContent = `${currentQuestionIndex + 1}. ${question.text}`; // Обновляем информацию о выборе totalOptionsElement.textContent = question.options.length; updateSelectionInfo(); // Скрываем блок обратной связи, если вопрос еще не проверен if (questionStatus[currentQuestionIndex] === 'unanswered') { feedbackContainer.classList.add('hidden'); } else { showFeedback(); } // Очищаем контейнер с вариантами optionsContainer.innerHTML = ''; // Создаем варианты ответов question.options.forEach((option, index) => { const optionElement = document.createElement('div'); optionElement.className = 'option'; // Проверяем, выбран ли этот вариант const isSelected = userAnswers[currentQuestionIndex].includes(index); const isChecked = questionStatus[currentQuestionIndex] !== 'unanswered'; if (isSelected) { optionElement.classList.add('selected'); } // Если вопрос проверен, показываем правильность ответов if (isChecked) { optionElement.classList.add('checked'); const isCorrectOption = question.correctOptionIndices.includes(index); if (isSelected && isCorrectOption) { optionElement.classList.add('correct'); } else if (isSelected && !isCorrectOption) { optionElement.classList.add('incorrect'); } else if (!isSelected && isCorrectOption) { optionElement.classList.add('correct'); } } optionElement.innerHTML = `
${letters[index]}) ${option.text}
`; // Если вопрос еще не проверен, добавляем обработчик клика if (!isChecked) { optionElement.addEventListener('click', () => toggleOption(index)); } optionsContainer.appendChild(optionElement); }); // Обновляем состояние кнопок навигации updateNavigationButtons(); } // Переключить выбор варианта function toggleOption(optionIndex) { const currentAnswers = userAnswers[currentQuestionIndex]; const index = currentAnswers.indexOf(optionIndex); if (index === -1) { // Добавляем вариант currentAnswers.push(optionIndex); } else { // Удаляем вариант currentAnswers.splice(index, 1); } // Обновляем отображение updateSelectionInfo(); showQuestion(); } // Обновить информацию о выбранных вариантах function updateSelectionInfo() { const selectedCount = userAnswers[currentQuestionIndex].length; selectedCountElement.textContent = selectedCount; // Подсвечиваем информацию в зависимости от количества выбранных ответов if (selectedCount === 0) { selectionInfo.style.borderColor = '#e0e0e0'; selectionInfo.style.backgroundColor = '#f0f4ff'; } else { selectionInfo.style.borderColor = '#4a00e0'; selectionInfo.style.backgroundColor = '#e6f7ff'; } } // Обновить кнопки навигации function updateNavigationButtons() { const isAnswered = questionStatus[currentQuestionIndex] !== 'unanswered'; const hasSelection = userAnswers[currentQuestionIndex].length > 0; prevBtn.disabled = currentQuestionIndex === 0; if (isAnswered) { checkBtn.classList.add('hidden'); nextBtn.classList.remove('hidden'); } else { checkBtn.classList.remove('hidden'); nextBtn.classList.add('hidden'); checkBtn.disabled = !hasSelection; } // Показываем кнопку завершения на последнем проверенном вопросе const allQuestionsAnswered = questionStatus.every(status => status !== 'unanswered'); const isLastQuestion = currentQuestionIndex === shuffledQuestions.length - 1; if (isLastQuestion && isAnswered) { nextBtn.classList.add('hidden'); submitBtn.classList.remove('hidden'); } else { submitBtn.classList.add('hidden'); } } // Проверить ответ и показать результат function checkAnswer() { const question = shuffledQuestions[currentQuestionIndex]; const userSelected = userAnswers[currentQuestionIndex]; const correctIndices = question.correctOptionIndices; // Находим количество правильных выбранных ответов const correctSelected = userSelected.filter(idx => correctIndices.includes(idx)).length; const incorrectSelected = userSelected.length - correctSelected; const missedCorrect = correctIndices.length - correctSelected; // Определяем статус ответа let status; let feedbackType; if (incorrectSelected === 0 && missedCorrect === 0) { // Все правильные выбраны, ничего лишнего status = 'correct'; feedbackType = 'correct'; score += 1; } else if (correctSelected > 0 && (incorrectSelected > 0 || missedCorrect > 0)) { // Частично правильно status = 'partial'; feedbackType = 'partial'; score += 0.5; // Половина балла за частично правильный ответ } else { // Полностью неправильно status = 'incorrect'; feedbackType = 'incorrect'; } // Сохраняем статус вопроса questionStatus[currentQuestionIndex] = status; // Показываем обратную связь showFeedback(correctSelected, correctIndices.length); // Обновляем навигацию updateNavigationButtons(); // Обновляем отображение вариантов showQuestion(); } // Показать обратную связь function showFeedback(correctSelected = 0, totalCorrect = 0) { const question = shuffledQuestions[currentQuestionIndex]; const status = questionStatus[currentQuestionIndex]; // Скрываем все виды обратной связи correctFeedback.classList.add('hidden'); partialFeedback.classList.add('hidden'); incorrectFeedback.classList.add('hidden'); // Показываем соответствующий вид обратной связи switch (status) { case 'correct': correctFeedback.classList.remove('hidden'); break; case 'partial': partialFeedback.classList.remove('hidden'); partialCorrectCount.textContent = correctSelected; totalCorrectCount.textContent = totalCorrect; break; case 'incorrect': incorrectFeedback.classList.remove('hidden'); correctAnswersText.textContent = question.correctAnswersText; break; } feedbackContainer.classList.remove('hidden'); } // Обновление прогресса function updateProgress() { const progress = ((currentQuestionIndex + 1) / shuffledQuestions.length) * 100; progressBar.style.setProperty('--width', `${progress}%`); progressText.textContent = `Вопрос ${currentQuestionIndex + 1} из ${shuffledQuestions.length}`; } // Переход к следующему вопросу function nextQuestion() { if (currentQuestionIndex < shuffledQuestions.length - 1) { currentQuestionIndex++; updateProgress(); showQuestion(); } } // Переход к предыдущему вопросу function prevQuestion() { if (currentQuestionIndex > 0) { currentQuestionIndex--; updateProgress(); showQuestion(); } } // Завершение теста и подсчет результатов function finishQuiz() { // Подсчет детальной статистики let correctCount = 0; let partialCount = 0; let incorrectCount = 0; questionStatus.forEach(status => { switch (status) { case 'correct': correctCount++; break; case 'partial': partialCount++; break; case 'incorrect': incorrectCount++; break; } }); // Обновление экрана результатов scoreElement.textContent = Math.round(score * 10) / 10; // Округляем до одного знака после запятой const percentage = Math.round((score / shuffledQuestions.length) * 100); percentageElement.textContent = `${percentage}%`; correctCountElement.textContent = correctCount; partialCountElement.textContent = partialCount; incorrectCountElement.textContent = incorrectCount; // Обновление кругового индикатора const circle = document.querySelector('.circle'); circle.style.background = `conic-gradient(#4a00e0 ${percentage}%, #e0e0e0 ${percentage}%)`; // Переключение экранов quizScreen.classList.add('hidden'); resultScreen.classList.remove('hidden'); } // Показать обзор ответов function showReview() { reviewContainer.innerHTML = ''; shuffledQuestions.forEach((question, index) => { const reviewItem = document.createElement('div'); reviewItem.className = 'review-item'; const status = questionStatus[index]; const userSelected = userAnswers[index]; const correctIndices = question.correctOptionIndices; // Определяем статус для отображения let statusText, statusClass; switch (status) { case 'correct': statusText = 'Правильно'; statusClass = 'status-correct'; break; case 'partial': statusText = 'Частично правильно'; statusClass = 'status-partial'; break; case 'incorrect': statusText = 'Неправильно'; statusClass = 'status-incorrect'; break; default: statusText = 'Не отвечено'; statusClass = 'status-incorrect'; } let optionsHTML = ''; question.options.forEach((option, optionIndex) => { let optionClass = ''; const isCorrect = correctIndices.includes(optionIndex); const isSelected = userSelected.includes(optionIndex); if (isCorrect && isSelected) { optionClass = 'user-correct'; } else if (isCorrect && !isSelected) { optionClass = 'correct-answer'; } else if (!isCorrect && isSelected) { optionClass = 'user-incorrect'; } else if (status === 'partial' && isSelected && !isCorrect) { optionClass = 'user-partial'; } optionsHTML += `
${letters[optionIndex]}) ${option.text}
`; }); reviewItem.innerHTML = `
${index + 1}. ${question.text} ${statusText}
${optionsHTML}
Ваши ответы: ${userSelected.length > 0 ? userSelected.map(idx => letters[idx]).join(', ') : 'нет ответа'}
`; reviewContainer.appendChild(reviewItem); }); resultScreen.classList.add('hidden'); reviewScreen.classList.remove('hidden'); } // Начало теста function startQuiz() { startScreen.classList.add('hidden'); quizScreen.classList.remove('hidden'); initializeQuiz(); } // События startBtn.addEventListener('click', startQuiz); prevBtn.addEventListener('click', prevQuestion); checkBtn.addEventListener('click', checkAnswer); nextBtn.addEventListener('click', nextQuestion); submitBtn.addEventListener('click', finishQuiz); restartBtn.addEventListener('click', () => { resultScreen.classList.add('hidden'); startScreen.classList.remove('hidden'); }); reviewBtn.addEventListener('click', showReview); backToResultsBtn.addEventListener('click', () => { reviewScreen.classList.add('hidden'); resultScreen.classList.remove('hidden'); }); // Загружаем вопросы при загрузке страницы loadQuestions(); });