Fix FerrersRogersRamanujan loop

Refactor animation logic to prevent infinite loop by replacing local step variable with state-driven useEffect, add proper termination, and guard intervals. Also introduce isAnimating flag, and adjust generate button states to reflect animation progress.

X-Lovable-Edit-ID: edt-8715691a-8a92-4c00-b580-9cb8dd310fc8
This commit is contained in:
gpt-engineer-app[bot] 2025-12-01 07:05:05 +00:00
commit b694b38558

View file

@ -12,6 +12,7 @@ const FerrersRogersRamanujan = () => {
const [rrPartition, setRRPartition] = useState<number[]>([]); const [rrPartition, setRRPartition] = useState<number[]>([]);
const [animatingHook, setAnimatingHook] = useState<{ row: number; col: number } | null>(null); const [animatingHook, setAnimatingHook] = useState<{ row: number; col: number } | null>(null);
const [animationStep, setAnimationStep] = useState(0); const [animationStep, setAnimationStep] = useState(0);
const [isAnimating, setIsAnimating] = useState(false);
useEffect(() => { useEffect(() => {
// Initialize sliders with all zeros // Initialize sliders with all zeros
@ -43,6 +44,7 @@ const FerrersRogersRamanujan = () => {
setRRPartition([]); setRRPartition([]);
setAnimatingHook(null); setAnimatingHook(null);
setAnimationStep(0); setAnimationStep(0);
setIsAnimating(false);
}; };
const generateRRPartition = () => { const generateRRPartition = () => {
@ -53,83 +55,69 @@ const FerrersRogersRamanujan = () => {
setRRPartition([]); setRRPartition([]);
setAnimationStep(0); setAnimationStep(0);
setIsAnimating(true);
// Start animation
animateHooks();
}; };
const animateHooks = () => { // Animation effect
const hooks: number[] = []; useEffect(() => {
if (!isAnimating || committedPartition.length === 0) return;
const partition = committedPartition; const partition = committedPartition;
// We need to traverse the L-shaped hooks // Find the hook at current animation step
// Start from position (0, 0) and go around the perimeter let found = false;
let step = 0; let hookCount = 0;
let targetRow = 0, targetCol = 0;
const maxRow = partition.length; const maxRow = partition.length;
const maxCol = partition[0] || 0; const maxCol = partition[0] || 0;
const processNextHook = () => { for (let d = 0; d < maxRow + maxCol && !found; d++) {
// Determine which hook to process for (let r = 0; r <= d; r++) {
// We traverse diagonally: (0,0), (1,0), (0,1), (2,0), (1,1), (0,2), ... const c = d - r;
let row = 0, col = 0; if (r < partition.length && c < partition[r]) {
let diag = 0; if (hookCount === animationStep) {
let found = false; targetRow = r;
targetCol = c;
// Find the step-th valid hook found = true;
let hookCount = 0; break;
for (let d = 0; d < maxRow + maxCol; d++) {
for (let r = 0; r <= d; r++) {
const c = d - r;
if (r < partition.length && c < partition[r]) {
if (hookCount === step) {
row = r;
col = c;
found = true;
break;
}
hookCount++;
} }
} hookCount++;
if (found) break;
}
if (!found) {
// Animation complete
setAnimatingHook(null);
return;
}
setAnimatingHook({ row, col });
// Calculate hook size: boxes to the right + boxes below + 1 (the box itself)
const boxesRight = partition[row] - col - 1;
let boxesBelow = 0;
for (let r = row + 1; r < partition.length; r++) {
if (partition[r] > col) {
boxesBelow++;
} else {
break;
} }
} }
const hookSize = boxesRight + boxesBelow + 1; }
hooks.push(hookSize); if (!found) {
setRRPartition([...hooks]); // Animation complete
setIsAnimating(false);
setAnimatingHook(null);
return;
}
setTimeout(() => { setAnimatingHook({ row: targetRow, col: targetCol });
setAnimationStep(step + 1);
}, 500);
};
const interval = setInterval(() => { // Calculate hook size
processNextHook(); const boxesRight = partition[targetRow] - targetCol - 1;
if (animatingHook === null && step > 0) { let boxesBelow = 0;
clearInterval(interval); for (let r = targetRow + 1; r < partition.length; r++) {
if (partition[r] > targetCol) {
boxesBelow++;
} else {
break;
} }
}
const hookSize = boxesRight + boxesBelow + 1;
// Update RR partition
setRRPartition(prev => [...prev, hookSize]);
// Schedule next step
const timeout = setTimeout(() => {
setAnimationStep(prev => prev + 1);
}, 500); }, 500);
processNextHook(); return () => clearTimeout(timeout);
}; }, [isAnimating, animationStep, committedPartition]);
const renderFerrersDiagram = (partition: number[], highlightHook?: { row: number; col: number }) => { const renderFerrersDiagram = (partition: number[], highlightHook?: { row: number; col: number }) => {
if (partition.length === 0) return null; if (partition.length === 0) return null;
@ -247,10 +235,10 @@ const FerrersRogersRamanujan = () => {
<Button <Button
onClick={generateRRPartition} onClick={generateRRPartition}
disabled={rrPartition.length > 0} disabled={rrPartition.length > 0 || isAnimating}
className="w-full md:w-auto" className="w-full md:w-auto"
> >
Generate Rogers-Ramanujan Partition {isAnimating ? "Generating..." : "Generate Rogers-Ramanujan Partition"}
</Button> </Button>
{/* RR Partition Display */} {/* RR Partition Display */}