穴埋め問題作成(穴の位置調整ツール)
穴埋め問題を作るとき、穴の位置を調整するのに手間がかかります。
今回、その手間を軽減するツールを作りました。
穴埋め問題
LBT(Learning by Typing)
LBT(Learning by Typing)は、お手本となるプログラムをタイピングで書き写すことで、プログラミングを学習するシステムです。
Fig.1 は、LBT の学習画面です。画面上半分にお手本となるプログラムがあります。
画面下半分は、穴が開いた「穴埋め問題」になっています。
穴埋め問題といっても、いろいろな種類や形態がありますが、今回は、LBT のような穴埋め問題を対象とします。
LBTについては、記事「タイピングでプログラミング学習するシステム」をご参照ください。
作成手順
穴埋め問題は、制作手順は一般的に次のようになります。
- まず、正解となる文章を用意する
- 次に、文章のどこを空白(穴)にするかを決める
- 回答欄を用意する
LBT では、次のようにして穴埋め問題を作成しています。
- 画面上半分: 正解となるプログラムを表示
- プログラムのどの部分を空白にするかを決定
- 画面下半分:
- 正解となるプログラムを表示
- 空白とする部分と同じ大きさの回答欄を用意
- 空白とする部分に回答欄を重ねる
作成の手間
LBT のような穴埋め問題を作成するとき、穴の大きさや位置を調整します。
問題文を更新したときや、正解箇所を変更したときなど、その都度、穴の位置を指定し直す必要があり、手間のかかる作業となります。
穴の位置を調整するツール(LBT-tool)
各部品
LBT-tool.htmlを動かすと、初期画面になります(Fig.2 参照)。
LBT-tool には、主に、3 個の部品があります(Fig.2 参照)。
- Text領域(大)
- Text領域(小)
- Canvas 領域
Text 領域(大)
- 機能:手本となるプログラムの表示
Text 領域(大)とCanvas 領域は重なっています。
Text 領域(大)の上に、Canvas 領域があります。
- Text 領域(大)の左上と、Canvas 領域の左上は一致しています。
Text 領域(小)
- 機能:穴の位置と長さを入力
初期値、25, 15, 60, 75, 130, 65 が入力済みです。
これらの数値は、穴の位置と長さを表しています。
例えば、25, 15, 60 は、次の穴を表します。
- 穴の位置:Canvas左上から、右方向に25px、下方向に15px
- 穴の長さ:60px
初期値は、2 個分の穴の数値です。
数字3 個で1 個の穴が記述できます。
そのため、穴を3 個にしたい場合は、適正な数値を9 個書きます。
Canvas 領域
- 機能:穴を表示
Text 領域(小)の数値に対応した穴を表示します。
Canvas 領域には、穴の位置指定がやり易いよう、100px 毎にメッシュが付いています。
使い方
以下の手順で穴の位置・長さを調整します。
- Text 領域(大)に、手本となるプログラムをコピー&ペースト
- 空白にしたい文字を決定
- 「function」と「context.rect」
- 穴の位置を調整
- Text 領域(小)の各数値を修正
最終的に、空白にしたい文字と、穴が完全に重なります(Fig.3 参照)
Text 領域(小)の数値が、穴埋め問題の穴の位置になります。
プログラム(LBT-tool)
以下、LBT-tool.html のプログラムです。
プログラム1
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style> canvas{border:solid 1px;} div { position:absolute; } .canvas { z-index:1; } .textarea { z-index:0; } </style> <script> var timer_ID; var time; var interval = 1000; const BLANK_HIGHT = 10; var x = 0, y=0, w=600, h=250; // canvas var context; function drawBlank() { context.clearRect(x,y,w,h); context.beginPath(); var str = document.getElementById("blank").value; var strSplit = str.split(","); var numOfBlank = strSplit.length/3; for (var i=0; i<numOfBlank; i++) { context.rect(strSplit[3*i],strSplit[3*i+1],strSplit[3*i+2],BLANK_HIGHT); } drawMesh(); context.stroke(); } function drawMesh(){ for (var i=0; i<=6; i++) { for (var j=0; j<=2; j++) { context.rect(100*i, 100*j, 100*(i+1), 100*(j+1)); }} } window.onload = function() { var canvas = document.getElementById('canvas'); context = canvas.getContext('2d'); timer_ID = setInterval("drawBlank()", interval); } </script> </head> <body> <div class="canvas"> <canvas id="canvas" width=600 height=250> </div> <div class="textarea"> <textarea cols="110" rows="23" id="example"></textarea> <br><br> <textarea cols="110" rows="2" id="blank">25, 15, 60, 75, 130, 65</textarea> </div> </body> </html>
プログラム1 の説明
概要
プログラム1 は、「タイマー」と「長方形描画」を組み合わせて作りました。
プログラム1 の処理概要は、次のようになります。
- 1 秒毎、以下の処理を実行
- Text領域(小)の数値を読む
- 長方形を描画
タイマーについては、記事「1 分タイマーの作り方」をご覧ください。
長方形描画については、記事「Canvas に長方形を描く」をご覧ください。
onload 関数
window.onload = function() { var canvas = document.getElementById('canvas'); context = canvas.getContext('2d'); timer_ID = setInterval("drawBlank()", interval); }
- Canvas の使用準備
- 2 次元(2D)描画のコンテキストを得ます
- タイマーの準備
- 1,000 m(1 秒)毎に、drawBlank() 関数を実行します
drawBlank()
function drawBlank() { context.clearRect(x,y,w,h); context.beginPath(); var str = document.getElementById("blank").value; var strSplit = str.split(","); var numOfBlank = strSplit.length/3; for (var i=0; i<numOfBlank; i++) { context.rect(strSplit[3*i],strSplit[3*i+1],strSplit[3*i+2],BLANK_HIGHT); } drawMesh(); context.stroke(); }
処理の手順は、以下となります。
- Canvas 上の描画物を消去
- text 領域(小)から数値を読む
- “,” で区切り、配列に代入
- 穴の数を計算
- 穴の数だけ、長方形を描画
- メッシュを描画