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; | |