import { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Switch } from '@/components/ui/switch'; import { Label } from '@/components/ui/label'; import { HelpCircle, RefreshCw, ChevronLeft, ChevronRight } from 'lucide-react'; import SocialShare from '@/components/SocialShare'; interface ZeckendorfSearchTrickProps { showSocialShare?: boolean; } // First 8 Fibonacci numbers: 1, 1, 2, 3, 5, 8, 13, 21 const FIBONACCI_NUMBERS = [21, 13, 8, 5, 3, 2, 1]; // Function to get Zeckendorf representation of a number const getZeckendorfRepresentation = (n: number): number[] => { if (n === 0) return []; // Find the largest Fibonacci number less than or equal to n let largestFib = 0; let largestFibIndex = 0; for (let i = 0; i < FIBONACCI_NUMBERS.length; i++) { if (FIBONACCI_NUMBERS[i] <= n) { largestFib = FIBONACCI_NUMBERS[i]; largestFibIndex = i; break; } } if (largestFib === 0) return []; // Recursively get representation for the remainder const remainder = n - largestFib; const remainderRep = getZeckendorfRepresentation(remainder); // Check if adding this Fibonacci number would create consecutive numbers if (remainderRep.length > 0 && remainderRep[0] === FIBONACCI_NUMBERS[largestFibIndex + 1]) { // If it would create consecutive, try the next smaller Fibonacci number return getZeckendorfRepresentation(n); } return [largestFib, ...remainderRep]; }; // Function to check if a number contains a specific Fibonacci number in its Zeckendorf representation const containsFibonacciInZeckendorf = (number: number, fibonacci: number): boolean => { const representation = getZeckendorfRepresentation(number); return representation.includes(fibonacci); }; const ZeckendorfSearchTrick = ({ showSocialShare = true }: ZeckendorfSearchTrickProps) => { const [cardStates, setCardStates] = useState>({}); const [result, setResult] = useState(null); const [showResult, setShowResult] = useState(false); const [isOneByOne, setIsOneByOne] = useState(false); const [isRandomized, setIsRandomized] = useState(true); const [isSpoiler, setIsSpoiler] = useState(false); const [currentCardIndex, setCurrentCardIndex] = useState(0); const [cards, setCards] = useState>([]); // Function to shuffle array const shuffleArray = (array: T[]): T[] => { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; }; // Generate cards with optional randomization const generateCards = () => { const baseCards = FIBONACCI_NUMBERS.map((fib, index) => { const numbers: number[] = []; // Check numbers from 1 to 33 to see which ones contain this Fibonacci number for (let i = 1; i <= 33; i++) { if (containsFibonacciInZeckendorf(i, fib)) { numbers.push(i); } } return { id: fib, title: `Card ${index + 1}`, numbers: numbers }; }); // Apply randomization based on toggle state return baseCards.map(card => ({ ...card, numbers: isRandomized ? shuffleArray(card.numbers) : card.numbers })); }; // Initialize cards on component mount useEffect(() => { setCards(generateCards()); }, [isRandomized]); // Handle mode toggle const handleModeToggle = (checked: boolean) => { setIsOneByOne(checked); setCurrentCardIndex(0); setCardStates({}); setShowResult(false); }; // Handle randomization toggle const handleRandomizationToggle = (checked: boolean) => { setIsRandomized(checked); setCardStates({}); setShowResult(false); setCurrentCardIndex(0); }; // Handle spoiler toggle const handleSpoilerToggle = (checked: boolean) => { setIsSpoiler(checked); }; // Navigation functions for one-by-one mode const goToPreviousCard = () => { setCurrentCardIndex(prev => Math.max(0, prev - 1)); }; const goToNextCard = () => { setCurrentCardIndex(prev => Math.min(cards.length - 1, prev + 1)); }; const handleCardSelection = (cardId: number, state: 'present' | 'absent') => { setCardStates(prev => ({ ...prev, [cardId]: state })); setShowResult(false); }; const calculateResult = () => { const sum = Object.entries(cardStates) .filter(([_, state]) => state === 'present') .reduce((acc, [cardId, _]) => acc + parseInt(cardId), 0); setResult(sum); setShowResult(true); }; const reset = () => { setCardStates({}); setResult(null); setShowResult(false); setCurrentCardIndex(0); setCards(generateCards()); // Regenerate with current randomization setting }; // Check if at least one card has been selected (present or absent) const hasAnySelection = Object.values(cardStates).some(state => state !== 'unselected'); // Check if all cards have been committed to in one-by-one mode const allCardsCommitted = isOneByOne ? cards.every(card => cardStates[card.id] && cardStates[card.id] !== 'unselected') : hasAnySelection; // Get cards to display based on mode const getDisplayCards = () => { if (isOneByOne) { return cards.length > 0 ? [cards[currentCardIndex]] : []; } return cards; }; return (
Zeckendorf Search Magic Trick
Zeckendorf Representation Magic Trick Explained

How to perform the trick:

  1. Ask someone to pick a secret number between 1 and 33
  2. Show them the 8 cards below and ask them to tell you which cards contain their number
  3. Add up the first numbers (21, 13, 8, 5, 3, 2, 1, 1) from the cards they selected
  4. The sum will be their secret number!

Why does it work?

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

Each card contains all numbers that have a specific Fibonacci number in their Zeckendorf representation:

  • Card 21: Numbers that have 21 in their Zeckendorf representation
  • Card 13: Numbers that have 13 in their Zeckendorf representation
  • Card 8: Numbers that have 8 in their Zeckendorf representation
  • Card 5: Numbers that have 5 in their Zeckendorf representation
  • Card 3: Numbers that have 3 in their Zeckendorf representation
  • Card 2: Numbers that have 2 in their Zeckendorf representation
  • Card 1: Numbers that have 1 in their Zeckendorf representation

Example:

The number 19 in Zeckendorf representation is 13 + 5 + 1 = 19

So 19 appears on cards 13, 5, and 1, but not on cards 21, 8, 3, or 2.

When you add up the first numbers from the selected cards, you're reconstructing the Zeckendorf representation of their secret number!

Think of a number between 1 and 33, then tell me which cards contain your number!

{/* Controls */}
{/* Navigation for one-by-one mode */} {isOneByOne && cards.length > 0 && (
Card {currentCardIndex + 1} of {cards.length}
)}
{/* Cards */}
{getDisplayCards().map(card => (
{isSpoiler ? card.id : card.title.replace('Card ', '')}
{card.numbers.map(num => (
{num}
))}
))}
{/* Reveal button */}
{/* Result */} {showResult && result !== null && (

Your number is: {result}

Magic! 🎩✨

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