/*---------------------------------------- * soinsuu.js * Copyright (C) 2020 StraightApps.com, All Rights Reserved * September 8, 2020 初期版 * September 11, 2020 実用版 *-----------------------------------------*/ //---------------------------------------- // canvas の設定 // この部分は、id "canvas-calc" の定義後でないと、失敗します。 var canvas = document.getElementById('canvas-calc'); var w = document.documentElement.clientWidth; var h = 48; if (w > 480){ // 十分広い場合は w = 480; // 480 ピクセルまでとします } canvas.width = w; // canvas の幅設定 canvas.height = h; // canvas の高さ設定 //---------------------------------------- // コンテキストを取得 var ctx = canvas.getContext('2d'); //---------------------------------------- // 数値を右詰め表示するときの x 位置を決めます。 ctx.font = "36px 'ヒラギノ角ゴ Pro', 'Hiragino Kaku Gothic Pro', 'MS ゴシック', 'MS Gothic', sans-serif"; var x_num = 50 + ctx.measureText("0000000000").width; // 10桁ぶん用意 if (x_num > w){ // canvas 幅が不足の場合 canvas.width = x_num + 10; // canvas の幅を再設定します } //---------------------------------------- // 新しい問題を作成します。 makeNewNumber(); /*---------------------------------------- * メインループ *-----------------------------------------*/ function main() { //---------------------------------------- // canvas を指定の色で塗りつぶします。 ctx.fillStyle = "rgb( 230, 230, 230 )"; ctx.fillRect(0, 0, canvas.width, canvas.height); //---------------------------------------- // 途中計算式を canvas に描画します。 // ループごとに描画しなおす必要はなさそうですが。 var x; var y = 40; ctx.font = "36px 'ヒラギノ角ゴ Pro', 'Hiragino Kaku Gothic Pro', 'MS ゴシック', 'MS Gothic', sans-serif"; ctx.fillStyle = '#000'; // 黒文字で x = x_num - ctx.measureText( numOrg ).width; // 右端を x_num にあわせる ctx.fillText( numOrg, x, y ); // canvas 領域の座標(y座標は'下'を指している) y += 40; var numTmp = numOrg; // 途中経過の表示用 for ( var i = 1; i < inp.length; i++ ){ numTmp /= inp[i]; if (numTmp > 1){ // 割ったあと1になるなら表示しません ctx.fillStyle = '#F00'; // 赤文字で x = 50 - ctx.measureText( inp[i] ).width; // 右端を 50 にあわせる ctx.fillText(inp[i], x, y - 40); // 1行上に表示 ctx.fillStyle = '#000'; // 黒文字で ctx.fillText(')', 55, y - 40); // 1行上に表示すべき ctx.fillRect(55, y - 40 + 2, x_num - 55 + 10, 2); // ラインを引く x = x_num - ctx.measureText( numTmp ).width; // 右端を x_num にあわせる ctx.fillText( numTmp, x, y); // クライアント領域の座標(y座標は'下'を指しているよう) } y += 40; } requestAnimationFrame( main ); } /*---------------------------------------- * ページと、依存している全てのデータが読み込まれたら、 * メインループを開始します。 *-----------------------------------------*/ addEventListener('load', main(), false); /*---------------------------------------- * 新しい問題の作成 *-----------------------------------------*/ function makeNewNumber() { // オブジェクト pow は、グローバルに、以下のように定義されています。 // var pow = new Object(); pow.n2 = Math.floor(Math.random() * 6); // 2の0乗〜5乗までを適当に決める pow.n3 = Math.floor(Math.random() * 5); // 3は4乗まで pow.n5 = Math.floor(Math.random() * 4); // 5は3乗まで pow.n7 = Math.floor(Math.random() * 3); // 7は2乗まで pow.n11 = Math.floor(Math.random() * 3); // 11は2乗まで pow.n13 = Math.floor(Math.random() * 2); // 13は1乗まで // ランダムに決めていますが、大きいほうから決めて、回数多すぎにならないよう制限すべきかもしれません。 if (Math.random() < 0.5){ // 例えば、11 と 13 は出すぎると面白くない pow.n11 = 0; pow.n13 = 0; } if (pow.n11 > 0){ // 例えば、11 が使われているなら pow.n13 = 0; // 13 は同時に使わない。 } // 変数 num は、グローバルに、以下のように定義されています。 // var num = 1; num = 1; num *= Math.pow(2, pow.n2); num *= Math.pow(3, pow.n3); num *= Math.pow(5, pow.n5); num *= Math.pow(7, pow.n7); num *= Math.pow(11, pow.n11); num *= Math.pow(13, pow.n13); // 元の値を残しておきます。 numOrg = num; // プレーヤーの回答をクリアします。 ans.n2 = 0; ans.n3 = 0; ans.n5 = 0; ans.n7 = 0; ans.n11 = 0; ans.n13 = 0; // 素因数分解されるべき値を、id "left-value" に表示します。 updateValue(); // 回答途中の式を id "answering" に表示します。 updateAnsweringArea(true); // 入力履歴配列をクリアします。 inp.length = 1; inp[0] = 0; // 計算途中表示の canvas のサイズを決定します。 canvas.height = inp.length * 40 + 15; // canvas の幅を再設定 } /*---------------------------------------- * 数字ボタンが押されたときの処理 * value は、押されたボタンの値 *-----------------------------------------*/ function numPressed(value) { var n1 = num / value; // 普通に割った数(実数) var n2 = Math.floor(num / value); // 小数部を切り捨て(正の場合) if (n1 != n2){ return; // 割り切れない } // num を、割ったあとの値に更新します。 num /= value; // 押されたボタンにより、記録や履歴を残します。 if (value == 2){ ans.n2 ++; // 乗数を加算 } else if (value == 3){ ans.n3 ++; } else if (value == 5){ ans.n5 ++; } else if (value == 7){ ans.n7 ++; } else if (value == 11){ ans.n7 ++; } else if (value == 13){ ans.n13 ++; } // 履歴を1つ増やします。 inp.length ++; inp[ inp.length - 1 ] = value; // 素因数分解されるべき値 id "left-value" を更新します。 updateValue(); // 回答途中の式 id "answering" を更新します。 updateAnsweringArea(false); // canvas のサイズを決定します(大きくします)。 if (num > 1){ canvas.height = inp.length * 40 + 15; // canvasの縦幅を再設定 } else{ canvas.height = inp.length * 40 + 15 - 40; // canvasの縦幅を再設定 } } /*---------------------------------------- * 素因数分解されるべき値を表示します。 * id 'left-value' 領域を書き換えます。 *-----------------------------------------*/ function updateValue() { var data = '

' + numOrg + ' を、下の素数ボタンを押して、素因数分解せよ!

'; var elem = document.getElementById('left-value'); data += num; data += ' は、何で割り切れるかな?

'; // 正解は自動判定します。 if (num == 1){ data = '

素因数分解 完了! おめでとう!

' } elem.innerHTML= data; } /*---------------------------------------- * 回答中の数式を出力します。 * id 'answering' 領域を書き換えます。 *-----------------------------------------*/ function updateAnsweringArea(init) { var data = '

'; var elem = document.getElementById('answering'); // 問題作成直後の場合 if (init == true){ data += 'ここに回答途中の式が表示されます。

'; elem.innerHTML= data; return; } var first = true; // 正解は自動判定します。 if (num == 1){ data += numOrg + 'を素因数分解した式は '; } else{ data += 'できた式は '; } if (ans.n2 > 0){ data += addString( 2, ans.n2, first ); first = false; } if (ans.n3 > 0){ data += addString( 3, ans.n3, first ); first = false; } if (ans.n5 > 0){ data += addString( 5, ans.n5, first ); first = false; } if (ans.n7 > 0){ data += addString( 7, ans.n7, first ); first = false; } if (ans.n11 > 0){ data += addString( 11, ans.n11, first ); first = false; } if (ans.n13 > 0){ data += addString( 13, ans.n13, first ); first = false; } data += '

'; elem.innerHTML= data; return /*data*/; } /*---------------------------------------- * 回答中の数式の1要素の出力形式を返します。 * その項があるとして(pow > 0)文字列を作成します。 * 追加されるべき文字列を返します。 * 引数は参照渡しとなることを確認しました。 *-----------------------------------------*/ function addString( value, pow, first ) { var str = value; if (first != true){ str = '×' + value; } if (pow > 1){ str += '' + pow + ''; } return str; }