[Labyrinthe Noir]>[Top]>[こども工作教室]>

「三択クイズ」のソースと解説

問題を表示し、三択から答えを選び、得点を競います。

問題数を増やしたり、三択の選択肢を変更しやすいように作ります。

改良すると、アンケート調査やテキスト型ロールプレイングゲームにもなります。

HTMLファイルの準備

メモ帳を使って基本的なHTMLファイルを作成します。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>三択クイズ</title> </head> <body> <h1>三択クイズ</h1> <hr> </body> </html>

ファイル名を「quiz.html」として保存します。

表示位置の作成

問題、解答の選択肢、解答結果を表示する3つのエリアを用意しましょう。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>三択クイズ</title>
</head>
<body>
<h1>三択クイズ</h1>
<hr>
<h2>問題</h2>
<div id="text_q"></div>
<h2>選択</h2>
<div id="text_s"></div>
<h2>解答</h2>
<div id="text_a"></div>

</body>
</html>

<h2>タグがそれぞれの見出し。<div>タグが3つの表示エリアです。

問題文、選択肢、解答

問題文と選択肢、そして解答を一問分、セットで作成します。十問作る場合、十セットになります。

配列変数を使って、問題文と選択肢はテキストで、解答は何番目の選択肢が正解か数値で表すことにしましょう。大まかに表すと次のような順番です。

配列変数 = ["問題文","選択肢1","選択肢2","選択肢3",正解の番号];

また問題文は複数必要ですので、セット毎に配列変数を用意して、更に一セットを配列変数で分けて作ります。

<script>タグを入れて、十問を一気に作って見ましょう。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>三択クイズ</title> </head> <body> <h1>三択クイズ</h1> <hr> <h2>問題</h2>
<div id="text_q"></div>
<h2>選択</h2>
<div id="text_s"></div>
<h2>解答</h2>
<div id="text_a"></div> <script type="text/javascript"> //問題と解答 qa = new Array(); qa[0] = ["イルカを漢字で書くとどれ?","海豚","海牛","河豚",1]; qa[1] = ["クラゲを漢字で書くとどれ?","水浮","水母","水星",2]; qa[2] = ["カタツムリを漢字で書くとどれ?","禍牛","鍋牛","蝸牛",3]; qa[3] = ["バッタを漢字で書くとどれ?","飛蝗","飛蟻","飛脚",1]; qa[4] = ["タツノオトシゴを英語にするとどれ?","sea fish","sea horse","sea dragon",2]; qa[5] = ["マグロを英語にするとどれ?","funa","suna","tuna",3]; qa[6] = ["トンボを英語にするとどれ?","fly","dragonfly","butterfly",2]; qa[7] = ["ヒトデを英語にするとどれ?","starfish","starshell","starmine",1]; qa[8] = ["恒星の中で最も明るい星は?","デネブ","スピカ","シリウス",3]; qa[9] = ["惑星の中で最も重たいのはどれ?","太陽","木星","天王星",2]; </script> </body> </html>

一問目のセットが配列変数qa[0]に入っています。その一問目の問題分は配列変数qa[0][0]で呼び出せます。次の選択肢1は配列変数qa[0][1]となります。

問題を表示する

一問目の問題を表示するところからスクリプトを作って行きましょう。

変数countを用意して、現在何問目なのか記録するようにします。これを1つずつ足して行けば、今が何問目なのか、次が何問目になるのか分かります。
ただし、一問目は配列変数では0番になっているので、変数countの初期値も0で始めます。

<script type="text/javascript">
//問題と解答
qa = new Array();
qa[0] = ["イルカを漢字で書くとどれ?","海豚","海牛","河豚",1];
qa[1] = ["クラゲを漢字で書くとどれ?","水浮","水母","水星",2];
qa[2] = ["カタツムリを漢字で書くとどれ?","禍牛","鍋牛","蝸牛",3];
qa[3] = ["バッタを漢字で書くとどれ?","飛蝗","飛蟻","飛脚",1];
qa[4] = ["タツノオトシゴを英語にするとどれ?","sea fish","sea horse","sea dragon",2];
qa[5] = ["マグロを英語にするとどれ?","funa","suna","tuna",3];
qa[6] = ["トンボを英語にするとどれ?","fly","dragonfly","butterfly",2];
qa[7] = ["ヒトデを英語にするとどれ?","starfish","starshell","starmine",1];
qa[8] = ["恒星の中で最も明るい星は?","デネブ","スピカ","シリウス",3];
qa[9] = ["惑星の中で最も重たいのはどれ?","太陽","木星","天王星",2];

//初期設定
count = 0; //問題番号
q_sel = 3; //選択肢の数
//最初の問題 quiz(); //問題表示 function quiz() { //問題 document.getElementById("text_q").innerHTML = (count + 1) + "問目:" + qa[count][0]; }
</script>

初期設定には変数countの他に、変数q_selで選択肢がいくつあるか明確に示しておきます。
解答が配列変数の何番目かも必要になりますが、選択肢が増えたとしても、必ず選択肢の次に来るようにしておけば、変数q_selに1を足すだけです。

問題文の表示は、ユーザー関数にして、何度も呼び出すことを想定しています。そのため、初期設定の次に問題文の表示を呼びだしています。

ユーザー関数quizでは、画面上に問題分を表示しますが、そのテキストの最初に現在が何問目かの表示を入れています。

選択肢の表示

選択肢は、3つの中から選択して次に進む必要があるので、ボタンかリンクを使って次に進むのが良いでしょう。

また、今回は3つの選択肢しかありませんが、選択肢の数が変わった場合にも対応できるように作っておきたいと思います。

//問題表示
function quiz() {
var s, n;
//問題
document.getElementById("text_q").innerHTML = (count + 1) + "問目:" + qa[count][0];
//選択肢
s = "";
for (n=1;n<=q_sel;n++) {
s += "【<a href=''>" + n + ":" + qa[count][n] + "</a>】";
}
document.getElementById("text_s").innerHTML = s;
}

選択肢を<a>タグで挟んでリンク先に飛ばします。まだ、この段階ではリンク先がありません。
リンク先は解答が合っているか調べるユーザー関数になる予定で、その後、解答を表示して、次の問題を表示する流れにします。

【この時点の quiz.html を別枠で表示】

解答の表示

解答はユーザー関数anserで表示することとします。

そこでまず、先ほどのユーザー関数quizのリンクからユーザー関数anserを呼びだし、そのときに引数として何番目の選択肢を選んだか分かるようにしましょう。

//問題表示
function quiz() {
	var s, n;
	//問題
	document.getElementById("text_q").innerHTML = (count + 1) + "問目:" + qa[count][0];
	//選択肢
	s = "";
	for (n=1;n<=q_sel;n++) {
		s += "【<a href='javascript:anser(" + n + ")'>" + n + ":" + qa[count][n] + "</a>】";
	}
	document.getElementById("text_s").innerHTML = s;
}

//解答表示
function anser(num) {
	var s;
	s = (count + 1) + "問目:";
	//答え合わせ
	if (num == qa[count][q_sel + 1]) {
		//正解
		s += "○" + qa[count][num];
	} else {
		s += "×" + qa[count][num];
	}
	document.getElementById("text_a").innerHTML = s;
}

これで解答の表示ができました。

しかし、このままでは次の問題が表示されませんので、同じ問題に何度も解答できてしまいます。

次の問題を表示

解答の表示をすると同時に次の問題を表示しましょう。

//解答表示
function anser(num) {
var s;
s = (count + 1) + "問目:";
//答え合わせ
if (num == qa[count][q_sel + 1]) {
//正解
s += "○" + qa[count][num];
} else {
s += "×" + qa[count][num];
}
document.getElementById("text_a").innerHTML = s;

//次の問題を表示
count++;
quiz();

}

変数countに1を足して、ユーザー関数quizを呼び出すと、次の問題を呼び出すことができます。

これで次々と問題に答えて行けば良いのですが、最後の問題に答えたところでエラーが発生します。なぜなら次の問題がないからです。

最後の問題

最後の問題を判別するには、問題が何問あるか確認しなければいけません。

配列変数qaの数は10個ありますので、「qa.length」でそれと分かります。あとは現在の問題番号が変数countで分かります。変数countが10になったとき、次の問題を表示しないようにします。

//解答表示
function anser(num) {
var s;
s = (count + 1) + "問目:";
//答え合わせ
if (num == qa[count][q_sel + 1]) {
//正解
s += "○" + qa[count][num];
} else {
s += "×" + qa[count][num];
}
document.getElementById("text_a").innerHTML = s;

//次の問題を表示
count++;
if (count < qa.length) {
quiz();
} else {
//終了
document.getElementById("text_q").innerHTML = "";
document.getElementById("text_s").innerHTML = "";
}

}

10回目にユーザー関数に入ったとき、変数countは「9」です。そして、「count++」のところで中身は「10」になります。このとき、qa.lengthと同じ数になりますので、10より小さい時は問題を表示し、10になったら問題を表示しないようにします。

終了のところで、問題文と選択肢を削除しています。

【この時点の quiz.html を別枠で表示】

繰り返しできる初期設定

全問の解答が終わったときに白紙は寂しすぎますので、成績発表を行いたいと思います。

そのためには各問題の記録を残さなければなりません。また、その前段階として、問題を最初からやり直せるようにもしたいと思います。

初期設定を整理して、ユーザー関数で繰り返し処理できるようにします。

//初期設定
count = 0; //問題番号
q_sel = 3; //選択肢の数

setReady();

//最初の問題
quiz();

//初期設定
function setReady() {
	count = 0; //問題番号
	ansers = new Array(); //解答記録
	
	//最初の問題
	quiz();
}

ユーザー関数setReadyの中に、変数countを移動し、配列変数ansersを準備しています。
その後にユーザー関数quizも移動しています。

これで、ユーザー関数setReadyを呼び出せば、いつでも初期状態に戻って1問目が表示されます。

解答時の成績記録

解答時に正解・不正解の記録を残します。

ユーザー関数anserの中で、配列変数ansersを使います。

//解答表示
function anser(num) {
	var s;
	s = (count + 1) + "問目:";
	//答え合わせ
	if (num == qa[count][q_sel + 1]) {
		//正解
		s += "○" + qa[count][num];
		ansers[count] = "○";
	} else {
		s += "×" + qa[count][num];
		ansers[count] = "×";
	}
	document.getElementById("text_a").innerHTML = s;
	
	//次の問題を表示
	count++;
	if (count < qa.length) {
		quiz();
	} else {
		//終了
		document.getElementById("text_q").innerHTML = "";
		document.getElementById("text_s").innerHTML = "";
	}
}

if文の中を少し整理すると以下のようにもできます。

(省略)

	//答え合わせ
	if (num == qa[count][q_sel + 1]) {
		//正解
		ansers[count] = "○";
	} else {
		ansers[count] = "×";
	}
	s += ansers[count] + qa[count][num];
	document.getElementById("text_a").innerHTML = s;

(省略)

終了時の成績表示

各問題の答えが記録できているので、あとはそれらを表示するだけです。

テーブルで横長に組んで表示します。ユーザー関数anserの後半です。

(省略)

	//次の問題を表示
count++;
if (count < qa.length) {
quiz();
} else {
//終了
s = "<table border='2'><caption>成績発表</caption>";
//1行目
s += "<tr><th>問題</th>";
for (n=0;n<qa.length;n++) {
s += "<th>" + (n+1) + "</th>";
}
s += "</tr>";
//2行目
s += "<tr><th>成績</th>";
for (n=0;n<qa.length;n++) {
s += "<td>" + ansers[n] + "</td>";
}
s += "</tr>";
s += "</table>";

document.getElementById("text_q").innerHTML = s;
document.getElementById("text_s").innerHTML = "";
}
(省略)

リセットしてもう一度

成績の表示ができたら、行動の選択が必要です。前のページに戻るか、また同じ問題を始めるか、また別の問題があるときは別のページに飛ぶことも考えられます。

ユーザー変数anserの成績表示の後、すぐに次の選択肢を用意します。

(省略)

	} else {
		//終了
		s = "<table border='2'><caption>成績発表</caption>";
		//1行目
		s += "<tr><th>問題</th>";
		for (n=0;n<qa.length;n++) {
			s += "<th>" + (n+1) + "</th>";
		}
		s += "</tr>";
		//2行目
		s += "<tr><th>成績</th>";
		for (n=0;n<qa.length;n++) {
			s += "<td>" + ansers[n] + "</td>";
		}
		s += "</tr>";
		s += "</table>";
		document.getElementById("text_q").innerHTML = s;
		//次の選択肢
		s = "【<a href='javascript:history.back()'>前のページに戻る</a>】";
		s += "【<a href='javascript:setReady()'>同じ問題を最初から</a>】";
		s += "【<a href=''>次の問題に進む</a>】";
		document.getElementById("text_s").innerHTML = s;
	}

(省略)

変数sにそれぞれのリンクを用意して、選択肢の欄に出力しています。

「次の問題に進む」については、リンク先が未定ですので、何も記述はしていません。必要なければ削除します。
このように同じ変数に入れるものでも1つ1つを行で分けると、不要なところだけすぐに削除したりコメントアウトができます。
コメントアウトした場合は、次のようになります。

		//s += "【<a href=''>次の問題に進む</a>】";

これで画面上にもこの選択肢は出力されなくなります。

完成

三択クイズは完成しました。

意外と単純な作りで、応用も色々とできそうです。

【この時点の quiz.html を別枠で表示】

改良案

問題数を増やす

問題の数を増やす場合は、配列変数qaの数を増やすだけで対応できます。
もちろん、同じ番号にならないよう、また、順番が飛ばないように連続した番号で問題を用意してください。

問題をランダムに表示する

問題を多数用意して、その中から10問だけ表示するという方法もあります。

その場合、出題数を管理する変数を用意して、問題の上限数を設定します。

//初期設定
q_sel = 3; //選択肢の数
q_max = 10; //出題数

問題表示を乱数で決定します。
乱数は問題セットの数だけ発生させることになりますので、ここでは記述しませんが問題も多数追加しておく必要があります。

//問題表示
function quiz() {
var s, n;
//問題 rnd = Math.floor(Math.random() * qa.length); //乱数
document.getElementById("text_q").innerHTML = (count + 1) + "問目:" + qa[rnd][0];
//選択肢
s = "";
for (n=1;n<=q_sel;n++) {
if (qa[rnd][n] != "") {
s += "【<a href='javascript:anser(" + n + ")'>" + n + ":" + qa[rnd][n] + "</a>】";
}
}
document.getElementById("text_s").innerHTML = s;
}

答え合わせもこの乱数を継続して使います。

//解答表示
function anser(num) {
var s;
s = (count + 1) + "問目:";
//答え合わせ
if (num == qa[rnd][q_sel + 1]) {
//正解
ansers[count] = "○";
} else {
ansers[count] = "×";
}
s += ansers[count] + qa[rnd][num];
document.getElementById("text_a").innerHTML = s;

//次の問題を表示
count++;
if (count < q_max) {
quiz();
} else {

ただし、この方法では同じ問題が出てしまう可能性がありますので、それを防ぎたい場合は、出題済みの問題を配列変数で管理しなければなりません。
出題済みの問題番号と乱数を比較して、同じものがあれば、再び乱数を取り直すという処理が必要になります。

選択肢を増やす

選択肢を増やす場合の注意箇所をまとめておきます。

選択肢を5つに増やした場合、問題文は次のようになります。

qa[0] = ["イルカを漢字で書くとどれ?","海豚","海牛","河豚","選択肢4","選択肢5",1];

これと当時に変数q_selも修正しましょう。

//初期設定
q_sel = 5; //選択肢の数

選択肢の数が変動する場合

上限が五択で、下限が二択というように問題によって変動する場合、変数q_selは上限の値にしておきます。
次に選択肢が少ない場合には問題を次のように作ります。選択肢2つのあと、いらないところは空にします。

qa[0] = ["イルカを漢字で書くとどれ?","海豚","海牛","","","",1];

次に選択肢を表示するユーザー関数quizの中で空の選択肢に対応した処理を書き加えます。

//問題表示
function quiz() {
var s, n;
//問題
document.getElementById("text_q").innerHTML = (count + 1) + "問目:" + qa[count][0];
//選択肢
s = "";
for (n=1;n<=q_sel;n++) {
if (qa[count][n] != "") { s += "【<a href='javascript:anser(" + n + ")'>" + n + ":" + qa[count][n] + "</a>】"; }
}
document.getElementById("text_s").innerHTML = s;
}

最終の quiz.html には上記修正を加えています。

【この時点の quiz.html を別枠で表示】

アンケート

アンケート調査や性格判断のような使い方もできます。

例えば問題文を次のようにして、ポイントを付加します。正解はないため、正解番号は削除しています。

qa[0] = ["あなたの血液型は?","A型","B型","AB型","O型",20,10,15,25];

選択肢の後に、対応する順番にポイントを用意して配列に格納しておきます。
選択肢は変数q_selで4つと指定しておけば、ポイントも4つということになり扱い安くなります。
配列変数qa[0][n]に対応するポイントは配列変数qa[0][n+q_sel]で表せるからです。

ユーザー関数quizの中は見出しの部分だけ変更します。

//問題表示
function quiz() {
var s, n;
//問題
document.getElementById("text_q").innerHTML = "設問" + (count + 1) + ":" + qa[count][0];
//選択肢
s = "";
for (n=1;n<=q_sel;n++) {
if (qa[count][n] != "") {
s += "【<a href='javascript:anser(" + n + ")'>" + n + ":" + qa[count][n] + "</a>】";
}
}
document.getElementById("text_s").innerHTML = s;
}

選択肢の表示は今まで通りですが、ユーザー関数anser内の答え合わせの修正が必要です。

//解答表示
function anser(num) {
var s;
s = "設問" + (count + 1) + ":";
//答え合わせ
ansers[count] = qa[count][num+q_sel];
s = qa[count][num] + "(" + qa[count][num+q_sel] + "点)";

document.getElementById("text_a").innerHTML = s;

後は、点数の合計を計算して、表示させます。

		//1行目
s += "<tr><th>設問</th>";
for (n=0;n<qa.length;n++) {
s += "<th>" + (n+1) + "</th>";
}
s += "<th>合計</th></tr>";
//2行目
s += "<tr><th>回答</th>"; var total = 0;
for (n=0;n<qa.length;n++) {
s += "<td>" + ansers[n] + "</td>"; total += eval(ansers[n]);
}
s += "<td>" + total + "</td></tr>";

ここまでの改良をしたアンケート調査のひな形を用意してあります。

【アンケート調査 enquete.html を表示】

最後に合計点数に応じた所見を表示しても良いでしょう。

テキストRPG

問題文の代わりにストーリーを書き、読み手の行動選択を選択肢にすることで、ゲームブックにも利用できます。

アンケート調査で改良した形式で問題セットを作って、ポイント計算をすることでゲーム内に変化を作り出すことができます。
また、移動を順番にするのではなく、選択肢によって変化させても面白いでしょう。

続きはこちらの「テキストRPG」で行います。

戻る