ansjs

(2022.11.1-2024.2.15)

ansjs 231031 DownLoad from [researchmap]

Webページに設置する,正規表現やJava Scriptで正解を記述できる,Java Scriptによる穴埋め問題。サンプル 紀要

設置

ansjsと正解ファイルを読み込みむ:

<script src="ans.js" type="text/javascript"></script>

<script src="a64.js" type="text/javascript"></script>

ansjsはzipファイルから展開したもの,正解ファイルは各自で作るもの,ここではa64.jsとしたそして,bodyタグに解答状態をロードする関数を書く:

<body onload="loadallvalues();">

解答状態は,ブラウザに保持されるが,それを全てクリアして初期状態に戻すには,clearallvalues関数をcallする。例えば,次のようなボタンを設置する:

<input type="button" value="clear all" onclick="clearallvalues();">

問題の書き方

チェックボタン

正誤チェックボタン

<input type="button" value="check" name="check" onclick="check(this);">

を挿入し,その親要素に,半角英数でQ1などのidをふる。そのidが正誤判定に使われる問題idになる。

穴埋め問題の要素は,問題idを設定した要素の子要素として(問題idを設定したタグで囲まれた部分に),readonly属性が設定されていない1行のtext入力 

<input type="text" size="4">

か,複数行のtextarea

<textarea rows="2" cols="50" spellcheck="false" style="overflow: hidden;">文字列</textarea>

で設置する。選択型の要素は次のように1行のtext入力にlist属性を設けて,datalistで設置する。

<input type="text" size="4" list="q3">

<datalist id="q3">

  <option>call</option>

  <option>命令</option>

  <option>クラス</option>

  <option>メソッド</option>

</datalist>

チェックボタンを押すと,正誤判定がなされ,正解の要素は緑(lightgreen),不正解の要素は赤(pink),未解答の要素は変化しない。

チェックマーク

問題番号などを表示する要素に,

id=Q1t

のように問題idの末尾にtを付したidを振ると,その問題が全て正解の場合,その要素の末尾に✅がつく。

正解の書き方

正解はJava Scriptファイルに次のように書く。

ans64オブジェクト

ans64 = {

  '問題id1':[要素1の正解, 要素2の正解, ...,],

  '問題id2':[要素1の正解, 要素2の正解, ...,],

};

ans64 = {

  '問題id1':[[要素1の正解, 要素2の正解], 要素3の正解, ...,],

  '問題id2':[要素1の正解, 要素2の正解, ...,],

}

とする。

文字列,数値・数式,正規表現

配列要素は,シングルコーテーションまたはダブルコーテーションで囲った文字列か,スラッシュで囲んだ正規表現である。

解答文字列の前処理

正解との比較に先立ち,解答文字列は次のように前処理される。

問題idがQ02-1,Q03-4,Q04-1,Q04-3,Q04-4,Q04-5,Q04-6に穴埋め要素がそれぞれ4, 5, 1, 4, 12, 8, 1箇所ある場合の正解ファイルの例:

ans64 = {

    'Q02-1':[['エディタ','コンパイラ'],'ソースプログラム','機械語プログラム'],

    'Q03-4':['java Hello','Visual Studio Code','Hello.java','javac Hello.java','Hello.class'],

    'Q04-1':["7"],

    'Q04-3':[['クラス','メソッド'],'call','クラス'],

    'Q04-4':[ ['空白','改行'], '字下げ', "0", "0", "2", "2", "4", "2", "0", '同じ', '大きく'],

    'Q04-5':['javac','java', '文法', '文法エラー', '論理エラー', '文法エラー', '論理エラー', '最初'],

    'Q04-6':[/^System\.out\.println\("(?!.*(Hello|world)).*"\);System\.out\.println\("(?!.*(Hello|world)).*"\);/],

}

Q02-1,Q04-3,Q04-4の1番目と2番目の空所,は順不同。

正解ファイルのエンコード

正解ファイルができたら(a.jsとする)

perl ans.pl a.js

とコマンドを打って内容が簡単には読めないように,配列要素をbase64エンコードしたファイルを生成する生成されるエンコードされた正解ファイル名は,正解ファイルのベース名に64をつけたもの,例えば,正解ファイルがa.jsならa64.jsとなる。

以下は,上の例の正解ファイルをエンコードしたもの:

ans64 = {

    'Q02-1':[['J+OCqOODh+OCo+OCvyc=','J+OCs+ODs+ODkeOCpOODqSc='],'J+OCveODvOOCueODl+ODreOCsOODqeODoCc=','J+apn+aisOiqnuODl+ODreOCsOODqeODoCc='],

    'Q03-4':['J2phdmEgSGVsbG8n','J1Zpc3VhbCBTdHVkaW8gQ29kZSc=','J0hlbGxvLmphdmEn','J2phdmFjIEhlbGxvLmphdmEn','J0hlbGxvLmNsYXNzJw=='],

    'Q04-1':['Ijci'],

    'Q04-3':[['J+OCr+ODqeOCuSc=','J+ODoeOCveODg+ODiSc='],'J2NhbGwn','J+OCr+ODqeOCuSc='],

    'Q04-4':[ ['J+epuueZvSc=','J+aUueihjCc='], 'J+Wtl+S4i+OBkic=', 'IjAi', 'IjAi', 'IjIi', 'IjIi', 'IjQi', 'IjIi', 'IjAi', 'J+WQjOOBmCc=', 'J+Wkp+OBjeOBjyc='],

    'Q04-5':['J2phdmFjJw==','J2phdmEn', 'J+aWh+azlSc=', 'J+aWh+azleOCqOODqeODvCc=', 'J+irlueQhuOCqOODqeODvCc=', 'J+aWh+azleOCqOODqeODvCc=', 'J+irlueQhuOCqOODqeODvCc=', 'J+acgOWInSc='],

    'Q04-6':['L15TeXN0ZW1cLm91dFwucHJpbnRsblwoIig/IS4qKEhlbGxvfHdvcmxkKSkuKiJcKTtTeXN0ZW1cLm91dFwucHJpbnRsblwoIig/IS4qKEhlbGxvfHdvcmxkKSkuKiJcKTsv'],

};

 上記コマンドは,VSCodeの[terminal]-[Configure Tasks...]で,tasks.jasonにブロック

{

  "label": "perl ans.pl",

  "type": "shell",

  "command": "perl ans.pl ${file}",

  "problemMatcher": [],

  "group": {

    "kind": "build",

    "isDefault": false

  }

},

を挿入すれば,VSCodeで正解ファイルを編集して,そのままメニュー[Terminal]-[Run Tasks]で実行できるans.plは絶対パスで書くこと)。

ハード再読み込み Shift+Ctrl+R

正解ファイルを修正した場合,ブラウザでページを再読み込みするだけでは,正解ファイル(Java script)が再読み込みされない場合があるので,キャッシュをクリアして再読み込みする「ハード再読み込み」をする必要がある。強制再読み込みはShit+Ctrl+R。

see https://qiita.com/kondo0602/items/7cc6e0e7783b3533ce2f

正解の例

サンプル参照。その他:

JavaScriptで記述する場合:

解答された数式が正しいか確認するために,幾つかの値を代入して計算される値が正しければ数式が合っていると推測して,解答された数式の正誤を判定する。

例1:解答の式が100000+7*(omosa-10000)であるか,2点omosa=10000,20000で確認する:

"{function d(omosa){return Math.abs(eval(ans)-(10000*10+(omosa-10000)*7))<1e-10;} d(10000)&&d(20000);}"

解答文字列ansをプログラムとして評価するためには,eval関数を使ってeval(ans)と書く必要がある。

記述を短くするにはアロー記法を用いるとよい:

"{var d=omosa=>return Math.abs(eval(ans)-(10000*10+(omosa-10000)*7))<1e-10; d(10000)&&d(20000);}"

例2:解答の数式がf(c)*(b-a)であるか(c=(a+b)/2であることは与えられている),f(x)=√xに対して,2点(a,b)=(0.2,0.6),(0.1,0.11)で確認する:

"{function f(x){return Math.sqrt(x);} function d(a,b){var c=(a+b)/2; return eval(ans)==f(c)*(b-a);} d(0.2,0.6) && d(0.1,0.11);}"

アロー記法

"{var f=x=>return Math.sqrt(x), d=(a,b)=>{var c=(a+b)/2; return eval(ans)==f(c)*(b-a); d(0.2,0.6) && d(0.1,0.11);}"

解答された値が誤差の範囲で正解と一致しているか確認する。

例:解答が0.02125±0.001か?

"{Math.abs(parseFloat(ans)-0.02125)<0.001;}"

解答された条件式に含まれる変数に,(幾つかの)数値を代入して,条件式が正しいかどうか確認する。

正規表現で記述する場合:

(?=.*キーワード1)(?=.*キーワード2)(?=.*キーワード3)

クリップボードを介した解答の送信機能

LMSやメールなどを使って,穴埋めの解答をコピーして送付してもらうための関数copyallvaluesとそれを解読するバッチファイルansclip。

copyallvalues関数は,全ての穴埋め要素を正誤判定し,時刻,乱数,正解でない要素,問題idがidである要素(学籍番号や氏名),問題idの末尾がdocである要素(記述問題)の内容(value)をbase64でエンコードして,クリップボードにコピーする。

copyallvalues関数の引数は,name属性の値が引数に一致する問題のみがコピーされる。必須と発展のように問題のカテゴリーを分ける時に利用する。

バッチファイルansclip.batは(注:ansclip.batは,zipファイルに含まれる。同じくzipファイルに含まれるansclip.plが同じフォルダにないと動きません),クリップボードにコピーされた,複数の改行で区切られたエンコードされた解答を,見出し行と複数の解答行からなる,次のようなtsv(tab separated value)形式に変換する:

score  \t                 \t    \t 問題id \t 問題id...

正答率% \t 年/月/日 時:分:秒 \t 乱数 \t 値    \t 値   ...

正答率% \t 年/月/日 時:分:秒 \t 乱数 \t 値    \t 値   ...

...

ここで,\tはタブ。1行目は見出しで,

2行目以降の値は,

例:

score for bas Q02-1

50% 2023/2/18 22:52:21 547 300MB

50% 2023/2/18 22:48:50 439 -

tsv形式は,表計算ソフトにそのまま貼り付けられる形式である。この機能によって,以下のようにして解答一覧を得ることができる:

サンプル


Windowsでローカルに使うには

Windowsで,[researchmap]から配布zipファイルをダウンロードして,展開して,simpleフォルダ内のindex.htmlをダブルクリックするとデフォルトブラウザで以下のようなシンプルな例が表示されます。これを編集することで,ansjsをWindowsで使う方法を説明します。

エディタ

HTMLとJavaScriptを編集するエディタを準備します。メモ帳でもかまいませんが,Visual Studio Code(VSCode)をインストールするとより便利です。VSCodeはSystem Installerでインストールしてください。

HTMLファイル編集

VSCode(またはメモ帳)を起動して,index.htmlをドラッグ&ドロップして開きます。「1から10までの和」を「1から5までの和」に書き換えて,[File]-[Save]で上書き保存します。

正解ファイル編集

次に,正解ファイルa.jsをVSCode(またはメモ帳)にドラッグ&ドロップして開き,55を15に書き換えます。[File]-[Save]で上書き保存します。

WSLのインストール

a.jsをエンコードするためにperlを使うので,WSLをインストールする必要があります。コマンド プロンプトを管理者モードで開き,wsl --installと打ってEnterして,指示に従ってインストールしてください。

エンコード

zipファイルを展開したフォルダにあるans.bat(⚙2つのアイコンのファイル)に,a.jsをドラッグ&ドロップします。エンコードされたファイルa64.jsが作成され,元のa64.jsが上書きされます。

以上で,HTMLの編集,正解の編集,エンコードの方法がわかったと思います。さらに,VSCodeに以下の設定をしておくと,VSCodeのメニューからエンコードができるようになります。

方法1 ans.batの登録

エンコードは,VSCodeの[Terminal]-[Configure tasks]に

{

    "label": "ans.bat",

    "type": "shell",

    "command": "ans.bat ${file}",

    "problemMatcher": []

},

以下のようなブロックを追加することで,a.jsを編集ながらメニュー[Terminal]-[Run Task...]で[ans.bat]を選ぶことで実行できるようになります。なお,ans.batは絶対パスで書いて下さい(c:/Users/ユーザ名/ans.batなど)。

方法2 ans.pl登録

VSCodeにWSL拡張機能をインストールします(インストールをクリックする)。インストールが終了したら,コマンドプロンプトで,wsl -u rootと打ってwslを起動して,続いてcodeと打ってVSCodeを起動して,WSL拡張を有効にします。VSCodeはすぐに終了します。

WindowsからVSCodeを起動し,[terminal]-[Configure Tasks...]で,tasks.jasonにブロック

{

  "label": "perl ans.pl",

  "type": "shell",

  "command": "perl ans.pl ${file}",

  "problemMatcher": [],

  "group": {

    "kind": "build",

    "isDefault": false

  }

},

を挿入します。ans.plはWSL形式の絶対パスで書いて下さい(/mnt/c/Users/ユーザ名/ans.plなど)。これで,VSCodeで正解ファイルを編集して,そのままメニュー[Terminal]-[Run Tasks]で実行できます。

設定したメニューを使うには:VSCodeを実行し,ウインドウ左端のRemote Explorerアイコンをクリックして,上部のREMOTE EXPLORERからWSL Targetsを選び,編集したいjsファイルをWSLから開いてください。