"use client"; import { useState, useCallback } from "react"; import { Card } from "@/components/ui/card"; import { ClientOnly } from "@/components/ui/client-only"; import { StepControls } from "./step-controls"; import { MathDisplay } from "@/components/math/math-display"; interface Column { exponent: number; placeValue: number; digit: string; contrib: number; } interface Step { label: string; math: string; activeCol: number | null; revealed: number; // how many columns show their contribution } const PLACE_NAMES = ["ones", "tens", "hundreds", "thousands", "ten thousands", "hundred thousands"]; function columnsFor(n: number): Column[] { const str = `${n}`; const len = str.length; return str.split("").map((d, i) => { const exponent = len - 1 - i; return { exponent, placeValue: Math.pow(10, exponent), digit: d, contrib: parseInt(d, 10) * Math.pow(10, exponent), }; }); } function buildSteps(n: number): Step[] { const cols = columnsFor(n); const len = cols.length; const steps: Step[] = [ { label: "In the denary (base 10) system, each digit has a place value that is a power of 10.", math: `${n}`, activeCol: null, revealed: 0, }, ]; cols.forEach((c, i) => { steps.push({ label: `The ${PLACE_NAMES[c.exponent]} digit is ${c.digit}. Its place value is 10^${c.exponent} = ${c.placeValue.toLocaleString("en-US")}.`, math: `${c.digit} \\times 10^{${c.exponent}} = ${c.contrib.toLocaleString("en-US")}`, activeCol: i, revealed: i + 1, }); }); const expanded = cols.map((c) => `${c.digit} \\times 10^{${c.exponent}}`).join(" + "); steps.push({ label: "Put it all together — this is the number in expanded form.", math: `${n} = ${expanded}`, activeCol: null, revealed: len, }); const sumParts = cols.map((c) => c.contrib.toLocaleString("en-US")).join(" + "); steps.push({ label: "Add every part back up and you return to the original number.", math: `${sumParts} = ${n.toLocaleString("en-US")}`, activeCol: null, revealed: len, }); return steps; } function PlaceValueChart({ columns, step }: { columns: Column[]; step: Step }) { return (
{columns.map((c, i) => ( ))} {columns.map((c, i) => ( ))} {columns.map((c, i) => ( ))} {columns.map((c, i) => ( ))}
10{c.exponent}
{c.placeValue.toLocaleString("en-US")}
{c.digit}
{i < step.revealed ? c.contrib.toLocaleString("en-US") : "_"}
); } // ── Quick practice ─────────────────────────────────────────────────────────── interface PracticeQ { prompt: string; answer: number; } function randInt(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1)) + min; } function makeQuestion(): PracticeQ { if (Math.random() < 0.5) { // value of a digit const n = randInt(1000, 99999); const cols = columnsFor(n); const nonZero = cols.filter((c) => c.digit !== "0"); const pick = nonZero[Math.floor(Math.random() * nonZero.length)]; return { prompt: `In ${n.toLocaleString("en-US")}, what is the VALUE of the digit ${pick.digit}?`, answer: pick.contrib, }; } // exponent of a named column const exp = randInt(0, 5); return { prompt: `Which power of 10 is the ${PLACE_NAMES[exp]} column? Enter the exponent.`, answer: exp, }; } function QuickPractice() { const [q, setQ] = useState(() => makeQuestion()); const [val, setVal] = useState(""); const [feedback, setFeedback] = useState<"correct" | "incorrect" | null>(null); const [score, setScore] = useState({ correct: 0, total: 0 }); function check() { const parsed = parseInt(val, 10); if (isNaN(parsed)) return; const correct = parsed === q.answer; setFeedback(correct ? "correct" : "incorrect"); setScore((s) => ({ correct: s.correct + (correct ? 1 : 0), total: s.total + 1 })); } function next() { setQ(makeQuestion()); setVal(""); setFeedback(null); } return (

Quick Practice

{score.correct}/{score.total}

{q.prompt}

{ setVal(e.target.value); setFeedback(null); }} onKeyDown={(e) => { if (e.key === "Enter") { if (feedback !== null) next(); else check(); } }} className={`w-32 rounded-lg border-2 px-3 py-2 text-center text-xl font-bold outline-none transition-colors ${ feedback === "correct" ? "border-correct bg-correct-light" : feedback === "incorrect" ? "border-incorrect bg-incorrect-light" : "border-border focus:border-unit-6" }`} placeholder="?" aria-label="Your answer" /> {feedback === null ? ( ) : ( )}
{feedback === "correct" &&

Correct!

} {feedback === "incorrect" && (

Not quite — the answer is {q.answer.toLocaleString("en-US")}.

)}
); } // ── Main explorer ──────────────────────────────────────────────────────────── export function PlaceValueExplorer() { const [input, setInput] = useState("983275"); const [error, setError] = useState(""); const [columns, setColumns] = useState(null); const [steps, setSteps] = useState(null); const [currentStep, setCurrentStep] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const done = steps ? currentStep >= steps.length - 1 : false; const reset = useCallback(() => { setSteps(null); setColumns(null); setCurrentStep(0); setIsPlaying(false); }, []); function handleGo() { setError(""); const cleaned = input.replace(/[,\s]/g, ""); const n = parseInt(cleaned, 10); if (isNaN(n) || !/^\d+$/.test(cleaned)) return setError("Enter a whole number (digits only)."); if (n < 1 || n > 999999) return setError("Use a whole number between 1 and 999,999."); setColumns(columnsFor(n)); setSteps(buildSteps(n)); setCurrentStep(0); setIsPlaying(false); } const stepForward = useCallback(() => { if (!steps || currentStep >= steps.length - 1) return; setCurrentStep((s) => s + 1); if (currentStep + 1 >= steps.length - 1) setIsPlaying(false); }, [steps, currentStep]); const stepBack = useCallback(() => { if (currentStep <= 0) return; setCurrentStep((s) => s - 1); }, [currentStep]); const togglePlay = useCallback(() => setIsPlaying((p) => !p), []); const step = steps ? steps[currentStep] : null; return (
{/* Input card */}

Enter a whole number (up to 999,999)

setInput(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") handleGo(); }} className="w-44 rounded-lg border-2 border-unit-6 bg-surface px-3 py-2 text-center font-mono text-2xl font-bold text-unit-6 outline-none focus:border-unit-6-dark" aria-label="Number input" />
{error &&

{error}

}
{/* Display card */} {!step || !columns ? (

Enter a number above and click Break Down

) : ( <>

{step.label}

)}
{/* Controls */} 0} /> {/* Quick practice */} }>
); }