feat(lessons): add lessons from client db
This commit is contained in:
116
src/components/lessons/FactoringWidget.tsx
Normal file
116
src/components/lessons/FactoringWidget.tsx
Normal file
@ -0,0 +1,116 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const FactoringWidget: React.FC = () => {
|
||||
// ax^2 + bx + c
|
||||
const [a, setA] = useState(1);
|
||||
const [b, setB] = useState(5);
|
||||
const [c, setC] = useState(6);
|
||||
|
||||
const product = a * c;
|
||||
const sum = b;
|
||||
|
||||
// We won't solve it for them immediately, let them guess or think
|
||||
// But we will show if it's factorable over integers
|
||||
// Simple check for nice numbers
|
||||
const getFactors = () => {
|
||||
// Find two numbers p, q such that p*q = product and p+q = sum
|
||||
// Brute force range reasonable for typical SAT (up to +/- 100)
|
||||
for (let i = -100; i <= 100; i++) {
|
||||
if (i === 0) continue;
|
||||
const q = product / i;
|
||||
if (Math.abs(q - Math.round(q)) < 0.001) { // is integer
|
||||
if (i + q === sum) return [i, q].sort((x,y) => x-y);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const solution = getFactors();
|
||||
|
||||
return (
|
||||
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
|
||||
<div className="flex flex-col md:flex-row gap-8 items-center">
|
||||
{/* Input Side */}
|
||||
<div className="w-full md:w-1/2 space-y-4">
|
||||
<h4 className="font-bold text-violet-900 mb-2">Polynomial: <span className="font-mono text-lg">{a === 1 ? '' : a}x² {b >= 0 ? '+' : ''}{b}x {c >= 0 ? '+' : ''}{c}</span></h4>
|
||||
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<div>
|
||||
<label className="text-xs font-bold text-slate-400">a</label>
|
||||
<input type="number" value={a} onChange={e => setA(parseInt(e.target.value) || 0)} className="w-full p-2 border rounded font-mono font-bold text-center" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-bold text-slate-400">b (Sum)</label>
|
||||
<input type="number" value={b} onChange={e => setB(parseInt(e.target.value) || 0)} className="w-full p-2 border rounded font-mono font-bold text-center" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-bold text-slate-400">c</label>
|
||||
<input type="number" value={c} onChange={e => setC(parseInt(e.target.value) || 0)} className="w-full p-2 border rounded font-mono font-bold text-center" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-slate-50 rounded-lg text-sm text-slate-600">
|
||||
<p><strong>AC Method (Diamond):</strong></p>
|
||||
<p>Find two numbers that multiply to <strong>a·c</strong> and add to <strong>b</strong>.</p>
|
||||
<p className="mt-2 font-mono text-center">
|
||||
Product (ac) = {a} × {c} = <strong>{product}</strong> <br/>
|
||||
Sum (b) = <strong>{sum}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Visual Side */}
|
||||
<div className="flex-1 flex flex-col items-center justify-center">
|
||||
<div className="relative w-48 h-48">
|
||||
{/* X Shape */}
|
||||
<div className="absolute top-0 left-0 w-full h-full">
|
||||
<svg width="100%" height="100%" viewBox="0 0 200 200">
|
||||
<line x1="20" y1="20" x2="180" y2="180" stroke="#cbd5e1" strokeWidth="4" />
|
||||
<line x1="180" y1="20" x2="20" y2="180" stroke="#cbd5e1" strokeWidth="4" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Top (Product) */}
|
||||
<div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-4 bg-violet-100 px-3 py-1 rounded border border-violet-300 text-violet-800 font-bold shadow-sm">
|
||||
{product}
|
||||
</div>
|
||||
|
||||
{/* Bottom (Sum) */}
|
||||
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-4 bg-indigo-100 px-3 py-1 rounded border border-indigo-300 text-indigo-800 font-bold shadow-sm">
|
||||
{sum}
|
||||
</div>
|
||||
|
||||
{/* Left (Factor 1) */}
|
||||
<div className="absolute left-0 top-1/2 -translate-x-6 -translate-y-1/2 bg-white px-3 py-2 rounded border-2 border-emerald-400 text-emerald-700 font-bold shadow-md min-w-[3rem] text-center">
|
||||
{solution ? solution[0] : "?"}
|
||||
</div>
|
||||
|
||||
{/* Right (Factor 2) */}
|
||||
<div className="absolute right-0 top-1/2 translate-x-6 -translate-y-1/2 bg-white px-3 py-2 rounded border-2 border-emerald-400 text-emerald-700 font-bold shadow-md min-w-[3rem] text-center">
|
||||
{solution ? solution[1] : "?"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 text-center">
|
||||
{solution ? (
|
||||
<div className="text-emerald-700 font-bold bg-emerald-50 px-4 py-2 rounded-lg border border-emerald-200">
|
||||
Factors Found: {solution[0]} and {solution[1]}
|
||||
{a === 1 && (
|
||||
<div className="text-sm mt-1 font-mono text-slate-600">
|
||||
(x {solution[0] >= 0 ? '+' : ''}{solution[0]})(x {solution[1] >= 0 ? '+' : ''}{solution[1]})
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-rose-600 font-bold text-sm bg-rose-50 px-4 py-2 rounded-lg border border-rose-200">
|
||||
No integer factors found. (Prime)
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FactoringWidget;
|
||||
Reference in New Issue
Block a user