"use client"; import { useState, useCallback } from "react"; import { Card } from "@/components/ui/card"; import { StepControls } from "./step-controls"; type DecOp = "add" | "subtract" | "multiply" | "divide"; interface Step { label: string; columns: ColumnDisplay[]; carry?: string; resultRow?: string; } interface ColumnDisplay { rows: string[]; highlight?: number; // which row is highlighted separator?: boolean; // line above this row } function padAndAlign(a: string, b: string): { aStr: string; bStr: string; dotPos: number } { const aParts = a.split("."); const bParts = b.split("."); const aInt = aParts[0] || "0"; const bInt = bParts[0] || "0"; const aDec = aParts[1] || ""; const bDec = bParts[1] || ""; const maxInt = Math.max(aInt.length, bInt.length); const maxDec = Math.max(aDec.length, bDec.length); const aAligned = aInt.padStart(maxInt, " ") + (maxDec > 0 ? "." + aDec.padEnd(maxDec, "0") : ""); const bAligned = bInt.padStart(maxInt, " ") + (maxDec > 0 ? "." + bDec.padEnd(maxDec, "0") : ""); return { aStr: aAligned, bStr: bAligned, dotPos: maxInt }; } function buildAddSubSteps(a: number, b: number, op: DecOp): Step[] { const steps: Step[] = []; const aStr = a.toString(); const bStr = b.toString(); const { aStr: aAligned, bStr: bAligned } = padAndAlign(aStr, bStr); const opSymbol = op === "add" ? "+" : "−"; const result = op === "add" ? a + b : a - b; const resultStr = parseFloat(result.toFixed(10)).toString(); // Step 0: Show the problem steps.push({ label: `${aStr} ${opSymbol} ${bStr}`, columns: [], }); // Step 1: Align decimal points steps.push({ label: "Align the decimal points", columns: [ { rows: [aAligned, `${opSymbol} ${bAligned}`] }, ], }); // Step 2: Add trailing zeros steps.push({ label: "Fill in zeros as placeholders", columns: [ { rows: [aAligned, `${opSymbol} ${bAligned}`], separator: true }, ], }); // Step 3: Compute const { aStr: aFinal, bStr: bFinal } = padAndAlign(aStr, bStr); const resultAligned = padAndAlign(resultStr, aStr).aStr; steps.push({ label: `Compute column by column`, columns: [ { rows: [aFinal, `${opSymbol} ${bFinal}`, resultAligned], separator: true, highlight: 2 }, ], }); // Step 4: Result steps.push({ label: `${aStr} ${opSymbol} ${bStr} = ${resultStr}`, columns: [ { rows: [aFinal, `${opSymbol} ${bFinal}`, resultAligned], separator: true, highlight: 2 }, ], resultRow: resultStr, }); return steps; } function buildMultiplySteps(a: number, b: number): Step[] { const steps: Step[] = []; const aStr = a.toString(); const bStr = b.toString(); const aDec = (aStr.split(".")[1] || "").length; const bDec = (bStr.split(".")[1] || "").length; const totalDec = aDec + bDec; // Remove decimals for integer multiplication const aInt = Math.round(a * Math.pow(10, aDec)); const bInt = Math.round(b * Math.pow(10, bDec)); const result = a * b; const resultStr = parseFloat(result.toFixed(10)).toString(); steps.push({ label: `${aStr} × ${bStr}`, columns: [], }); if (totalDec > 0) { steps.push({ label: `Count decimal places: ${aDec} + ${bDec} = ${totalDec}`, columns: [ { rows: [`${aStr} → ${aDec} d.p.`, `${bStr} → ${bDec} d.p.`, `Total: ${totalDec} d.p.`] }, ], }); steps.push({ label: `Multiply as whole numbers: ${aInt} × ${bInt}`, columns: [ { rows: [`${aInt}`, `× ${bInt}`, `${aInt * bInt}`], separator: true, highlight: 2 }, ], }); steps.push({ label: `Place decimal point ${totalDec} place${totalDec !== 1 ? "s" : ""} from the right`, columns: [ { rows: [`${aInt * bInt}`, `→ ${resultStr}`], highlight: 1 }, ], resultRow: resultStr, }); } else { const intResult = a * b; steps.push({ label: `Multiply: ${aStr} × ${bStr} = ${intResult}`, columns: [ { rows: [`${aStr}`, `× ${bStr}`, `${intResult}`], separator: true, highlight: 2 }, ], resultRow: intResult.toString(), }); } return steps; } function buildDivideSteps(a: number, b: number): Step[] { const steps: Step[] = []; const aStr = a.toString(); const bStr = b.toString(); const result = a / b; const resultStr = parseFloat(result.toFixed(10)).toString(); steps.push({ label: `${aStr} ÷ ${bStr}`, columns: [], }); // Make divisor a whole number const bDec = (bStr.split(".")[1] || "").length; if (bDec > 0) { const factor = Math.pow(10, bDec); const newA = parseFloat((a * factor).toFixed(10)); const newB = parseFloat((b * factor).toFixed(10)); steps.push({ label: `Make divisor whole: multiply both by ${factor}`, columns: [ { rows: [`${aStr} × ${factor} = ${newA}`, `${bStr} × ${factor} = ${newB}`] }, ], }); steps.push({ label: `Now divide: ${newA} ÷ ${newB}`, columns: [ { rows: [`${newA} ÷ ${newB}`, `= ${resultStr}`], highlight: 1 }, ], }); } else { steps.push({ label: `Divide: ${aStr} ÷ ${bStr}`, columns: [ { rows: [`${aStr} ÷ ${bStr}`, `= ${resultStr}`], highlight: 1 }, ], }); } steps.push({ label: `${aStr} ÷ ${bStr} = ${resultStr}`, columns: [ { rows: [`${aStr} ÷ ${bStr} = ${resultStr}`] }, ], resultRow: resultStr, }); return steps; } function ColumnArithmetic({ columns, }: { columns: ColumnDisplay[]; }) { if (columns.length === 0) return null; return (
Enter two decimal numbers
{error}
}Enter numbers above and click Go
) : ( <>{step.label}
Result will appear here when steps are complete
) : ( <>Answer
{step.resultRow}
> )}