import React, { useState, useEffect, useCallback } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import SocialShare from '@/components/SocialShare'; // First 10 Fibonacci numbers: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 const FIBONACCI_NUMBERS = [55, 34, 21, 13, 8, 5, 3, 2, 1, 1]; interface ZeckendorfGameProps { showSocialShare?: boolean; } const ZeckendorfGame: React.FC = ({ showSocialShare = true }) => { const [targetNumber, setTargetNumber] = useState(0); const [flippedCards, setFlippedCards] = useState(new Array(10).fill(false)); const [currentSum, setCurrentSum] = useState(0); const [timer, setTimer] = useState(0); const [isGameActive, setIsGameActive] = useState(false); const [isGameWon, setIsGameWon] = useState(false); const [hasGameStarted, setHasGameStarted] = useState(false); const [highScore, setHighScore] = useState(null); // Load high score from localStorage on component mount useEffect(() => { const savedHighScore = localStorage.getItem('zeckendorf-game-high-score'); if (savedHighScore) { setHighScore(parseInt(savedHighScore)); } }, []); // Generate a valid target number (sum of some Fibonacci numbers) const generateValidTarget = useCallback(() => { // Generate a random combination of Fibonacci numbers const numTerms = Math.floor(Math.random() * 4) + 2; // 2-5 terms let target = 0; let usedIndices = new Set(); for (let i = 0; i < numTerms; i++) { let index; do { index = Math.floor(Math.random() * 10); } while (usedIndices.has(index)); usedIndices.add(index); target += FIBONACCI_NUMBERS[index]; } return target; }, []); // Start new game const startNewGame = useCallback(() => { const newTarget = generateValidTarget(); setTargetNumber(newTarget); setFlippedCards(new Array(10).fill(false)); setCurrentSum(0); setTimer(0); setIsGameActive(true); setIsGameWon(false); setHasGameStarted(true); }, [generateValidTarget]); // Start game for the first time const startGame = () => { startNewGame(); }; // Timer effect useEffect(() => { let interval: NodeJS.Timeout; if (isGameActive && !isGameWon) { interval = setInterval(() => { setTimer(prev => prev + 0.1); }, 100); } return () => clearInterval(interval); }, [isGameActive, isGameWon]); // Check for win condition useEffect(() => { if (currentSum === targetNumber && isGameActive) { setIsGameActive(false); setIsGameWon(true); // Update high score const currentTime = Math.round(timer * 10) / 10; if (highScore === null || currentTime < highScore) { setHighScore(currentTime); localStorage.setItem('zeckendorf-game-high-score', currentTime.toString()); } } }, [currentSum, targetNumber, isGameActive, timer, highScore]); // Calculate current sum useEffect(() => { const sum = flippedCards.reduce((acc, isFlipped, index) => { return isFlipped ? acc + FIBONACCI_NUMBERS[index] : acc; }, 0); setCurrentSum(sum); }, [flippedCards]); // Check if current selection violates Zeckendorf rule (no consecutive Fibonacci numbers) const hasConsecutiveFibonacci = () => { for (let i = 0; i < flippedCards.length - 1; i++) { if (flippedCards[i] && flippedCards[i + 1]) { return true; } } return false; }; const toggleCard = (index: number) => { if (!isGameActive || isGameWon) return; setFlippedCards(prev => { const newFlipped = [...prev]; newFlipped[index] = !newFlipped[index]; return newFlipped; }); }; const isInvalidSelection = hasConsecutiveFibonacci(); return (

Zeckendorf Representation

Click the cards to represent the target number as a sum of Fibonacci numbers (no consecutive numbers allowed)!

{highScore !== null && ( Best Time: {highScore}s )}
{/* Cards representing Fibonacci numbers */}
{FIBONACCI_NUMBERS.map((fib, index) => (
toggleCard(index)} > {flippedCards[index] ? ( {fib} ) : (
)}
{fib}
))}
{/* Warning for invalid selection */} {isInvalidSelection && (
⚠️ Invalid: Cannot use consecutive Fibonacci numbers!
)} {/* Sum display boxes */}

Current Sum

targetNumber ? "text-red-600" : isInvalidSelection ? "text-orange-600" : "text-foreground"}`}> {currentSum}

Target Sum

{!hasGameStarted ? "🎯" : targetNumber}
{/* Timer and controls */}
Time: {Math.round(timer * 10) / 10}s
{isGameWon && (
Congratulations! 🎉
Your score: {Math.round(timer * 10) / 10} seconds
{highScore === Math.round(timer * 10) / 10 && ( New High Score! 🏆 )}
)}
{/* Information about Zeckendorf representation */}

About Zeckendorf Representation

Every positive integer can be uniquely represented as a sum of Fibonacci numbers, where no two consecutive Fibonacci numbers are used. This is called the Zeckendorf representation.

{showSocialShare && ( )}
); }; export default ZeckendorfGame;