import React, { useState, useEffect, useCallback } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Slider } from '@/components/ui/slider'; import { Badge } from '@/components/ui/badge'; import { Switch } from '@/components/ui/switch'; import { Label } from '@/components/ui/label'; import { Brain, User, Trophy, Target, HelpCircle, CheckCircle, XCircle } from 'lucide-react'; import SocialShare from '@/components/SocialShare'; import StandardGuessingMode from '@/components/guessing-game/StandardGuessingMode'; import QuestionGuessingMode from '@/components/guessing-game/QuestionGuessingMode'; interface GuessingGameProps { showSocialShare?: boolean; } type GameMode = 'user-guesses' | 'computer-asks'; type UserGuessingMode = 'standard' | 'questions'; type ComputerStrategy = 'random' | 'linear' | 'binary'; type GameState = 'setup' | 'playing' | 'won' | 'lost'; interface Question { text: string; isCorrect: (num: number) => boolean; } const GuessingGame: React.FC = ({ showSocialShare = true }) => { // Game settings const [range, setRange] = useState([50]); const [gameMode, setGameMode] = useState('user-guesses'); const [userGuessingMode, setUserGuessingMode] = useState('standard'); const [computerStrategy, setComputerStrategy] = useState('binary'); // Game state const [gameState, setGameState] = useState('setup'); const [secretNumber, setSecretNumber] = useState(null); const [userGuess, setUserGuess] = useState(''); const [guesses, setGuesses] = useState([]); const [feedback, setFeedback] = useState(''); const [validNumbers, setValidNumbers] = useState>(new Set()); // Computer asking mode const [possibleNumbers, setPossibleNumbers] = useState([]); const [currentQuestion, setCurrentQuestion] = useState(null); const [questionsAsked, setQuestionsAsked] = useState([]); const [userScore, setUserScore] = useState(0); const [currentSearchIndex, setCurrentSearchIndex] = useState(0); const maxRange = range[0]; // Prime checker utility const isPrime = (num: number): boolean => { if (num < 2) return false; for (let i = 2; i <= Math.sqrt(num); i++) { if (num % i === 0) return false; } return true; }; // Random question generator const generateRandomQuestion = useCallback((): Question => { const questions = [ { text: "Is your number prime?", isCorrect: (num: number) => isPrime(num) }, { text: "Is your number even?", isCorrect: (num: number) => num % 2 === 0 }, { text: "Is your number divisible by 3?", isCorrect: (num: number) => num % 3 === 0 }, { text: "Is your number divisible by 5?", isCorrect: (num: number) => num % 5 === 0 }, { text: "Is your number a perfect square?", isCorrect: (num: number) => Math.sqrt(num) % 1 === 0 }, { text: "Is your number greater than half the maximum range?", isCorrect: (num: number) => num > maxRange / 2 }, { text: "Does your number contain the digit 5?", isCorrect: (num: number) => num.toString().includes('5') } ]; return questions[Math.floor(Math.random() * questions.length)]; }, [maxRange]); // Linear search question generator const generateLinearQuestion = useCallback((): Question => { const currentNum = currentSearchIndex + 1; return { text: `Is your number ${currentNum}?`, isCorrect: (num: number) => num === currentNum }; }, [currentSearchIndex]); // Binary search question generator const generateBinaryQuestion = useCallback((): Question => { if (possibleNumbers.length <= 1) { return { text: `Is your number ${possibleNumbers[0]}?`, isCorrect: (num: number) => num === possibleNumbers[0] }; } const midIndex = Math.floor(possibleNumbers.length / 2); const midValue = possibleNumbers[midIndex]; return { text: `Is your number ${midValue} or less?`, isCorrect: (num: number) => num <= midValue }; }, [possibleNumbers]); // Calculate valid numbers based on guesses and feedback const updateValidNumbers = useCallback((guesses: number[], secretNumber: number | null) => { if (guesses.length === 0 || !secretNumber) { const allNumbers = new Set(Array.from({ length: maxRange }, (_, i) => i + 1)); setValidNumbers(allNumbers); return; } const valid = new Set(); for (let num = 1; num <= maxRange; num++) { let isValid = true; for (const guess of guesses) { if (guess === secretNumber) break; // Game would be over if (guess < secretNumber) { // Guess was too low, so number must be higher than guess if (num <= guess) { isValid = false; break; } } else { // Guess was too high, so number must be lower than guess if (num >= guess) { isValid = false; break; } } } if (isValid) { valid.add(num); } } setValidNumbers(valid); }, [maxRange]); // Start new game const startGame = () => { if (gameMode === 'user-guesses') { const secret = Math.floor(Math.random() * maxRange) + 1; setSecretNumber(secret); setGuesses([]); setFeedback(''); const allNumbers = new Set(Array.from({ length: maxRange }, (_, i) => i + 1)); setValidNumbers(allNumbers); } else { const numbers = Array.from({ length: maxRange }, (_, i) => i + 1); setPossibleNumbers(numbers); setQuestionsAsked([]); setUserScore(0); setCurrentSearchIndex(0); setSecretNumber(null); } setGameState('playing'); setUserGuess(''); }; // Generate next question for computer const generateNextQuestion = useCallback(() => { if (possibleNumbers.length <= 1) { setGameState('won'); return; } let question: Question; switch (computerStrategy) { case 'random': question = generateRandomQuestion(); break; case 'linear': question = generateLinearQuestion(); break; case 'binary': question = generateBinaryQuestion(); break; } setCurrentQuestion(question); }, [computerStrategy, possibleNumbers, generateRandomQuestion, generateLinearQuestion, generateBinaryQuestion]); // Handle user's guess (both input and number click) const handleGuess = (guessValue?: number) => { const guess = guessValue || parseInt(userGuess); if (isNaN(guess) || guess < 1 || guess > maxRange) { setFeedback('Please enter a valid number within the range.'); return; } const newGuesses = [...guesses, guess]; setGuesses(newGuesses); if (guess === secretNumber) { setGameState('won'); setFeedback(`Congratulations! You found the number in ${newGuesses.length} guesses!`); } else { if (guess < secretNumber!) { setFeedback('Too low! Try a higher number.'); } else { setFeedback('Too high! Try a lower number.'); } // Update valid numbers based on new feedback updateValidNumbers(newGuesses, secretNumber); } setUserGuess(''); }; // Handle computer's question answer const handleQuestionAnswer = (answer: boolean) => { if (!currentQuestion) return; const questionText = `${currentQuestion.text} → ${answer ? 'Yes' : 'No'}`; setQuestionsAsked([...questionsAsked, questionText]); setUserScore(userScore + 1); let newPossibleNumbers = [...possibleNumbers]; if (computerStrategy === 'random') { // Filter based on the answer to the random question newPossibleNumbers = possibleNumbers.filter(num => currentQuestion.isCorrect(num) === answer ); } else if (computerStrategy === 'linear') { if (answer) { // Found the number setGameState('won'); return; } else { // Move to next number in linear search setCurrentSearchIndex(currentSearchIndex + 1); newPossibleNumbers = possibleNumbers.filter(num => num > currentSearchIndex + 1); } } else if (computerStrategy === 'binary') { const midIndex = Math.floor(possibleNumbers.length / 2); const midValue = possibleNumbers[midIndex]; if (possibleNumbers.length === 1) { setGameState('won'); return; } if (answer) { // Number is <= midValue newPossibleNumbers = possibleNumbers.slice(0, midIndex + 1); } else { // Number is > midValue newPossibleNumbers = possibleNumbers.slice(midIndex + 1); } } setPossibleNumbers(newPossibleNumbers); }; // Generate question when computer is asking useEffect(() => { if (gameState === 'playing' && gameMode === 'computer-asks') { generateNextQuestion(); } }, [gameState, gameMode, possibleNumbers, generateNextQuestion]); const resetGame = () => { setGameState('setup'); setSecretNumber(null); setUserGuess(''); setGuesses([]); setFeedback(''); setPossibleNumbers([]); setCurrentQuestion(null); setQuestionsAsked([]); setUserScore(0); setCurrentSearchIndex(0); }; const getStrategyDescription = (strategy: ComputerStrategy) => { switch (strategy) { case 'random': return 'Asks random mathematical questions about your number'; case 'linear': return 'Checks each number sequentially from 1 upward'; case 'binary': return 'Uses binary search to efficiently narrow down the range'; } }; const getOptimalGuesses = () => { return Math.ceil(Math.log2(maxRange)); }; return (
Number Guessing Game Experience different search strategies in this interactive guessing game {gameState === 'setup' && (
{/* Range Selection */}
Min: 10 Current: {maxRange} Max: 512
{/* Game Mode Selection */}
setGameMode('user-guesses')} >

You Guess

Computer thinks of a number, you try to guess it

Optimal: {getOptimalGuesses()} guesses
setGameMode('computer-asks')} >

Computer Asks

You think of a number, computer asks questions

Earn points for each question
{/* User Guessing Mode Selection */} {gameMode === 'user-guesses' && (
setUserGuessingMode('standard')} >

Standard (High/Low)

Traditional guessing with "too high" or "too low" feedback

setUserGuessingMode('questions')} >

Ask Questions

Ask yes/no questions about mathematical properties

)} {/* Computer Strategy Selection */} {gameMode === 'computer-asks' && (
{(['random', 'linear', 'binary'] as ComputerStrategy[]).map(strategy => ( setComputerStrategy(strategy)} >

{strategy} Search

{getStrategyDescription(strategy)}

{strategy === 'binary' ? `~${getOptimalGuesses()} questions` : strategy === 'linear' ? `~${Math.ceil(maxRange/2)} questions` : '? questions'}
))}
)}
)} {gameState === 'playing' && gameMode === 'user-guesses' && userGuessingMode === 'standard' && ( )} {gameState === 'playing' && gameMode === 'user-guesses' && userGuessingMode === 'questions' && ( )} {gameState === 'playing' && gameMode === 'computer-asks' && (

Think of a number between 1 and {maxRange}

Strategy: {computerStrategy.charAt(0).toUpperCase() + computerStrategy.slice(1)} Search

Score: {userScore} Remaining: {possibleNumbers.length}
{currentQuestion && (

{currentQuestion.text}

)} {questionsAsked.length > 0 && (

Questions Asked:

{questionsAsked.map((question, index) => (
{question}
))}
)}
)} {gameState === 'won' && (

Game Complete!

{gameMode === 'user-guesses' ? (

You found the number {secretNumber} in{' '} {guesses.length} guesses!

) : (

The computer identified your number using the{' '} {computerStrategy} search strategy!

Final Score: {userScore} points
{possibleNumbers.length === 1 && (

Your number was: {possibleNumbers[0]}

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