137 lines
5.1 KiB
TypeScript
137 lines
5.1 KiB
TypeScript
import type { MathProblem, Difficulty } from "../types";
|
||
import { randomInt, randomChoice } from "@/lib/utils";
|
||
|
||
let counter = 0;
|
||
function nextId() {
|
||
return `np-${++counter}-${Date.now()}`;
|
||
}
|
||
|
||
export function generateIdentityInverse(difficulty: Difficulty): MathProblem {
|
||
const kind = randomChoice(
|
||
difficulty === 1
|
||
? (["identity-add", "zero", "inverse-add"] as const)
|
||
: (["identity-add", "identity-mul", "zero", "inverse-add"] as const),
|
||
);
|
||
|
||
if (kind === "identity-add") {
|
||
const n = randomInt(-20, 20);
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${n} + 0`,
|
||
answer: { kind: "integer", value: n },
|
||
hints: ["0 is the identity for addition.", "Adding 0 changes nothing."],
|
||
steps: [{ explanation: "Adding the identity 0 leaves the number unchanged.", math: `${n} + 0 = ${n}` }],
|
||
};
|
||
}
|
||
|
||
if (kind === "identity-mul") {
|
||
const n = randomInt(-20, 20);
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${n} \\times 1`,
|
||
answer: { kind: "integer", value: n },
|
||
hints: ["1 is the identity for multiplication.", "Multiplying by 1 changes nothing."],
|
||
steps: [{ explanation: "Multiplying by the identity 1 leaves the number unchanged.", math: `${n} \\times 1 = ${n}` }],
|
||
};
|
||
}
|
||
|
||
if (kind === "zero") {
|
||
const n = randomInt(1, 30);
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${n} \\times 0`,
|
||
answer: { kind: "integer", value: 0 },
|
||
hints: ["Anything multiplied by zero is zero."],
|
||
steps: [{ explanation: "Any number times zero is zero.", math: `${n} \\times 0 = 0` }],
|
||
};
|
||
}
|
||
|
||
// inverse-add: additive inverse
|
||
const n = randomInt(-20, 20) || 5;
|
||
return {
|
||
id: nextId(),
|
||
prompt: `\\text{The additive inverse of } ${n} \\text{ is?}`,
|
||
answer: { kind: "integer", value: -n },
|
||
hints: ["The additive inverse adds up to 0.", "Flip the sign."],
|
||
steps: [{ explanation: "The additive inverse flips the sign so the sum is 0.", math: `${n} + (${-n}) = 0` }],
|
||
};
|
||
}
|
||
|
||
export function generateExponentEvaluate(difficulty: Difficulty): MathProblem {
|
||
if (difficulty === 3) {
|
||
// index law: find the resulting exponent
|
||
const base = randomInt(2, 6);
|
||
const op = randomChoice(["\\times", "\\div"] as const);
|
||
if (op === "\\times") {
|
||
const m = randomInt(1, 5);
|
||
const n = randomInt(1, 5);
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${base}^{${m}} \\times ${base}^{${n}} = ${base}^{x}`,
|
||
answer: { kind: "integer", value: m + n },
|
||
hints: ["Same base, multiplying → add the powers.", `${m} + ${n} = ?`],
|
||
steps: [{ explanation: "When multiplying powers of the same base, add the exponents.", math: `${base}^{${m}} \\times ${base}^{${n}} = ${base}^{${m + n}}` }],
|
||
};
|
||
}
|
||
const m = randomInt(3, 7);
|
||
const n = randomInt(1, m - 1);
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${base}^{${m}} \\div ${base}^{${n}} = ${base}^{x}`,
|
||
answer: { kind: "integer", value: m - n },
|
||
hints: ["Same base, dividing → subtract the powers.", `${m} - ${n} = ?`],
|
||
steps: [{ explanation: "When dividing powers of the same base, subtract the exponents.", math: `${base}^{${m}} \\div ${base}^{${n}} = ${base}^{${m - n}}` }],
|
||
};
|
||
}
|
||
|
||
if (difficulty === 2 && Math.random() < 0.5) {
|
||
// difference of two powers, e.g. 2^3 - 2^1
|
||
const base = randomInt(2, 4);
|
||
const a = randomInt(2, 3);
|
||
const b = 1;
|
||
const value = Math.pow(base, a) - Math.pow(base, b);
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${base}^{${a}} - ${base}^{${b}}`,
|
||
answer: { kind: "integer", value },
|
||
hints: [`${base}^${a} = ${Math.pow(base, a)}`, `${base}^${b} = ${Math.pow(base, b)}`],
|
||
steps: [{ explanation: "Work out each power, then subtract.", math: `${Math.pow(base, a)} - ${Math.pow(base, b)} = ${value}` }],
|
||
};
|
||
}
|
||
|
||
// evaluate a single power (includes n^0 and n^1)
|
||
const base = randomInt(2, difficulty === 1 ? 6 : 9);
|
||
const exp = difficulty === 1 ? randomChoice([0, 1, 2, 2, 3]) : randomChoice([0, 1, 2, 3]);
|
||
const value = Math.pow(base, exp);
|
||
const note = exp === 0 ? "Any number to the power 0 is 1." : exp === 1 ? "Any number to the power 1 is itself." : `Multiply ${base} by itself ${exp} times.`;
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${base}^{${exp}}`,
|
||
answer: { kind: "integer", value },
|
||
hints: [note],
|
||
steps: [{ explanation: note, math: `${base}^{${exp}} = ${value}` }],
|
||
};
|
||
}
|
||
|
||
export function generateDistributive(difficulty: Difficulty): MathProblem {
|
||
const a = randomInt(2, difficulty === 1 ? 6 : 9);
|
||
const b = randomInt(1, difficulty === 1 ? 6 : 9);
|
||
const c = randomInt(1, difficulty === 1 ? 6 : 9);
|
||
const value = a * (b + c);
|
||
return {
|
||
id: nextId(),
|
||
prompt: `${a} \\times (${b} + ${c})`,
|
||
answer: { kind: "integer", value },
|
||
hints: [
|
||
"Add inside the bracket first, then multiply.",
|
||
"Or multiply the outside number by each number inside.",
|
||
`${a} × ${b} + ${a} × ${c}`,
|
||
],
|
||
steps: [
|
||
{ explanation: `Add inside the bracket: ${b} + ${c} = ${b + c}` },
|
||
{ explanation: `Multiply: ${a} × ${b + c} = ${value}` },
|
||
{ explanation: `Check by distributing: ${a * b} + ${a * c} = ${value}` },
|
||
],
|
||
};
|
||
}
|