2進から10進練習

どちらかを選んでください

0から7まで8問出題します

0から15まで16問出題します

再挑戦しますか?

0から7まで8問出題します

0から15まで16問出題します

制作意図

こちらも、親しんでもらうことだけです。スラスラとできるようになる必要はないですが、2,4,8,16とか1,3,7,15から進めたり戻したりしながら考えればわかるようにはなって欲しいところです。10進から2進は実際には使う場面がないと考えて省略しています。

プログラムなど

このプログラムの制作時期は、「ビット数とパターンの数」より前です。当時のプログラムはクリックで渡される数を変換して正誤を判断していましたが、今回「ビット数とパターンの数」を利用して問題-解答の配列にしてから使う手法に変えました。

プログラムは整理すると理解しやすくなることも多いですが、巧妙な手法のゆえにわかりにくくなることもあります。

この「授業で使ったプログラム」は、わかりやすく自分で改変したり新たに作る時の参考にしてほしいという気持ちが大きく働いています。

「ビット数とパターンの数」ではグローバル変数なるものをfunctionの外に出してみましたが、ここではinit()というfunctionの中にまとめてvarをつけずに書くという手法にしてみました。

そもそも、varを書くのもあとになって追加された文法で、さらに2015年のバージョンからはconstとletの宣言が加わりました(実は置き換えになります)。変化していくものについてあまりあれこれ追求しないことにします。

ただし、DOMとの組み合わせでは、変数の実体と名前を別のものとして把握することが必要だと感じます。

初期化部分

0-7と0-15の2種類の問題を出すので引数が2つです。m種類の解答の選択肢がある問題をn個出すようにします。

「ビット数とパターンの数」で直接記述していた問題と選択肢の配列をプログラムで作ってから使っています。一見無駄ではありまずか、「ビット数とパターンの数」のプログラムを流用できるところが強みです。

function init(m,n){
  q = [];
  a = new Array(); //same with []
  for (var i = 0; m > i ; i++) {
    q.push(i.toString(2));
    a.push(i.toString());
  }
  ran = -1; //-1 will be never used
  toiwaku = document.getElementById("toiwaku");
  answers = document.getElementById("answers");
  toiPelement = document.createElement("p"); //dummy
  //toitextnode = document.createTextNode("");
  for (var i = 0; a.length > i ; i++) {
     var text = document.createTextNode(a[i]);
     var sentakushi = document.createElement("button");
     sentakushi.appendChild(text);
     sentakushi.setAttribute("type","button");
     sentakushi.setAttribute("onclick","answer("+i+")");
     answers.appendChild(sentakushi);
     //if(i==7) answers.appendChild(document.createElement("br"));
  }
  document.getElementById("replay").setAttribute("style","display:none;");
  document.getElementById("start").setAttribute("style","display:none;");
  toimax = n; //kurikaeshi suu
  toiNo = 1;
  seikaict=0;
  gotouct =0;
  answers.setAttribute("style","display:block;");
  putmondai();
}

再挑戦の入り口

全問解答したあとに、再挑戦するには、onclick="location.reload();" を使ってもいいのです。しかし、removeChild()を使ってみたくでこのようにしました。一度に全部削除できないので、whileを使っています。これさえしてしまえばinit()を呼び出しても大丈夫です。

function restart(m,n){
  while (toiwaku.firstChild) {
    toiwaku.removeChild(toiwaku.firstChild);
  }
  while (answers.firstChild) {
    answers.removeChild(answers.firstChild);
  }
  init(m,n);
}

1つの問題を出題

「ビット数とパターンの数」と同じです。違いはテキストノードでなく、p要素をグローバルとしていることです。

テキストノードのほうがデータに近いのですが、他のidで特定された「要素」であることから、p要素のほうがしっくりきます。

function putmondai(){    
    ran = Math.floor( Math.random() *q.length );
    var text = document.createTextNode(
        "第"+toiNo+"問 : " + q[ran]);
    toiPelement = document.createElement("p");
    toiPelement.appendChild(text);
    toiwaku.appendChild(toiPelement);
}

正誤判定

p要素をグローバルとしてテキストを入れ替えているので、.nodeValueだったところが.firstChild.nodeValueとなっています。

function answer(ans){
  if (ans == ran){
    seikaict++;
    toiPelement.firstChild.nodeValue = "第"+toiNo+"問 : 正解です。"
         +" 正解数は"+seikaict+" ,誤答数は"+gotouct;
  }
  else{
    gotouct++;
    toiPelement.firstChild.nodeValue = "第"+toiNo+"問 : 違います。"
         +" 正解数は"+seikaict+" ,誤答数は"+gotouct; 
  }
  if (toimax>toiNo){
    toiNo++;
    putmondai();
  }
  else{
    var text = document.createTextNode(
        "正答率は "+seikaict/(seikaict+gotouct)*100 +" % でした。");
    var pnode = document.createElement("p");
    pnode.appendChild(text);
    toiwaku.appendChild(pnode);
    answers.setAttribute("style","display:none;");
    document.getElementById("replay").setAttribute("style","display:block;");
  }
}

HTML

ビット数とパターンの数と同様ですが、問題の範囲と数を選択するように2つあります。

再挑戦はlocation.reload()で済ませずに、restart()というfunctionを作っています。

<div id="start">
<p>どちらかを選んでください</p>
<p><button type="button" onclick="init(8,8)">0 - 7</button> 0から7まで8問出題します</p>
<p><button type="button" onclick="init(16,16)">0-15</button> 0から15まで16問出題します</p>
</div>

<div id="toiwaku"></div>

<div id="answers"></div>

<div id="replay">
<p>再挑戦しますか?</p>
<p><button type="button" onclick="restart(8,8)">0 - 7</button> 0から7まで8問出題します</p>
<p><button type="button" onclick="restart(16,16)">0-15</button> 0から15まで16問出題します</p>
<!-- <button type="button" onclick="location.reload();">もう一度</button> -->
</div>