equal-2-step / src /App.tsx
elyor-ml's picture
add same different
c133828
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;