Dev.to WebDev 🛠 Dev 👁 0 📖 3 min read

Generating Printable Math Worksheets in JavaScript: Seeded Randomness, Constraints and Answer Keys

"Just generate 20 random addition problems" sounds like a five-minute job. Then a teacher asks for problems with regrouping only, a parent wants to reprint the exact same sheet next week, and someone notices the answer k

"Just generate 20 random addition problems" sounds like a five-minute job. Then a teacher asks for problems with regrouping only, a parent wants to reprint the exact same sheet next week, and someone notices the answer key doesn't match after a refresh.

DWorksheets is a free generator for printable math worksheets (kindergarten through 6th grade), handwriting tracing sheets and quizzes. Here's the approach behind generating worksheets that are actually usable in a classroom.

1. Use a seeded PRNG, not Math.random()

Math.random() can't be reproduced. A seeded generator means the same seed always produces the same worksheet — so a sheet can be shared by URL, reprinted later, and its answer key always matches.

// mulberry32: small, fast, deterministic
function mulberry32(seed) {
  return function () {
    seed |= 0; seed = (seed + 0x6d2b79f5) | 0;
    let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

const randInt = (rng, min, max) => min + Math.floor(rng() * (max - min + 1));

Put the seed in the URL (?seed=48213) and "print again next week" just works.

2. Generate against constraints, not just ranges

Teachers care about what kind of practice a problem gives. "Two-digit addition with regrouping" means at least one column must carry. A constraint check handles that:

function needsRegrouping(a, b) {
  while (a > 0 || b > 0) {
    if ((a % 10) + (b % 10) >= 10) return true;
    a = Math.floor(a / 10); b = Math.floor(b / 10);
  }
  return false;
}

function additionProblem(rng, { digits = 2, regrouping = "any" }) {
  const min = 10 ** (digits - 1), max = 10 ** digits - 1;
  for (let tries = 0; tries < 1000; tries++) {
    const a = randInt(rng, min, max), b = randInt(rng, min, max);
    const r = needsRegrouping(a, b);
    if (regrouping === "any" || (regrouping === "only") === r) return { a, b, answer: a + b };
  }
  throw new Error("constraints too strict");
}

The same pattern covers subtraction without negative answers, multiplication tables for a specific factor (e.g. grade 3 vs grade 4 multiplication), or division with no remainder.

3. Avoid duplicates and trivial problems

Twenty problems where three are "10 + 10" looks lazy. Keep a set of seen problems (normalizing commutative pairs), and filter out trivial ones like × 1 or + 0 unless the level calls for them:

function uniqueProblems(rng, n, make) {
  const seen = new Set(), out = [];
  while (out.length < n) {
    const p = make(rng);
    const key = [p.a, p.b].sort((x, y) => x - y).join("+");
    if (!seen.has(key)) { seen.add(key); out.push(p); }
  }
  return out;
}

4. Map grade levels to presets

Parents and teachers think in grades, not parameters. A preset table turns "2nd Grade Math" into concrete settings while still letting people tweak them:

const presets = {
  "kindergarten": { op: "+", digits: 1, max: 10 },
  "grade-2": { op: "+", digits: 2, regrouping: "any" },
  "grade-3-multiplication": { op: "×", factors: [2, 10] },
  "grade-4-multiplication": { op: "×", digits: [2, 1] },
};

Each preset also gets its own landing page, so someone searching for "3rd grade multiplication worksheets" lands on a ready-to-print sheet.

5. Answer keys are a separate page

The answer key is generated from the same problem list and printed on its own page, so teachers can hand out the worksheet and keep the key:

@media print {
  .no-print { display: none; }
  .worksheet { break-after: page; }
  .problem { break-inside: avoid; }
}

6. No accounts

Everything is free, unlimited and works without a login or credit card. Because worksheets are deterministic from their settings and seed, there's nothing that needs to be saved server-side.

Takeaways

  • Seeded randomness makes worksheets shareable and reprintable.
  • Encode pedagogy (regrouping, no negatives, no remainders) as constraints.
  • De-duplicate and filter trivial problems.
  • Use grade presets as the human interface to parameters.

Make a sheet at dworksheets.com. If you've built generators for educational content, I'd like to hear how you handled difficulty levels.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.