0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

計算ドリル

Posted at

See the Pen Untitled by matsunaga kosuke (@matsunaga-kosuke) on CodePen.

参考サイト

p5.js

index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <!-- PLEASE NO CHANGES BELOW THIS LINE (UNTIL I SAY SO) -->
  <script language="javascript" type="text/javascript" src="libraries/p5.min.js"></script>
  <script language="javascript" type="text/javascript" src="sketch_251102b.js"></script>
  <!-- OK, YOU CAN MAKE CHANGES BELOW THIS LINE AGAIN -->

  <style>
    body {
      padding: 0;
      margin: 0;
    }
  </style>
</head>

<body>
</body>
</html>
sketch_251102b.js
// p5.js 計算ドリル
// マウスで5択から選ぶ
// 出題種別:
// 0: 500以下の3桁 × 30未満の2桁
// 1: 4桁 + 4桁
// 2: 2桁 × 2桁
// 3: 2桁 × 1桁 覆面算(□に入る1けた)
// 4: 4桁 ÷ 2桁(割り切れる)
// 5: 1桁 − 小数3桁(負にならない)
// 6: 4桁の覆面算の計算(4桁+4桁の答えの1けたが□)

let problemText = "";
let choices = [];   // {label, value, x,y,w,h}
let correctValue = "";
let message = "";
let problemType = 0;

function setup() {
  createCanvas(720, 480);
  textFont("sans-serif");
  textSize(20);
  newProblem();
}

function draw() {
  background(245);
  fill(0);
  textSize(22);
  text("p5.js 計算ドリル", 20, 30);
  textSize(18);
  text(problemText, 20, 90, width - 40, 200);

  // 選択肢を描画
  for (let i = 0; i < choices.length; i++) {
    let c = choices[i];
    stroke(0);
    strokeWeight(1);
    fill(255);
    rect(c.x, c.y, c.w, c.h, 8);
    fill(0);
    textAlign(CENTER, CENTER);
    text(c.label, c.x + c.w / 2, c.y + c.h / 2);
  }

  // メッセージ
  textAlign(LEFT, BASELINE);
  fill(0);
  textSize(18);
  text(message, 20, height - 40);
}

function mousePressed() {
  for (let i = 0; i < choices.length; i++) {
    let c = choices[i];
    if (
      mouseX > c.x && mouseX < c.x + c.w &&
      mouseY > c.y && mouseY < c.y + c.h
    ) {
      checkAnswer(c.value);
      break;
    }
  }
}

function checkAnswer(val) {
  if (val === correctValue) {
    message = "◎ せいかい! もう1問だすね。(クリックで次)";
  } else {
    message = "× ざんねん… せいかいは「" + correctValue + "」だよ。(クリックで次)";
  }
  // 次の問題をすぐ出すならここで呼ぶ
  // 1クリックで答えを見て、さらにクリックで次にしたいなら、
  // ここではフラグにしてもいい。簡単に今回はすぐ次にする。
  setTimeout(newProblem, 3000); // 0.8秒で次
}

function newProblem() {
  message = "";
  choices = [];
  // 問題タイプをランダムに
  problemType = int(random(0, 7));
  switch (problemType) {
    case 0:
      genMul3digitUnder500x2digitUnder30();
      break;
    case 1:
      genAdd4digit4digit();
      break;
    case 2:
      genMul2digit2digit();
      break;
    case 3:
      genMasked2digitTimes1digit();
      break;
    case 4:
      genDiv4digitBy2digit();
      break;
    case 5:
      gen1digitMinusDecimal3();
      break;
    case 6:
      genMasked4digitCalc();
      break;
  }
  layoutChoices();
}

// 0: 500以下の3桁 × 30未満の2桁
function genMul3digitUnder500x2digitUnder30() {
  let a = int(random(100, 501));  // 100〜500
  let b = int(random(10, 30));    // 10〜29
  let ans = a * b;
  problemText = a + " × " + b + " を計算しなさい。";
  correctValue = str(ans);
  let wrongs = makeNearNumbers(ans, 4, 0.05); // ±5%くらいで
  buildChoices(correctValue, wrongs);
}

// 1: 4桁 + 4桁
function genAdd4digit4digit() {
  let a = int(random(1000, 10000));
  let b = int(random(1000, 10000));
  let ans = a + b;
  problemText = a + "" + b + " を計算しなさい。";
  correctValue = str(ans);
  let wrongs = makeNearNumbers(ans, 4, 0.03);
  buildChoices(correctValue, wrongs);
}

// 2: 2桁 × 2桁
function genMul2digit2digit() {
  let a = int(random(10, 100));
  let b = int(random(10, 100));
  let ans = a * b;
  problemText = a + " × " + b + " を計算しなさい。";
  correctValue = str(ans);
  let wrongs = makeNearNumbers(ans, 4, 0.08);
  buildChoices(correctValue, wrongs);
}

// 3: 2桁 × 1桁 覆面算(□に入る1けた)
function genMasked2digitTimes1digit() {
  let x = int(random(10, 100));   // 2桁
  let y = int(random(2, 10));     // 1桁
  let prod = x * y;
  let xStr = str(x);
  // 2桁のうちどちらかを□に
  let idx = int(random(0, 2)); // 0:十のくらい, 1:一のくらい
  let missingDigit = xStr.charAt(idx);
  let shownX =
    (idx === 0 ? "" + xStr.charAt(1) : xStr.charAt(0) + "");
  problemText = shownX + " × " + y + "" + prod + " □に入る数はどれですか。";
  correctValue = missingDigit;  // 0〜9の1文字
  let wrongs = makeOtherDigits(missingDigit, 4);
  buildChoices(correctValue, wrongs);
}

// 4: 4桁 ÷ 2桁(割り切れる)
function genDiv4digitBy2digit() {
  // 2桁のわり算で4桁になるように作る
  // divisor: 10〜99
  // quotient: 10〜99
  // dividend = divisor * quotient
  let divisor, quotient, dividend;
  while (true) {
    divisor = int(random(10, 100));
    quotient = int(random(10, 100));
    dividend = divisor * quotient;
    if (dividend >= 1000 && dividend <= 9999) break;
  }
  problemText = dividend + " ÷ " + divisor + " を計算しなさい。";
  correctValue = str(quotient);
  let wrongs = makeNearNumbers(quotient, 4, 0.3, true); // ±30%で
  buildChoices(correctValue, wrongs);
}

// 5: 1桁 − 小数3桁(負にならない)
function gen1digitMinusDecimal3() {
  let a = int(random(1, 10)); // 1〜9
  // bは0.001〜a.000くらいで3桁
  let b = int(random(1, a * 1000 + 1)) / 1000.0;
  let ans = a - b;
  ans = float(ans.toFixed(3));
  problemText = a + "" + b.toFixed(3) + " を計算しなさい。(小数第3位まで)";
  correctValue = ans.toFixed(3);
  let wrongs = makeDecimalNear(ans, 4, 0.02); // ±0.02程度
  buildChoices(correctValue, wrongs, true);
}

// 6: 4桁の覆面算の計算(4桁+4桁の答えの1けたが□)
function genMasked4digitCalc() {
  let a = int(random(1000, 10000));
  let b = int(random(1000, 10000));
  let sum = a + b;
  let sumStr = str(sum);
  // どこか1けたを□に
  let idx = int(random(0, sumStr.length));
  let missing = sumStr.charAt(idx);
  let shown = "";
  for (let i = 0; i < sumStr.length; i++) {
    if (i === idx) shown += "";
    else shown += sumStr.charAt(i);
  }
  problemText = a + "" + b + "" + shown + " □に入る数はどれですか。";
  correctValue = missing;
  let wrongs = makeOtherDigits(missing, 4);
  buildChoices(correctValue, wrongs);
}

// =============================
// 選択肢ユーティリティ
// =============================
function buildChoices(correct, wrongArray) {
  // 正解を入れてからシャッフル
  let temp = [correct].concat(wrongArray);
  temp = shuffle(temp);
  choices = [];
  // レイアウトは2列×3行ぶんのうち5コ
  let startX = 60;
  let startY = 180;
  let w = 240;
  let h = 50;
  for (let i = 0; i < temp.length; i++) {
    let col = i % 2;
    let row = int(i / 2);
    let x = startX + col * (w + 30);
    let y = startY + row * (h + 15);
    choices.push({
      label: temp[i],
      value: temp[i],
      x: x,
      y: y,
      w: w,
      h: h
    });
  }
}

function layoutChoices() {
  // すでにbuildChoicesでレイアウト済み
}

// 近い数値のダミーをつくる(整数)
function makeNearNumbers(ans, count, rate, positiveOnly = false) {
  let arr = [];
  let tries = 0;
  while (arr.length < count && tries < 100) {
    tries++;
    let delta = int(ans * rate);
    if (delta < 1) delta = 1;
    let cand = ans + int(random(-delta, delta + 1));
    if (cand === ans) continue;
    if (positiveOnly && cand <= 0) continue;
    if (!arr.includes(str(cand))) {
      arr.push(str(cand));
    }
  }
  // 足りないときは適当に足す
  while (arr.length < count) {
    let cand = ans + int(random(1, 10));
    if (!arr.includes(str(cand))) arr.push(str(cand));
  }
  return arr;
}

// 小数のダミー
function makeDecimalNear(ans, count, width) {
  let arr = [];
  let tries = 0;
  while (arr.length < count && tries < 200) {
    tries++;
    let cand = ans + random(-width, width);
    cand = float(cand.toFixed(3));
    if (cand === ans) continue;
    if (cand < 0) continue;
    let cstr = cand.toFixed(3);
    if (!arr.includes(cstr)) arr.push(cstr);
  }
  while (arr.length < count) {
    let cand = ans + random(0.001, 0.010);
    let cstr = cand.toFixed(3);
    if (!arr.includes(cstr)) arr.push(cstr);
  }
  return arr;
}

// ある数字(digit)以外の0〜9からダミーをつくる
function makeOtherDigits(digit, count) {
  let arr = [];
  for (let d = 0; d <= 9; d++) {
    if (str(d) === str(digit)) continue;
    arr.push(str(d));
  }
  arr = shuffle(arr);
  return arr.slice(0, count);
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?