JS|別ページのデータから条件に従いクイズを選び出す関数|2次元配列制御方法

勘違いしながらドはまりしながら作り上げていく『JavaScript奮闘記』。事始めのJavaScript常識をまとめたページや現在作ろうとしてるクイズの仕様説明はこちら。

ポク太郎です。

本ページの話題は「JavaScriptで別ページ内の情報を取得後、条件に合うデータを選び出す。」『JavaScript3択クイズを作ろう』中の一機能。

別ページから読み込んだクイズ問題の中から実際に出題する問題を選び出すルーチン。


前回、別ページのデータを読み込んだ

別ページからデータを読み込むルーチンはこちら。詳細はこちら

その問題のデータが書いてある別ページのURLはhttps://poku.blog/js-test

document.getElementById("debug").innerHTML = '';
var obj = new XMLHttpRequest();
obj.open('GET','https://poku.blog/js-test',true);//true:非同期通信
obj.onreadystatechange = function(){

	if (obj.readyState === 4 && obj.status === 200){
		var str = obj.responseText; //読み込んだHTMLを変数に代入
//----処理
		var qdt = str.match(/<div class="qdt">.+?<\/div>/g);

			document.getElementById("debug").style.display = '';
		//id="debug"タグにテキストを記述する。
		for (var i=0;i<qdt.length;i++){
			document.getElementById("debug").innerHTML += qdt[i];
		}
//----処理
	}

	};
	obj.send(null); //リクエストの送信

上記の結果、qdt[i]には以下のデータが代入されました。

9000,足し算,r,3+5=?,8○,9,10,正解は「8」です。
9001,足し算,r,4+5=?,8,9○,10,正解は「9」です。
9002,足し算,r,3+9=?,12○,15,10,正解は「12」です。
9003,足し算,r,2+8=?,8,9,10○,正解は「10」です。
9004,引き算,r,2-5=?,-3○,-5,7,正解は「-3」です。
9005,引き算,r,11-4=?,7○,9,10,正解は「7」です。
9006,引き算,r,9-2=?,7○,6,11,正解は「7」です。
9007,引き算,r,8-5=?,3○,2,13,正解は「3」です。
9008,掛け算,r,2×5=?,10○,12,7,正解は「10」です。
9009,掛け算,r,11×4=?,44○,42,7,正解は「44」です。
9010,掛け算,r,4×4=?,16○,20,8,正解は「16」です。
9011,掛け算,r,3×4=?,12○,10,7,正解は「12」です。
9012,割り算,r,10/5=?,2○,3,4,正解は「2」です。
9013,割り算,r,9/3=?,3○,4,5,正解は「3」です。
9014,割り算,r,3/2=?,1.5○,2,1,正解は「1.5」です。
9015,割り算,r,4/2=?,2○,1,4,正解は「2」です。
9016,慣用句,r,○○を漢字で埋めなさい。豚に○○。,真珠○,念仏,小判,正解は「真珠」です。
9017,慣用句,r,○○を漢字で埋めなさい。人生万事塞翁が○,馬○,豚,猿,正解は「馬」です。
9018,慣用句,r,○○を漢字で埋めなさい。猿吉は○でも踏んどれ。,麦○,米,肉,正解は「麦」です。
9019,慣用句,r,○○を漢字で埋めなさい。パンツトラナイデネ!○○トコナイデネ!,二度○,再度,既,正解は「二度」です。

データのフォーマットは以下としました。

クイズNo,カテゴリ,シャッフルフラグ,問題文,選択肢1,選択肢2,選択肢3,正解の解説文

としました。シャッフルフラグとは選択肢の順番を並び替えて出題するかどうか、また選択肢中の正解には文末に○。

条件に従いクイズを選び出す関数

プログラムの仕様として別ページBからクイズデータ全体を読み取り、そこからクイズデータを出題順番に出題数分だけ配列qx[][]に入れてしまう構成としました。

データフォーマットにある、選択肢をシャッフルした結果も配列qx[][]に代入することに。

こうすることで以降は配列qx[][]を順番に表示するだけで目的の機能が果たせるし、最後に表示するクイズの正誤解説文作成時にも配列qx[][]だけ意識すればOKとなるので。

定義した変数

定義した変数
qdt[]別ページから読み込んだクイズデータ。
qdt2[][]2次元配列化したクイズデータ。
mode_tudo(ここでは未使用)1問づつ正誤表示するかどうかの設定。
catego選び出すカテゴリ設定。
ntest出題数設定。
count(ここでは未使用)問題番号。
q_sel(ここでは未使用)選択肢の数。
qx[][]出題決定した問題の2次元配列化。
an[](ここでは未使用)正解だったかどうか。

定義したグローバル関数

定義したグローバル関数
quiz_make()読み込んだクイズデータから条件に従い実際に出題する質問を選び出す関数。
rand(min,max)乱数発生関数。最小値と最大値を引数として設定する仕様。
quiz_shuffle()クイズデータに選択肢の順番を入れ替えるためのシャッフルフラグを持たせた仕様。そのシャッフル機能を実現する関数。

クイズを選び出すJavaScriptソースコード

var qdt=[];//クイズのデータ
var qdt2=[];//クイズのデータ2次元配列化

var mode_tudo=1;//1:1問づつ正誤表示
var catego='掛け算';

var ntest=3;//出題数
var count=0;//現在の問題番号
var q_sel=3;//選択肢の数

var qx=[];//qx[]出題された問題
var an=[];//an[]正解したら1違うなら0

document.getElementById("debug").innerHTML = '';
var obj = new XMLHttpRequest();
obj.open('GET','https://poku.blog/js-test',true);//true:非同期通信
obj.onreadystatechange = function(){

	if (obj.readyState === 4 && obj.status === 200){
		var str = obj.responseText; //読み込んだHTMLを変数に代入
//----処理
		qdt = str.match(/<div class="qdt">.+?<\/div>/g);

			document.getElementById("debug").style.display = '';

		quiz_make();

//----処理
	}

	};
	obj.send(null); //リクエストの送信

function rand( min, max ) {
//範囲選択可能な乱数
	var random = Math.floor( Math.random() * (max + 1 - min) ) + min;
	return random;
}

function quiz_make() {
//クイズデータの作成
	var tmp=[];//2次元配列作成用
	var sel=[];//既に選択済の番号記憶

	//2次元配列qdt2にデータ入れ直し
	for (var i=0;i<qdt.length;i++){
			tmp=qdt[i].split(',');
			qdt2[i]=[];//JavaScript常識、配列の階層ごとに初期化要
		for (var j=0;j<tmp.length;j++){
			qdt2[i][j]=tmp[j];
		}
	}

							var n;
							var find;

	//無限ループに陥らないよう条件に合うcategoの数>出題数を先に確認する
							var kazu = 0;
							var jd;
	for (var i=0;i<qdt.length;i++){
			if (qdt2[i][1] == catego){
							kazu = kazu + 1;
			}
	}
	if (kazu >= ntest){
							jd = true;
	} else {
							jd = false;
	}

	if (jd == false){
				document.getElementById("debug").innerHTML += kazu + 'エラー:条件に合うクイズデータが出題数より少なく無限ループに陥ります。';
	} else {
		for(i=0;i<ntest;i++){
			while(0==0){
							find=1;
							n=9000+rand(0,qdt.length-1);
	//	document.getElementById("debug").innerHTML += 'n=' + n;
				if (qdt2[n-9000][1] == catego){
							find=0;
					for (i=0;i<sel.length;i++){
						if (sel[i] == n){
							find=1;
							break;
						}
					}
				}
				if(find == 0){
							sel.push(n);
							break;
				}
			}
		}
	}

				tmp=[];//2次元配列作成用
	for (i=0;i<sel.length;i++){
				n=Number(sel[i]-9000);
				tmp=qdt[n].split(',');
				qx[i]=[];//JavaScript常識、配列の階層ごとに初期化要
		for (j=0;j<tmp.length;j++){
				qx[i][j]=tmp[j];
		}
	}
				quiz_shuffle();
				count = 1;

	//id="debug"タグに選び出したクイズデータqxを記述する。
	for (i=0;i<qx.length;i++){
	//	document.getElementById("debug").innerHTML += '選択したクイズNo.:' + qx[i][0] + ' カテゴリ:' + qx[i][1] + ' 問題文:' + qx[i][3] + '<br />';
	}
}

function quiz_shuffle() {
//シャッフルフラグの対応
	//クイズのフォーマット
	//クイズNo,カテゴリ,シャッフルフラグ,問題文,選択肢1,選択肢2,選択肢3,正解の解説文

						var tmp;
						var a,b;
	for (var i=0;i<qx.length;i++) {
		if(qx[i][2] == 'r'){
			for (var j=0;j<100;j++) {
			//100回入替を行う
						a = rand(4,4+q_sel-1);
						b = rand(4,4+q_sel-1);
						tmp = qx[i][a];
						qx[i][a] = qx[i][b];
						qx[i][b] = tmp;
			}
		}
	}

	//id="debug"タグに選び出したクイズデータqxを記述する。
	for (i=0;i<qx.length;i++){
		document.getElementById("debug").innerHTML += '選択したクイズNo.:' + qx[i][0] + ' 選択肢1:' + qx[i][4] + ' 選択肢2:' + qx[i][5] + ' 選択肢3:' + qx[i][6] + '<br />';
	}
}

ソースコード説明

実際に出題するクイズを選び出す関数quiz_make()

別ページBから読み込んだqdt[]を2次元配列化しますが、ここで注意点。

JavaScriptで多次元配列を使用する際は配列の階層ごとに初期化要だそう。

なので、.split(‘,’)tmp[]に代入した,区切りのデータをqdt2[][]に代入する際、qdt2[i]=[];と初期化しております。

2次元配列を作り、qdt2[i][]を完成させた後、実際に出題する質問をランダムに選び出す部分。

一度選択したクイズNo.を配列変数sel[]に保持しておき、異なるクイズNo.が乱数で生成されるまでwhile文でループさせます。

ただし、上記は無限ループに陥らない条件:「該当カテゴリのデータ数>ntest」を満たすかどうかを事前に変数kazuで数えてエラーメッセージを出すようにしています。

選び出したntest個の要素番号が配列sel[]に入ってるので、それに従い別の2次元配列qx[][]にそのデータを代入。

その後、選択肢をシャッフルさせる関数に移行。シャッフルフラグ付きなら関数rand()を利用し、選択肢データ=配列qx[][]の要素4、5、6番目の入れ替えを100回繰り返しています。

これで実際に出題する問題qx[][]が出来上がりました。

別ページの情報を読み、条件に従い選び出した結果

ここから

ここまで表示領域。

本ページでは、別ページBからのデータから条件に従い実際に出題する問題を選び出すまでを実施してみました。

JavaScript3択クイズを作ろう
Step 0Step 1Step 2Step 3

コメント

タイトルとURLをコピーしました