Spaces:
Sleeping
Sleeping
| import { useState, useEffect } from 'react' | |
| import './App.css' | |
| // Game question structure | |
| interface ComparisonQuestion { | |
| leftSide: string[]; | |
| rightSide: string[]; | |
| isEqual: boolean; | |
| secondStepQuestion: 'more' | 'fewer'; | |
| } | |
| // Game states | |
| type GameStep = 'step1' | 'step2' | 'correct-step1' | 'correct-step2'; | |
| function App() { | |
| const [currentQuestion, setCurrentQuestion] = useState<ComparisonQuestion | null>(null); | |
| const [gameStep, setGameStep] = useState<GameStep>('step1'); | |
| const [feedback, setFeedback] = useState(''); | |
| const [showFeedback, setShowFeedback] = useState(false); | |
| const [buttonLabels, setButtonLabels] = useState({ equal: 'Equal', notEqual: 'Not Equal' }); | |
| const [questionTitle, setQuestionTitle] = useState('Are they equal?'); | |
| // Emoji pools for different categories | |
| const emojiCategories = { | |
| animals: ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐸', '🐷'], | |
| fruits: ['🍎', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🫐', '🍒', '🥝'], | |
| objects: ['⚽', '🏀', '🎾', '🏈', '🎱', '🎪', '🎨', '🎭', '🎪', '🎯'], | |
| hearts: ['💙', '💚', '💛', '💜', '🤍', '🖤', '🤎', '💗', '💖', '💕'], | |
| stars: ['⭐', '🌟', '💫', '✨', '🌠', '⚡', '🔥', '❄️', '☀️', '🌙'] | |
| }; | |
| // Generate random button labels and question title | |
| const generateButtonLabels = () => { | |
| const equalOptions = ['Equal', 'Same']; | |
| const notEqualOptions = ['Not Equal', 'Different']; | |
| return { | |
| equal: equalOptions[Math.floor(Math.random() * equalOptions.length)], | |
| notEqual: notEqualOptions[Math.floor(Math.random() * notEqualOptions.length)] | |
| }; | |
| }; | |
| const generateQuestionTitle = () => { | |
| const titleOptions = ['Are they equal?', 'Are they same?']; | |
| return titleOptions[Math.floor(Math.random() * titleOptions.length)]; | |
| }; | |
| // Generate a random question | |
| const generateQuestion = (): ComparisonQuestion => { | |
| const categories = Object.keys(emojiCategories) as (keyof typeof emojiCategories)[]; | |
| const selectedCategory = categories[Math.floor(Math.random() * categories.length)]; | |
| const emojis = emojiCategories[selectedCategory]; | |
| // Pick a random emoji for this question | |
| const emoji = emojis[Math.floor(Math.random() * emojis.length)]; | |
| // Generate counts (1-10) | |
| const leftCount = Math.floor(Math.random() * 10) + 1; | |
| let rightCount = Math.floor(Math.random() * 10) + 1; | |
| // 50% chance of making them equal | |
| const shouldBeEqual = Math.random() < 0.5; | |
| if (shouldBeEqual) { | |
| rightCount = leftCount; | |
| } | |
| // Create arrays with repeated emoji | |
| const leftSide = Array(leftCount).fill(emoji); | |
| const rightSide = Array(rightCount).fill(emoji); | |
| // Determine second step question type | |
| const secondStepQuestion: 'more' | 'fewer' = Math.random() < 0.5 ? 'more' : 'fewer'; | |
| // Generate new button labels and question title for this question | |
| setButtonLabels(generateButtonLabels()); | |
| setQuestionTitle(generateQuestionTitle()); | |
| return { | |
| leftSide, | |
| rightSide, | |
| isEqual: leftCount === rightCount, | |
| secondStepQuestion | |
| }; | |
| }; | |
| // Initialize with first question | |
| useEffect(() => { | |
| setCurrentQuestion(generateQuestion()); | |
| }, []); | |
| // Safety effect: if we're in step 2 but sides are equal, generate new question | |
| useEffect(() => { | |
| if (currentQuestion && | |
| (gameStep === 'step2' || gameStep === 'correct-step2') && | |
| currentQuestion.leftSide.length === currentQuestion.rightSide.length) { | |
| // Generate new question and go back to step 1 | |
| setTimeout(() => { | |
| setCurrentQuestion(generateQuestion()); | |
| setGameStep('step1'); | |
| }, 1000); | |
| } | |
| }, [currentQuestion, gameStep]); | |
| // Handle step 1 answer (equal/not equal) | |
| const handleStep1Answer = (answer: 'equal' | 'not-equal') => { | |
| if (!currentQuestion) return; | |
| const isCorrect = (answer === 'equal') === currentQuestion.isEqual; | |
| if (isCorrect) { | |
| setFeedback('Correct! 🎉'); | |
| setShowFeedback(true); | |
| setGameStep('correct-step1'); | |
| // If they correctly identified as "equal", generate new question | |
| // If they correctly identified as "not equal", proceed to step 2 | |
| if (answer === 'equal') { | |
| // Generate new question after delay | |
| setTimeout(() => { | |
| setCurrentQuestion(generateQuestion()); | |
| setGameStep('step1'); | |
| setShowFeedback(false); | |
| setFeedback(''); | |
| }, 2000); | |
| } else { | |
| // Proceed to step 2 only if they are NOT equal | |
| setTimeout(() => { | |
| setGameStep('step2'); | |
| setShowFeedback(false); | |
| setFeedback(''); | |
| }, 1500); | |
| } | |
| } else { | |
| setFeedback('Try again! 🤔'); | |
| setShowFeedback(true); | |
| setTimeout(() => { | |
| setShowFeedback(false); | |
| setFeedback(''); | |
| }, 1000); | |
| } | |
| }; | |
| // Handle step 2 answer (more/fewer) | |
| const handleStep2Answer = (answer: 'left' | 'right') => { | |
| if (!currentQuestion) return; | |
| const leftCount = currentQuestion.leftSide.length; | |
| const rightCount = currentQuestion.rightSide.length; | |
| // Safety check: if sides are equal, this shouldn't happen in step 2 | |
| if (leftCount === rightCount) { | |
| // Generate new question and go back to step 1 | |
| setCurrentQuestion(generateQuestion()); | |
| setGameStep('step1'); | |
| return; | |
| } | |
| let isCorrect = false; | |
| if (currentQuestion.secondStepQuestion === 'more') { | |
| if (leftCount > rightCount && answer === 'left') isCorrect = true; | |
| if (rightCount > leftCount && answer === 'right') isCorrect = true; | |
| } else { // fewer | |
| if (leftCount < rightCount && answer === 'left') isCorrect = true; | |
| if (rightCount < leftCount && answer === 'right') isCorrect = true; | |
| } | |
| if (isCorrect) { | |
| setFeedback('Excellent! 🌟'); | |
| setShowFeedback(true); | |
| setGameStep('correct-step2'); | |
| // Generate new question after delay | |
| setTimeout(() => { | |
| setCurrentQuestion(generateQuestion()); | |
| setGameStep('step1'); | |
| setShowFeedback(false); | |
| setFeedback(''); | |
| }, 2000); | |
| } else { | |
| setFeedback('Try again! 🤔'); | |
| setShowFeedback(true); | |
| setTimeout(() => { | |
| setShowFeedback(false); | |
| setFeedback(''); | |
| }, 1000); | |
| } | |
| }; | |
| // Render emoji grid | |
| const renderEmojiSide = (emojis: string[], side: 'left' | 'right') => { | |
| const gridClass = `emoji-grid ${side}`; | |
| return ( | |
| <div className={gridClass}> | |
| {emojis.map((emoji, index) => ( | |
| <span key={index} className="emoji-item"> | |
| {emoji} | |
| </span> | |
| ))} | |
| </div> | |
| ); | |
| }; | |
| if (!currentQuestion) { | |
| return <div className="loading">Loading...</div>; | |
| } | |
| return ( | |
| <div className="equal-game"> | |
| {gameStep === 'step1' || gameStep === 'correct-step1' ? ( | |
| // Step 1: Are they equal? | |
| <> | |
| <h1 className="question-title">{questionTitle}</h1> | |
| <div className="comparison-container"> | |
| <div className="side-container"> | |
| {renderEmojiSide(currentQuestion.leftSide, 'left')} | |
| <div className="count-display">{currentQuestion.leftSide.length}</div> | |
| </div> | |
| <div className="vs-divider">VS</div> | |
| <div className="side-container"> | |
| {renderEmojiSide(currentQuestion.rightSide, 'right')} | |
| <div className="count-display">{currentQuestion.rightSide.length}</div> | |
| </div> | |
| </div> | |
| {gameStep === 'step1' && ( | |
| <div className="answer-buttons"> | |
| <button | |
| className="answer-btn equal-btn" | |
| onClick={() => handleStep1Answer('equal')} | |
| > | |
| {buttonLabels.equal} | |
| </button> | |
| <button | |
| className="answer-btn not-equal-btn" | |
| onClick={() => handleStep1Answer('not-equal')} | |
| > | |
| {buttonLabels.notEqual} | |
| </button> | |
| </div> | |
| )} | |
| </> | |
| ) : ( | |
| // Step 2: Which side has more/fewer? (Only if sides are NOT equal) | |
| currentQuestion.leftSide.length !== currentQuestion.rightSide.length ? ( | |
| <> | |
| <h1 className="question-title"> | |
| Which side has {currentQuestion.secondStepQuestion}? | |
| </h1> | |
| <div className="comparison-container"> | |
| <div className="side-container clickable" onClick={() => handleStep2Answer('left')}> | |
| {renderEmojiSide(currentQuestion.leftSide, 'left')} | |
| <div className="count-display">{currentQuestion.leftSide.length}</div> | |
| </div> | |
| <div className="vs-divider">VS</div> | |
| <div className="side-container clickable" onClick={() => handleStep2Answer('right')}> | |
| {renderEmojiSide(currentQuestion.rightSide, 'right')} | |
| <div className="count-display">{currentQuestion.rightSide.length}</div> | |
| </div> | |
| </div> | |
| <div className="step2-instruction"> | |
| Click on the side with {currentQuestion.secondStepQuestion} items | |
| </div> | |
| </> | |
| ) : ( | |
| // If somehow we get to step 2 with equal sides, generate new question | |
| <div className="loading">Generating new question...</div> | |
| ) | |
| )} | |
| {showFeedback && ( | |
| <div className="feedback-message"> | |
| {feedback} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |
| export default App; | |