import type { MathProblem, Difficulty } from "../types"; import { randomInt, randomChoice } from "@/lib/utils"; import * as frac from "@/lib/math/fractions"; let counter = 0; function nextId() { return `fp-${++counter}-${Date.now()}`; } export function generateFractionAddSubtract(difficulty: Difficulty): MathProblem { const operation = randomChoice(["add", "subtract"] as const); const op = operation === "add" ? "+" : "-"; let n1: number, d1: number, n2: number, d2: number; if (difficulty === 1) { // Common denominators d1 = randomChoice([2, 3, 4, 5, 6, 8, 10, 12]); d2 = d1; n1 = randomInt(1, d1 - 1); n2 = operation === "subtract" ? randomInt(1, n1) : randomInt(1, d1 - n1); } else if (difficulty === 2) { // One denominator is a multiple of the other d1 = randomChoice([2, 3, 4, 5, 6]); const multiplier = randomChoice([2, 3]); d2 = d1 * multiplier; n1 = randomInt(1, d1 - 1); n2 = randomInt(1, d2 - 1); } else { // Unlike denominators d1 = randomChoice([3, 4, 5, 7, 8, 9]); d2 = randomChoice([3, 4, 5, 7, 8, 9].filter((d) => d !== d1)); n1 = randomInt(1, d1 - 1); n2 = randomInt(1, d2 - 1); } const [ansNum, ansDen] = operation === "add" ? frac.add(n1, d1, n2, d2) : frac.subtract(n1, d1, n2, d2); const prompt = `\\frac{${n1}}{${d1}} ${op} \\frac{${n2}}{${d2}}`; const commonDen = frac.lcm(d1, d2); const steps = d1 === d2 ? [ { explanation: "Denominators are the same, so just " + (operation === "add" ? "add" : "subtract") + " the numerators" }, { explanation: `${n1} ${op} ${n2} = ${operation === "add" ? n1 + n2 : n1 - n2}`, math: `\\frac{${operation === "add" ? n1 + n2 : n1 - n2}}{${d1}}` }, ] : [ { explanation: `Find the common denominator: LCM(${d1}, ${d2}) = ${commonDen}` }, { explanation: `Convert: ${n1}×${commonDen / d1}/${d1}×${commonDen / d1} and ${n2}×${commonDen / d2}/${d2}×${commonDen / d2}` }, { explanation: `${op === "+" ? "Add" : "Subtract"} numerators`, math: `\\frac{${ansNum}}{${ansDen}}` }, ]; return { id: nextId(), prompt, answer: { kind: "fraction", numerator: ansNum, denominator: ansDen }, hints: [ d1 === d2 ? "The denominators are already the same!" : "Find a common denominator first", d1 !== d2 ? `Try using the Butterfly Method: cross multiply` : `Just ${operation} the numerators`, ], steps, }; } export function generateFractionMultiply(difficulty: Difficulty): MathProblem { const denChoices = difficulty === 1 ? [2, 3, 4, 5] : difficulty === 2 ? [2, 3, 4, 5, 6, 7, 8] : [3, 5, 7, 9, 11, 12, 15]; const d1 = randomChoice(denChoices); const d2 = randomChoice(denChoices); const n1 = randomInt(1, d1 - 1); const n2 = randomInt(1, d2 - 1); const [ansNum, ansDen] = frac.multiply(n1, d1, n2, d2); return { id: nextId(), prompt: `\\frac{${n1}}{${d1}} \\times \\frac{${n2}}{${d2}}`, answer: { kind: "fraction", numerator: ansNum, denominator: ansDen }, hints: [ "Multiply numerator × numerator", "Multiply denominator × denominator", "Simplify if possible", ], steps: [ { explanation: `Multiply numerators: ${n1} × ${n2} = ${n1 * n2}` }, { explanation: `Multiply denominators: ${d1} × ${d2} = ${d1 * d2}` }, { explanation: "Simplify", math: `\\frac{${ansNum}}{${ansDen}}` }, ], }; } export function generateFractionDivide(difficulty: Difficulty): MathProblem { const denChoices = difficulty === 1 ? [2, 3, 4, 5] : difficulty === 2 ? [2, 3, 4, 5, 6, 7, 8] : [3, 5, 7, 9, 11, 14, 15]; const d1 = randomChoice(denChoices); const d2 = randomChoice(denChoices); const n1 = randomInt(1, d1 - 1); const n2 = randomInt(1, d2 - 1); const [ansNum, ansDen] = frac.divide(n1, d1, n2, d2); return { id: nextId(), prompt: `\\frac{${n1}}{${d1}} \\div \\frac{${n2}}{${d2}}`, answer: { kind: "fraction", numerator: ansNum, denominator: ansDen }, hints: [ "Keep the first fraction the same", "Flip the second fraction (reciprocal)", "Then multiply", ], steps: [ { explanation: `Keep ${n1}/${d1}, flip ${n2}/${d2} to ${d2}/${n2}` }, { explanation: `Multiply: ${n1}×${d2} / ${d1}×${n2}` }, { explanation: "Simplify", math: `\\frac{${ansNum}}{${ansDen}}` }, ], }; } export function generateFractionOfQuantity(difficulty: Difficulty): MathProblem { const denChoices = difficulty === 1 ? [2, 4, 5, 10] : difficulty === 2 ? [3, 4, 5, 6, 8] : [7, 8, 9, 12, 15]; const den = randomChoice(denChoices); const num = randomInt(1, den - 1); const multiplier = randomChoice(difficulty === 1 ? [2, 4, 5, 10] : [3, 6, 7, 8, 9, 12]); const quantity = den * multiplier; const answer = num * multiplier; return { id: nextId(), prompt: `\\frac{${num}}{${den}} \\text{ of } ${quantity}`, answer: { kind: "integer", value: answer }, hints: [ `Divide ${quantity} by ${den} first`, `Then multiply by ${num}`, ], steps: [ { explanation: `Divide the quantity by the denominator: ${quantity} ÷ ${den} = ${quantity / den}` }, { explanation: `Multiply by the numerator: ${quantity / den} × ${num} = ${answer}` }, ], }; } export function generateWholeFromFraction(difficulty: Difficulty): MathProblem { const denChoices = difficulty === 1 ? [2, 3, 4, 5] : difficulty === 2 ? [3, 5, 6, 8] : [7, 8, 9, 12]; const den = randomChoice(denChoices); const num = randomInt(1, den - 1); const whole = den * randomChoice(difficulty === 1 ? [2, 3, 4, 5] : [3, 5, 6, 7, 8, 10]); const part = (num / den) * whole; return { id: nextId(), prompt: `\\frac{${num}}{${den}} \\text{ of a number is } ${part}\\text{. Find the number.}`, answer: { kind: "integer", value: whole }, hints: [ `If ${num}/${den} of the number is ${part}...`, `Find 1/${den} first by dividing ${part} by ${num}`, `Then multiply by ${den} to get the whole`, ], steps: [ { explanation: `1/${den} of the number = ${part} ÷ ${num} = ${part / num}` }, { explanation: `The whole number = ${part / num} × ${den} = ${whole}` }, ], }; }