Initial Commit

This commit is contained in:
2026-03-01 18:50:29 -04:00
parent 261c52d602
commit 364facd9f0
69 changed files with 7829 additions and 87 deletions

View File

@@ -0,0 +1,110 @@
import type { MathProblem, Difficulty } from "../types";
import { randomInt, randomChoice } from "@/lib/utils";
import { simplifyRatio, divideInRatio } from "@/lib/math/ratios";
let counter = 0;
function nextId() {
return `rp-${++counter}-${Date.now()}`;
}
export function generateSimplifyRatio(difficulty: Difficulty): MathProblem {
const gcd = randomChoice(difficulty === 1 ? [2, 3, 4, 5] : difficulty === 2 ? [3, 4, 5, 6, 7] : [4, 6, 8, 9, 12]);
const a = randomInt(1, difficulty === 1 ? 5 : 10) * gcd;
const b = randomInt(1, difficulty === 1 ? 5 : 10) * gcd;
const simplified = simplifyRatio([a, b]);
return {
id: nextId(),
prompt: `\\text{Simplify the ratio } ${a}:${b}`,
answer: { kind: "ratio", parts: simplified },
hints: [
`Find the GCD of ${a} and ${b}`,
`The GCD is ${gcd}`,
`Divide both parts by ${gcd}`,
],
steps: [
{ explanation: `GCD of ${a} and ${b} is ${gcd}` },
{ explanation: `${a} ÷ ${gcd} = ${simplified[0]}, ${b} ÷ ${gcd} = ${simplified[1]}` },
{ explanation: `Simplified: ${simplified.join(":")}` },
],
};
}
export function generateDivideInRatio(difficulty: Difficulty): MathProblem {
const numParts = difficulty === 3 ? 3 : 2;
const parts: number[] = [];
for (let i = 0; i < numParts; i++) {
parts.push(randomInt(1, difficulty === 1 ? 5 : 9));
}
const sum = parts.reduce((a, b) => a + b, 0);
const multiplier = randomChoice(difficulty === 1 ? [2, 3, 4, 5] : [3, 4, 5, 6, 7, 8]);
const total = sum * multiplier;
const values = divideInRatio(total, parts);
const intValues = values.map(Math.round);
const names = ["first share", "second share", "third share"];
return {
id: nextId(),
prompt: `\\text{Share } ${total} \\text{ in the ratio } ${parts.join(":")}`,
answer: { kind: "ratio", parts: intValues },
hints: [
`Total parts: ${parts.join(" + ")} = ${sum}`,
`One part = ${total} ÷ ${sum} = ${multiplier}`,
`Multiply each ratio number by ${multiplier}`,
],
steps: [
{ explanation: `Total parts = ${parts.join(" + ")} = ${sum}` },
{ explanation: `One part = ${total} ÷ ${sum} = ${multiplier}` },
...parts.map((p, i) => ({
explanation: `${names[i]}: ${p} × ${multiplier} = ${intValues[i]}`,
})),
],
};
}
export function generateRatioWordProblem(difficulty: Difficulty): MathProblem {
const a = randomInt(2, 7);
const b = randomInt(2, 7);
const diff = Math.abs(a - b);
if (diff === 0) {
return generateDivideInRatio(difficulty);
}
const contexts = [
{ item: "sweets", nameA: "Josh", nameB: "Nathan" },
{ item: "marbles", nameA: "Amy", nameB: "Ben" },
{ item: "stickers", nameA: "Karen", nameB: "Natasha" },
];
const ctx = randomChoice(contexts);
const onePart = randomChoice(difficulty === 1 ? [5, 10, 12] : [6, 8, 9, 15, 20]);
const extraAmount = diff * onePart;
const totalParts = a + b;
const total = totalParts * onePart;
const bigger = a > b ? ctx.nameA : ctx.nameB;
const biggerRatio = Math.max(a, b);
const smallerRatio = Math.min(a, b);
return {
id: nextId(),
prompt: `\\text{${ctx.item.charAt(0).toUpperCase() + ctx.item.slice(1)} were shared between ${ctx.nameA} and ${ctx.nameB} in the ratio ${a}:${b}. If ${bigger} received ${extraAmount} more ${ctx.item}, find the total shared.}`,
answer: { kind: "integer", value: total },
hints: [
`The difference in ratio parts is ${biggerRatio} - ${smallerRatio} = ${diff}`,
`${diff} parts = ${extraAmount}, so 1 part = ${onePart}`,
`Total parts = ${a} + ${b} = ${totalParts}`,
],
steps: [
{ explanation: `Difference in parts: ${biggerRatio} - ${smallerRatio} = ${diff}` },
{ explanation: `${diff} parts = ${extraAmount}, so 1 part = ${extraAmount} ÷ ${diff} = ${onePart}` },
{ explanation: `Total parts: ${a} + ${b} = ${totalParts}` },
{ explanation: `Total ${ctx.item}: ${totalParts} × ${onePart} = ${total}` },
],
};
}