111 lines
3.9 KiB
TypeScript
111 lines
3.9 KiB
TypeScript
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}` },
|
||
],
|
||
};
|
||
}
|