"use client"; import { useState, useCallback } from "react"; import { Card } from "@/components/ui/card"; import { StepControls } from "./step-controls"; import { MathDisplay } from "@/components/math/math-display"; type Mode = "number-line" | "rules"; interface Step { label: string; math: string; numberLineHighlight?: { start: number; end: number; direction: "left" | "right"; moves: number; }; } function buildAddSubtractSteps(a: number, b: number, op: "add" | "subtract"): Step[] { const steps: Step[] = []; const opSymbol = op === "add" ? "+" : "-"; const expression = `${a} ${opSymbol} ${b < 0 ? `(${b})` : b}`; // Step 0: Show the original expression steps.push({ label: "Start with the expression", math: expression, numberLineHighlight: { start: a, end: a, direction: "right", moves: 0 }, }); if (op === "add") { // Adding steps.push({ label: `Place your finger on ${a} on the number line`, math: `\\text{Start at } ${a}`, numberLineHighlight: { start: a, end: a, direction: "right", moves: 0 }, }); if (b >= 0) { steps.push({ label: `Adding a positive number: move ${b} steps to the RIGHT`, math: `${a} + ${b} \\longrightarrow \\text{move right } ${b}`, numberLineHighlight: { start: a, end: a + b, direction: "right", moves: b }, }); } else { steps.push({ label: `Adding a negative number: move ${Math.abs(b)} steps to the LEFT`, math: `${a} + (${b}) \\longrightarrow \\text{move left } ${Math.abs(b)}`, numberLineHighlight: { start: a, end: a + b, direction: "left", moves: Math.abs(b) }, }); } const result = a + b; steps.push({ label: `You land on ${result}`, math: `${expression} = ${result}`, numberLineHighlight: { start: a, end: result, direction: b >= 0 ? "right" : "left", moves: Math.abs(b) }, }); // Sign rule explanation if (a >= 0 && b >= 0) { steps.push({ label: "Rule: Positive + Positive = Positive", math: `(+) + (+) = (+) \\quad \\Rightarrow \\quad ${expression} = ${result}`, numberLineHighlight: { start: a, end: result, direction: "right", moves: Math.abs(b) }, }); } else if (a < 0 && b < 0) { steps.push({ label: "Rule: Negative + Negative = Negative (add magnitudes, keep negative sign)", math: `(-) + (-) = (-) \\quad \\Rightarrow \\quad ${expression} = ${result}`, numberLineHighlight: { start: a, end: result, direction: "left", moves: Math.abs(b) }, }); } else { steps.push({ label: "Rule: Different signs? Subtract the smaller from the larger, keep the sign of the larger", math: `|${Math.abs(a)}| - |${Math.abs(b)}| = ${Math.abs(Math.abs(a) - Math.abs(b))} \\quad \\Rightarrow \\quad ${expression} = ${result}`, numberLineHighlight: { start: a, end: result, direction: result >= a ? "right" : "left", moves: Math.abs(b) }, }); } } else { // Subtracting steps.push({ label: `Place your finger on ${a} on the number line`, math: `\\text{Start at } ${a}`, numberLineHighlight: { start: a, end: a, direction: "right", moves: 0 }, }); if (b >= 0) { steps.push({ label: `Subtracting a positive number: move ${b} steps to the LEFT`, math: `${a} - ${b} \\longrightarrow \\text{move left } ${b}`, numberLineHighlight: { start: a, end: a - b, direction: "left", moves: b }, }); } else { steps.push({ label: `Subtracting a negative number is the same as ADDING a positive! Move ${Math.abs(b)} steps RIGHT`, math: `${a} - (${b}) = ${a} + ${Math.abs(b)} \\longrightarrow \\text{move right } ${Math.abs(b)}`, numberLineHighlight: { start: a, end: a - b, direction: "right", moves: Math.abs(b) }, }); } const result = a - b; steps.push({ label: `You land on ${result}`, math: `${expression} = ${result}`, numberLineHighlight: { start: a, end: result, direction: result >= a ? "right" : "left", moves: Math.abs(b) }, }); // Two like/unlike signs rule if (b >= 0) { steps.push({ label: "Two unlike signs (+ -) becomes negative: subtract means move left", math: `+(-)\\text{ becomes } - \\quad \\Rightarrow \\quad ${expression} = ${result}`, numberLineHighlight: { start: a, end: result, direction: "left", moves: Math.abs(b) }, }); } else { steps.push({ label: "Two like signs (- -) becomes positive: subtracting a negative means move right!", math: `-(-) \\text{ becomes } + \\quad \\Rightarrow \\quad ${expression} = ${result}`, numberLineHighlight: { start: a, end: result, direction: "right", moves: Math.abs(b) }, }); } } return steps; } function NumberLine({ highlight, animate, }: { highlight?: Step["numberLineHighlight"]; animate: boolean; }) { const minVal = -15; const maxVal = 15; const range = maxVal - minVal; const start = highlight?.start ?? 0; const end = highlight?.end ?? 0; const startX = ((start - minVal) / range) * 100; const endX = ((end - minVal) / range) * 100; const leftX = Math.min(startX, endX); const width = Math.abs(endX - startX); return (
{/* Arrow path highlight */} {highlight && highlight.moves > 0 && (
)} {/* Direction arrow */} {highlight && highlight.moves > 0 && (
{highlight.direction === "right" ? "→ right →" : "← left ←"}
{highlight.moves} step{highlight.moves !== 1 ? "s" : ""}
)} {/* Number line */}
{/* Tick marks */} {Array.from({ length: range + 1 }, (_, i) => { const val = minVal + i; const x = (i / range) * 100; const isZero = val === 0; const isHighlighted = highlight && (val === start || val === end); const isInRange = highlight && highlight.moves > 0 && val >= Math.min(start, end) && val <= Math.max(start, end); return (
{(val % 5 === 0 || isHighlighted) && ( {val} )}
); })}
{/* Start marker */} {highlight && (
Start
)} {/* End marker */} {highlight && highlight.moves > 0 && animate && (
End: {end}
)}
{/* Arrows on edges */}
← negative positive →
); } function SignRuleCard({ rule, active }: { rule: string; active: boolean }) { return (
{rule}
); } function QuickPractice() { const [problem, setProblem] = useState(() => generateProblem()); const [userAnswer, setUserAnswer] = useState(""); const [feedback, setFeedback] = useState<"correct" | "incorrect" | null>(null); const [score, setScore] = useState({ correct: 0, total: 0 }); function generateProblem() { const ops = ["+", "-"] as const; const op = ops[Math.floor(Math.random() * ops.length)]; const a = Math.floor(Math.random() * 21) - 10; const b = Math.floor(Math.random() * 21) - 10; const answer = op === "+" ? a + b : a - b; return { a, b, op, answer }; } function checkAnswer() { const parsed = parseInt(userAnswer); if (isNaN(parsed)) return; const isCorrect = parsed === problem.answer; setFeedback(isCorrect ? "correct" : "incorrect"); setScore((prev) => ({ correct: prev.correct + (isCorrect ? 1 : 0), total: prev.total + 1, })); } function nextProblem() { setProblem(generateProblem()); setUserAnswer(""); setFeedback(null); } const displayB = problem.b < 0 ? `(${problem.b})` : `${problem.b}`; return (

Quick Practice

{score.correct}/{score.total}
{problem.a} {problem.op} {displayB} = { setUserAnswer(e.target.value); setFeedback(null); }} onKeyDown={(e) => { if (e.key === "Enter") { if (feedback !== null) nextProblem(); else checkAnswer(); } }} className={`w-20 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-5" }`} placeholder="?" aria-label="Your answer" /> {feedback === null ? ( ) : ( )}
{feedback === "correct" && (

Correct! Well done!

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

Not quite. The answer is {problem.answer}. Try the next one!

)}
); } export function IntegerAddSubtractExplorer() { const [mode, setMode] = useState("number-line"); const [op, setOp] = useState<"add" | "subtract">("add"); const [inputA, setInputA] = useState("-3"); const [inputB, setInputB] = useState("5"); const [error, setError] = useState(""); const [steps, setSteps] = useState(null); const [currentStep, setCurrentStep] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const done = steps ? currentStep >= steps.length - 1 : false; function handleGo() { setError(""); const a = parseInt(inputA); const b = parseInt(inputB); if (isNaN(a) || isNaN(b)) { setError("Enter valid integers."); return; } if (Math.abs(a) > 15 || Math.abs(b) > 15) { setError("Keep numbers between -15 and 15 for the number line."); return; } const result = op === "add" ? a + b : a - b; if (Math.abs(result) > 15) { setError("Result goes off the number line. Try smaller numbers."); return; } try { const s = buildAddSubtractSteps(a, b, op); setSteps(s); setCurrentStep(0); setIsPlaying(false); } catch { setError("Could not compute. Check your inputs."); } } 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 reset = useCallback(() => { setSteps(null); setCurrentStep(0); setIsPlaying(false); }, []); const step = steps ? steps[currentStep] : null; const addRules = [ { rule: "(+) + (+) = (+)", active: step?.label.includes("Positive + Positive") ?? false }, { rule: "(-) + (-) = (-)", active: step?.label.includes("Negative + Negative") ?? false }, { rule: "Different signs? Subtract, keep sign of larger", active: step?.label.includes("Different signs") ?? false }, ]; const subRules = [ { rule: "+(−) becomes −", active: step?.label.includes("unlike signs") ?? false }, { rule: "−(−) becomes +", active: step?.label.includes("like signs") ?? false }, ]; return (
{/* Mode toggle */}
{(["number-line", "rules"] as Mode[]).map((m) => ( ))}
{/* Operation tabs */}
{(["add", "subtract"] as const).map((o) => ( ))}
{/* Input Card */}

Enter two integers

setInputA(e.target.value)} className="w-20 rounded-lg border-2 border-border bg-surface px-3 py-2 text-center text-lg font-bold outline-none focus:border-unit-5" aria-label="First integer" /> {op === "add" ? "+" : "−"} setInputB(e.target.value)} className="w-20 rounded-lg border-2 border-border bg-surface px-3 py-2 text-center text-lg font-bold outline-none focus:border-unit-5" aria-label="Second integer" />
{error &&

{error}

}
{/* Sign Rules Reference */} {mode === "rules" && (
{(op === "add" ? addRules : subRules).map((r) => ( ))}
)} {/* Display Card with Number Line */} {!step ? (

Enter integers above and click Go

) : ( <>

{step.label}

{mode === "number-line" && ( 0} /> )} )}
{/* Controls */} 0} /> {/* Result */} {!done || !steps ? (

Result will appear here when steps are complete

) : ( <>

Answer

)}
{/* Quick Practice */}
); }