<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>音楽記号〜音符の音の長さ編〜</title> <link rel="stylesheet" href="phlox.css" /> <style> /* 新しい表示形式に合わせてCSSを調整 */ .quiz-container { max-width: 600px; margin: 2em auto; padding: 1.5em; border: 1px solid #ddd; border-radius: 8px; } .question-box { margin-bottom: 1.5em; } .choices-list { list-style-type: none; padding: 0; } .choices-list li { margin-bottom: 0.5em; } .choices-list button { width: 100%; padding: 0.8em; font-size: 1.1em; text-align: left; border: 1px solid #ccc; background-color: #f9f9f9; cursor: pointer; border-radius: 5px; transition: background-color 0.3s; } .choices-list button:hover { background-color: #eaeaea; } .explanation-box { margin-top: 2em; padding: 1em; border-left: 5px solid #007bff; background-color: #7a9ac4; color: #f0f0f0; border-radius: 4px; display: none; } .explanation-box.correct { border-color: #28a745; background-color: #69a369; } .explanation-box.incorrect { border-color: #dc3545; background-color: #ce7575; } .navigation-buttons { text-align: center; margin-top: 1.5em; } </style> </head> <body> <h1>ここは音の長さについてのクイズ</h1> <h1><span class="juyo">4分音符を1拍</span>と数えるとき</h1> <div id="timer" style="font-size: 1.5em; margin-bottom: 1em; text-align: center;">タイム: 00:00</div> <div class="quiz-container"> <div id="quiz-question-box"> </div> <div id="explanation-container" class="explanation-box"> </div> <div class="navigation-buttons"> <button id="next-button" style="display: none;">次の問題へ</button> <button id="show-results-button" style="display: none;">結果を見る</button> </div> </div> <script> // クイズデータを保持する配列 let quizData = []; // 現在表示している問題のインデックス let currentQuestionIndex = 0; // ユーザーの回答履歴を保持する配列 let userAnswers = []; // クイズ開始時刻を記録する変数 let startTime; // タイマーのsetInterval IDを保持する変数 let timerInterval; // タイマーを1秒ごとに更新する関数 function updateTimer() { const currentTime = new Date().getTime(); // 現在時刻(ミリ秒)を取得 const elapsedTime = Math.floor((currentTime - startTime) / 1000); // 経過時間を秒で計算 const minutes = String(Math.floor(elapsedTime / 60)).padStart(2, '0'); // 分を計算し、2桁にフォーマット const seconds = String(elapsedTime % 60).padStart(2, '0'); // 秒を計算し、2桁にフォーマット document.getElementById('timer').textContent = `タイム: ${minutes}:${seconds}`; } // 配列の要素をシャッフルする関数 function shuffle(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; } // CSVファイルを読み込み、クイズデータを準備する非同期関数 async function loadCSV() { // CSVファイルを読み込む(キャッシュを防ぐためにタイムスタンプを追加) const res = await fetch("phlox-quiz2.csv?ts=" + Date.now()); const text = await res.text(); // テキストを行ごとに分割し、空行をフィルタリング const lines = text.trim().split("\n").filter(line => line.trim() !== ""); // 各行をパースしてクイズデータオブジェクトを作成 for (let i = 1; i < lines.length; i++) { // 正規表現を使ってカンマと二重引用符で囲まれた文字列を正しく分割 const row = lines[i].match(/(".*?"|[^",]+)(?=\s*,|\s*$)/g)?.map(s => s.replace(/^"|"$/g, "")); if (!row || row.length < 5) continue; const [question, c1 = "", c2 = "", c3 = "", c4 = "", correctNumStr = "", explanation = ""] = row; const rawChoices = [c1, c2, c3, c4]; // 空の選択肢をフィルタリング const choices = rawChoices.filter(c => c.trim() !== ""); // 正解のインデックスを文字列から数値に変換 const correctIndex = parseInt(correctNumStr, 10) - 1; const correctAnswer = rawChoices[correctIndex]; quizData.push({ question: question, choices: choices, correct: correctAnswer, explanation: explanation }); } // クイズデータの順番をシャッフル quizData = shuffle(quizData); // 最初の問題を画面に表示 renderQuestion(); // クイズ開始時刻を記録し、タイマーを開始 startTime = new Date().getTime(); timerInterval = setInterval(updateTimer, 1000); } // 現在の問題を画面に表示する関数 function renderQuestion() { const quizQuestionBox = document.getElementById("quiz-question-box"); const explanationContainer = document.getElementById("explanation-container"); const nextButton = document.getElementById("next-button"); const showResultsButton = document.getElementById("show-results-button"); // 前回の表示内容をリセット explanationContainer.style.display = 'none'; nextButton.style.display = 'none'; showResultsButton.style.display = 'none'; // 全ての問題が終了したらクイズを終了 if (currentQuestionIndex >= quizData.length) { endQuiz(); return; } const q = quizData[currentQuestionIndex]; // 選択肢をシャッフル const shuffledChoices = shuffle([...q.choices]); // HTML文字列を動的に生成 let html = ` <div class="question-box"> <h2>Q${currentQuestionIndex + 1}. ${q.question}</h2> <ul class="choices-list"> `; shuffledChoices.forEach(choice => { html += `<li><button class="choice-button" data-choice="${choice}">${choice}</button></li>`; }); html += `</ul></div>`; quizQuestionBox.innerHTML = html; // 選択肢ボタンにクリックイベントリスナーを追加 document.querySelectorAll(".choice-button").forEach(button => { button.addEventListener("click", handleAnswer); }); } // ユーザーが回答を選択したときの処理 function handleAnswer(event) { const selectedChoice = event.target.dataset.choice; const currentQuestion = quizData[currentQuestionIndex]; const isCorrect = selectedChoice === currentQuestion.correct; // ユーザーの回答結果を保存 userAnswers.push({ userAnswer: selectedChoice, correctAnswer: currentQuestion.correct, isCorrect: isCorrect }); // 全ての選択肢ボタンを無効化 document.querySelectorAll(".choice-button").forEach(button => { button.disabled = true; // 正解と不正解でボタンの背景色を変更 if (button.dataset.choice === currentQuestion.correct) { button.style.backgroundColor = '#d4edda'; // 正解は薄い緑 } else if (button.dataset.choice === selectedChoice) { button.style.backgroundColor = '#f8d7da'; // 不正解は薄い赤 } }); // 解説を表示 const explanationContainer = document.getElementById("explanation-container"); explanationContainer.innerHTML = ` <p><strong>あなたの答え:</strong> ${selectedChoice}</p> <p><strong>正解:</strong> ${currentQuestion.correct}</p> <p>${currentQuestion.explanation}</p> `; explanationContainer.style.display = 'block'; // 正解・不正解に応じて解説ボックスの色を変更 explanationContainer.className = isCorrect ? 'explanation-box correct' : 'explanation-box incorrect'; // 次へボタンまたは結果を見るボタンを表示 const nextButton = document.getElementById("next-button"); const showResultsButton = document.getElementById("show-results-button"); if (currentQuestionIndex < quizData.length - 1) { // まだ問題が残っている場合 nextButton.style.display = 'inline-block'; nextButton.onclick = () => { currentQuestionIndex++; // 次の問題へ進む renderQuestion(); // 次の問題を表示 }; } else { // 最後の問題の場合 showResultsButton.style.display = 'inline-block'; showResultsButton.onclick = endQuiz; // 結果ページへ } } // クイズを終了し、結果ページに遷移する関数 function endQuiz() { clearInterval(timerInterval); // タイマーを停止 const endTime = new Date().getTime(); const totalTime = Math.floor((endTime - startTime) / 1000); // ユーザーの回答とクイズデータをまとめてlocalStorageに保存 localStorage.setItem("quizResults", JSON.stringify({ quizData, answers: userAnswers.map(a => a.userAnswer), totalTime })); // 結果ページへ遷移 location.href = "kaisetu-2.html"; } // ページが読み込まれたらクイズを開始 loadCSV(); </script> </body> </html>