プログラミング初心者のための「単語帳風クイズラーニングアプリ」開発入門~第2部 学習クイズ実行編~

今回の「学習クイズ実行編」では、「クイズを実行」するプログラムの内容についてお話をしていきたいと思います。

まだ、第1部をご覧になっていない方は、

→「第1部 ラーニングクイズアプリ~学習データ管理~」

を先にご覧ください。

クイズを実行する機能は、

  • 登録された順番に全てのクイズを実行
  • ランダムに「指定されたクイズ数」のクイズを実行

という2つの実行方法があります。

「startLearningQuiz」関数は、次のようになります。

/**
 * クイズをスタート
 */
function startLearningQuiz(){
	resetSelectAnsBtnOpacity();     //「選択肢ボタン」の透明度を初期化
	currentQiuzCount = 1;           //現在のクイズ番号を「1」に設定

	//ランダムクイズフラグの設定
	getElmId("quiz_exec_random").checked ? randomQuiz = true : randomQuiz = false;

	randQuizNums = []; //「ランダムクイズの配列要素番号」用配列を初期化

	// ランダムクイズの「クイズの配列要素番号」を生成
	randomQuiz ? createRandomQuizNums() : randomMaxCount = 0;

	// 出題する「クイズの配列要素番号」を生成
	createIndexNum();

	getElmId("quiz_count").innerHTML = currentQiuzCount;                     //「クイズ数」を設定
	getElmId("quiz").innerHTML = g_learning_data[indexNum]["contents"];      //「クイズ内容」を設定
	getElmId("select_1").innerHTML = g_learning_data[indexNum]["select_1"];  //「選択肢1」を設定
	getElmId("select_2").innerHTML = g_learning_data[indexNum]["select_2"];  //「選択肢2」を設定
	getElmId("select_3").innerHTML = g_learning_data[indexNum]["select_3"];  //「選択肢3」を設定
	getElmId("select_4").innerHTML = g_learning_data[indexNum]["select_4"];  //「選択肢4」を設定
	getElmId("next").style.display = "none";                                 //「次へ」ボタンを非表示
	getElmId("learning_quiz").style.display = "block";                       //「クイズ」を表示
	getElmId("setting").style.display = "none";                              //「クイズスタート前設定画面」を非表示  
	dispQuizCount();                                                         //「クイズ番号」と「残りクイズ数」を設定
	hideAnswer();                                                            //「クイズ解答」クリック時の処理                
	getElmId("results").innerHTML = "";                                      //「結果」を「空」に設定
}

さまざまな処理が実行されていますが、最後に「プログラムの全容」を公開しますので、現在のところは「処理の流れ」を掴んでおいてください。

「clickAnswer」関数は、次のようになります。

/**
 * クイズの「解答」クリック時の処理
 */
function clickAnswer(e){
	e.target.style.opacity = 0.5;                        //ボタンの透明度を設定
	result = [];                                         //クイズの正誤結果格納用(クイズ内容と結果)
	result.push(g_learning_data[indexNum]["contents"]);  //クイズ内容を配列に設定
	correctAnsObj[parseInt(g_learning_data[indexNum]["answer"]) -1].style.display = "block";  //正解の選択肢に「〇」を表示
	
	// クイズの解答が合っている場合
	if(e.target.dataset.id ===  g_learning_data[indexNum]["answer"]){
		correctCount++; // 「正解カウント」を「+1カウントアップ」
		// 「クイズデータ」の正解数を「+1カウントアップ」
		g_learning_data[indexNum]["success_count"] = parseInt(g_learning_data[indexNum]["success_count"])+1;
		result.push("〇");  //「クイズの正誤結果格納用」配列に「〇」を追加
	} else { // クイズの解答が間違っている場合
		mistakeAnsObj[e.target.dataset.id-1].style.display = "block";  //「誤り」の選択肢に「×」を表示
		result.push("×");  //「クイズの正誤結果格納用」配列に「×」を追加
	}

	results.push(result); //「結果データ群配列」に結果データを追加
	// 「クイズ挑戦回数」を「+1カウントアップ」
	g_learning_data[indexNum]["challenge_count"] = parseInt(g_learning_data[indexNum]["challenge_count"])+1;
	saveLearningData();           //クイズデータをセーブ
	dispNextBtn();                //「次へ」ボタンを表示
	if (isLast()){dispResults()}; //「クイズ実行結果」を表示
}

「選択肢」ボタンをクリックすると、「選択項目」のボタンの透明度を「0.5」に設定し、結果をボタンの右横に表示しています。

次のクイズが存在する場合は「次へ」ボタンをクリックすると、「toNext」関数が実行され、次のクイズを実行することができます。

/**
 * 「次へ」ボタンクリック時の処理
 */
function toNext(){
	resetSelectAnsBtnOpacity();  //「選択肢ボタン」の透明度をリセット
	hideAnswer();                //「〇」「×」画像を非表示            
	currentQiuzCount++;          //「クイズ番号」を「+1カウントアップ」

	// 出題する「クイズの配列要素番号」を生成
	createIndexNum();  // 出題する「クイズの配列要素番号」を生成
	getElmId("quiz_count").innerHTML = currentQiuzCount;                       //「クイズ数」を設定
	getElmId("quiz").innerHTML = g_learning_data[indexNum]["contents"];        //「クイズ内容」を設定
	getElmId("select_1").innerHTML = g_learning_data[indexNum]["select_1"];    //「選択肢1」を設定
	getElmId("select_2").innerHTML = g_learning_data[indexNum]["select_2"];    //「選択肢2」を設定
	getElmId("select_3").innerHTML = g_learning_data[indexNum]["select_3"];    //「選択肢3」を設定
	getElmId("select_4").innerHTML = g_learning_data[indexNum]["select_4"];    //「選択肢4」を設定
	getElmId("next").style.display = "none";                                   //「次へ」ボタンを非表示
	getElmId("learning_quiz").style.display = "block";                         //「クイズ」を表示
	dispQuizCount();  //「クイズ番号」と「残りクイズ数」を設定
}

「次のクイズ」をセットして、画面に表示する処理が実行されています。

全てのクイズを完了すると、「クイズ実行結果」が表示されます。

「クイズの実行結果」を表示する関数は「dispResults」関数ですが、次のようになっています。

/**
 * 「クイズ実行結果」を表示
 */
function dispResults(){
	getElmId("results").style.display = "block";
	let count = 1;
	let html = "";
	html += "<hr>";
	html += "<table>";
	html += "<tr>";
	html += "<th>No</th><th>問題</th><th>結果</th>";
	html += "</tr>";
	results.forEach(element => {
		html += "<tr>";
		html += "<td>" + count + "</td><td>" + element[0] + "</td><td>" + element[1] + "</td>"; 
		html += "</tr>";
		count++;
	});
	html += "</table>";
	getElmId("results").innerHTML = html;
	results = [];
	result = [];
}

「学習クイズ実行ページ(learning.html)」のプログラムコード

<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title>単語帳風クイズラーニングアプリ-学習-</title>
		<link rel="stylesheet" href="common.css">
		<link rel="stylesheet" href="learning.css">
		<script src="common.js"></script>
		<script>
			let g_learning_data = null; //学習データ格納用
			let currentQiuzCount = 1;  //現在のクイズ番号
			let indexNum = 0;           //配列要素番号
			let correctAnsObj = null;   //「〇」画像オブジェクト格納用
			let mistakeAnsObj = null;  //「×」画像オブジェクト格納用
			let correctCount = 0;       //問題正解数カウント
			let randomQuiz = false;     //ランダム出題ステータス
			let randomMaxCount = 0;     //ランダム出題時の出題数
			let results = [];           //結果データ群
			let result = [];            //結果データ
			let randQuizNums = [];      //ランダム出題時の配列要素番号格納用

			/**
			  * クイズをスタート
			  */
			function startLearningQuiz(){
				resetSelectAnsBtnOpacity();     //「選択肢ボタン」の透明度を初期化
				currentQiuzCount = 1;           //現在のクイズ番号を「1」に設定

				//ランダムクイズフラグの設定
				getElmId("quiz_exec_random").checked ? randomQuiz = true : randomQuiz = false;

				randQuizNums = []; //「ランダムクイズの配列要素番号」用配列を初期化

				// ランダムクイズの「クイズの配列要素番号」を生成
				randomQuiz ? createRandomQuizNums() : randomMaxCount = 0;

				// 出題する「クイズの配列要素番号」を生成
				createIndexNum();

				getElmId("quiz_count").innerHTML = currentQiuzCount;                     //「クイズ数」を設定
				getElmId("quiz").innerHTML = g_learning_data[indexNum]["contents"];      //「クイズ内容」を設定
				getElmId("select_1").innerHTML = g_learning_data[indexNum]["select_1"];  //「選択肢1」を設定
				getElmId("select_2").innerHTML = g_learning_data[indexNum]["select_2"];  //「選択肢2」を設定
				getElmId("select_3").innerHTML = g_learning_data[indexNum]["select_3"];  //「選択肢3」を設定
				getElmId("select_4").innerHTML = g_learning_data[indexNum]["select_4"];  //「選択肢4」を設定
				getElmId("next").style.display = "none";                                 //「次へ」ボタンを非表示
				getElmId("learning_quiz").style.display = "block";                       //「クイズ」を表示
				getElmId("setting").style.display = "none";                              //「クイズスタート前設定画面」を非表示  
				dispQuizCount();                                                         //「クイズ番号」と「残りクイズ数」を設定
				hideAnswer();                                                            //「クイズ解答」クリック時の処理                
				getElmId("results").innerHTML = "";                                      //「結果」を「空」に設定
			}

			/**
			  * 出題する「クイズの配列要素番号」を生成
			  */
			function createIndexNum(){            
				indexNum = currentQiuzCount-1;  //クイズの配列要素番号を取得
				if( randomQuiz ){
					indexNum = randQuizNums[0]; //ランダムクイズの配列要素番号を取得
					randQuizNums.splice(0, 1);  //取得した配列要素番号を削除
				}
			}

			/**
			  * ランダムに出題する「クイズの配列要素番号」を生成
			  */
			function createRandomQuizNums(){
				randomMaxCount = getElmId("quiz_exec_count").value;  //クイズの実行数を設定
				let nums = []; //配列要素番号格納用
				let rand = 0;  //ランダム値格納用

				//配列要素番号を作成
				for( let i = 0; i < g_learning_data.length; i++) {
					nums.push(i);
				}

				//ランダムな配列要素番号を作成
				for( let i = 0; i < randomMaxCount; i++) {
					rand = Math.floor(Math.random() * nums.length);
					randQuizNums.push(nums[rand]);
					nums.splice(rand, 1);
				}
			}

			/**
			  * 「クイズ実施数」のセレクトボックスの選択項目を作成
			  */
			function createQuizCountSelectOption(){
				for( var i =0; i < g_learning_data.length; i++){
					let optionObj = document.createElement('option');
					optionObj.value = i+1;
					optionObj.innerHTML = i+1;
					getElmId('quiz_exec_count') .appendChild(optionObj);
					getElmId('start_learning_btn').addEventListener('click', startLearningQuiz, false);
				}
			}

			/**
			  * クイズの「解答」クリック時の処理
			  */
			function clickAnswer(e){
				e.target.style.opacity = 0.5;                        //ボタンの透明度を設定
				result = [];                                         //クイズの正誤結果格納用(クイズ内容と結果)
				result.push(g_learning_data[indexNum]["contents"]);  //クイズ内容を配列に設定
				correctAnsObj[parseInt(g_learning_data[indexNum]["answer"]) -1].style.display = "block";  //正解の選択肢に「〇」を表示
				
				// クイズの解答が合っている場合
				if(e.target.dataset.id ===  g_learning_data[indexNum]["answer"]){
					correctCount++; // 「正解カウント」を「+1カウントアップ」
					// 「クイズデータ」の正解数を「+1カウントアップ」
					g_learning_data[indexNum]["success_count"] = parseInt(g_learning_data[indexNum]["success_count"])+1;
					result.push("〇");  //「クイズの正誤結果格納用」配列に「〇」を追加
				} else { // クイズの解答が間違っている場合
					mistakeAnsObj[e.target.dataset.id-1].style.display = "block";  //「誤り」の選択肢に「×」を表示
					result.push("×");  //「クイズの正誤結果格納用」配列に「×」を追加
				}

				results.push(result); //「結果データ群配列」に結果データを追加
				// 「クイズ挑戦回数」を「+1カウントアップ」
				g_learning_data[indexNum]["challenge_count"] = parseInt(g_learning_data[indexNum]["challenge_count"])+1;
				saveLearningData();           //クイズデータをセーブ
				dispNextBtn();                //「次へ」ボタンを表示
				if (isLast()){dispResults()}; //「クイズ実行結果」を表示
			}

			/**
			  * 「〇」「×」画像を非表示
			  */
			function hideAnswer(){
				//「〇」画像オブジェクトを全て非表示
				correctAnsObj.forEach(element => {
					element.style.display = "none";
				});
				//「×」画像オブジェクトを全て非表示
				mistakeAnsObj.forEach(element => {
					element.style.display = "none";
				});
			}

			/**
			  * 「次へ」ボタンクリック時の処理
			  */
			function toNext(){
				resetSelectAnsBtnOpacity();  //「選択肢ボタン」の透明度をリセット
				hideAnswer();                //「〇」「×」画像を非表示            
				currentQiuzCount++;          //「クイズ番号」を「+1カウントアップ」

				// 出題する「クイズの配列要素番号」を生成
				createIndexNum();  // 出題する「クイズの配列要素番号」を生成
				getElmId("quiz_count").innerHTML = currentQiuzCount;                       //「クイズ数」を設定
				getElmId("quiz").innerHTML = g_learning_data[indexNum]["contents"];        //「クイズ内容」を設定
				getElmId("select_1").innerHTML = g_learning_data[indexNum]["select_1"];    //「選択肢1」を設定
				getElmId("select_2").innerHTML = g_learning_data[indexNum]["select_2"];    //「選択肢2」を設定
				getElmId("select_3").innerHTML = g_learning_data[indexNum]["select_3"];    //「選択肢3」を設定
				getElmId("select_4").innerHTML = g_learning_data[indexNum]["select_4"];    //「選択肢4」を設定
				getElmId("next").style.display = "none";                                   //「次へ」ボタンを非表示
				getElmId("learning_quiz").style.display = "block";                         //「クイズ」を表示
				dispQuizCount();  //「クイズ番号」と「残りクイズ数」を設定
			}

			/**
			  * 「クイズ番号」と「残りクイズ数」を設定
			  */
			function dispQuizCount(){
				getElmId("quiz_count").innerHTML = currentQiuzCount;
				if( randomQuiz ){
					getElmId("quiz_remain").innerHTML = randomMaxCount - currentQiuzCount;
				} else {
					getElmId("quiz_remain").innerHTML = g_learning_data.length - currentQiuzCount;
				}
			}

			/**
			  * 「次へ」ボタンを表示
			  */
			function dispNextBtn(){
				isLast() ? getElmId("next").style.display = "none" : getElmId("next").style.display = "block";
			}

			/**
			  * 「クイズ実行結果」を表示
			  */
			function dispResults(){
				getElmId("results").style.display = "block";
				let count = 1;
				let html = "";
				html += "<hr>";
				html += "<table>";
				html += "<tr>";
				html += "<th>No</th><th>問題</th><th>結果</th>";
				html += "</tr>";
				results.forEach(element => {
					html += "<tr>";
					html += "<td>" + count + "</td><td>" + element[0] + "</td><td>" + element[1] + "</td>"; 
					html += "</tr>";
					count++;
				});
				html += "</table>";
				getElmId("results").innerHTML = html;
				results = [];
				result = [];
			}

			/**
			  * 「スタート画面(設定画面)」表示処理
			  */       
			function resetScreenToStart(){
				getElmId("setting").style.display = "block";       //「クイズ設定画面」を表示
				getElmId("learning_quiz").style.display = "none";  //「クイズ画面」を非表示
				getElmId("results").style.display = "none";        //「クイズ結果画面」を非表示
			}

			/**
			  * 「選択肢ボタン」の透明度をリセット
			  */
			function resetSelectAnsBtnOpacity(){
				getElmId("select_1").style.opacity = 1.0;
				getElmId("select_2").style.opacity = 1.0;
				getElmId("select_3").style.opacity = 1.0;
				getElmId("select_4").style.opacity = 1.0;
			} 

			/**
			  * 「最後のクイズ」を判定
			  */
			function isLast(){
				if( randomQuiz ){
					if(randomMaxCount <= currentQiuzCount){
						return true;
					}
				} else {
					if(g_learning_data.length <= currentQiuzCount){
						return true;
					}
				}
				return false;
			}

			window.onload = function(){
				loadLearningData();             //「学習データ」をロード
				createQuizCountSelectOption();  //「クイズ実施数」のセレクトボックスの選択項目を作成
				getElmId("select_1").addEventListener("click", clickAnswer, false);  //「選択肢1」ボタンのイベントリスナーを設定
				getElmId("select_2").addEventListener("click", clickAnswer, false);  //「選択肢2」ボタンのイベントリスナーを設定
				getElmId("select_3").addEventListener("click", clickAnswer, false);  //「選択肢3」ボタンのイベントリスナーを設定
				getElmId("select_4").addEventListener("click", clickAnswer, false);  //「選択肢4」ボタンのイベントリスナーを設定
				getElmId("start_screen").addEventListener("click", resetScreenToStart, false);  //「スタート画面へ」ボタンのイベントリスナーを設定
				getElmId("next").addEventListener("click", toNext, false);  //「次へ」ボタンのイベントリスナーを設定
				getElmId("learning_quiz").style.display = "none";  //「クイズ画面」を非表示
				correctAnsObj = Array.from(document.getElementsByClassName("correct"));  //「〇」画像オブジェクトを配列で取得
				mistakeAnsObj = Array.from(document.getElementsByClassName("mistake"));  //「×」画像オブジェクトを配列で取得
				hideAnswer();  //「〇」「×」画像を非表示

				//「クイズデータ」の有無を確認
				if(g_learning_data.length === 0){
					alert("先にクイズを登録してください。クイズがスタートできません。");
				}
			}


		</script>
	</head>
	<body>
		<div id="wrap_frame">
			<header>
				<img src="./images/title.png">
			</header>
			<section id="setting">
				<h2>ランダム実行</h2>
				<input type="checkbox" id="quiz_exec_random">
				<h2>ランダム出題時のラーニングクイズ実行数</h2>
				<select id="quiz_exec_count"></select>
				<button id="start_learning_btn">スタート</button>
			</section>
			<section id="learning_quiz">
				<div id="quiz_num">第<span id="quiz_count"></span>問</div>
				<div id="remain_num">(残り<span id="quiz_remain"></span>問)</div>
				<div id="quiz"></div>
				<ul id="answer">
					<li><button id="select_1" data-id="1"></button><img src="./images/answer_correct.png" class="correct"><img src="./images/answer_mistake.png" class="mistake"></li>
					<li><button id="select_2" data-id="2"></button><img src="./images/answer_correct.png" class="correct"><img src="./images/answer_mistake.png" class="mistake"></li>
					<li><button id="select_3" data-id="3"></button><img src="./images/answer_correct.png" class="correct"><img src="./images/answer_mistake.png" class="mistake"></li>
					<li><button id="select_4" data-id="4"></button><img src="./images/answer_correct.png" class="correct"><img src="./images/answer_mistake.png" class="mistake"></li>
				</ul>
				<button id="next">次へ</button>
				<hr>
				<button id="start_screen">スタート画面へ</button>
			</section>
			<section id="results"></section>
			<a href="index.html" id="to_main">メイン画面へ戻る</a>
		</div>
	</body>
</html>

下記のリンクから「ラーニングクイズアプリ」が試用できます。

→「ラーニングクイズアプリ」

「学習したい内容」は、自由に登録することができますので、クイズで遊びながら「学習をより楽しい時間」に変えてみてはいかがでしょうか。

HOMEへ