Spaces:
Sleeping
Sleeping
File size: 7,244 Bytes
0b49cb3 a432b46 671ec71 3e4b4c2 671ec71 a432b46 671ec71 0b49cb3 671ec71 0b49cb3 671ec71 0b49cb3 671ec71 3e4b4c2 0b49cb3 671ec71 0b49cb3 671ec71 0b49cb3 671ec71 0b49cb3 671ec71 0b49cb3 671ec71 0b49cb3 671ec71 0b49cb3 a432b46 0b49cb3 671ec71 3e4b4c2 0b49cb3 671ec71 a432b46 671ec71 a432b46 671ec71 0b49cb3 671ec71 0b49cb3 671ec71 a432b46 671ec71 a432b46 3e4b4c2 a432b46 3e4b4c2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | import { useState, useEffect } from 'react'
import './App.css'
// Define the types for the game
type DisplayMode = 'numbers' | 'objects' | 'both';
interface AdditionQuestion {
num1: number;
num2: number;
answer: number;
options: number[];
object1: string;
object2: string;
}
// Emoji pool
const emojis = ['🍎', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🫐', '🍒', '🥝', '🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐸', '🐷', '⚽', '🏀', '🎾', '🏈', '🎱', '🎨', '🎭', '🎯', '🚗', '🚕', '🚓', '🚑', '🚁', '🚀'];
function App() {
const [currentQuestion, setCurrentQuestion] = useState<AdditionQuestion | null>(null);
const [displayMode, setDisplayMode] = useState<DisplayMode>('numbers');
const [feedback, setFeedback] = useState('');
const [score, setScore] = useState(0);
// Generate a random number between min and max (inclusive)
const getRandomNumber = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
// Helper function to get an operand (0-5) with a reduced chance of it being 0
const getOperandWithReducedZero = (maxValue: number): number => {
const CHANCE_OF_BEING_ZERO = 0.10; // 10% chance the operand is 0
if (maxValue < 0) maxValue = 0; // Ensure maxValue is not negative
if (maxValue === 0) return 0; // If max is 0, operand must be 0
if (Math.random() < CHANCE_OF_BEING_ZERO) {
return 0;
} else {
// Generate a number from 1 to maxValue
return getRandomNumber(1, maxValue);
}
};
// Get a random emoji
const getRandomEmoji = () => {
return emojis[Math.floor(Math.random() * emojis.length)];
};
// Generate a new question
const generateQuestion = () => {
let num1, num2;
const MAX_OPERAND_VALUE = 5;
const MAX_SUM = 5;
do {
num1 = getOperandWithReducedZero(MAX_OPERAND_VALUE);
num2 = getOperandWithReducedZero(MAX_OPERAND_VALUE);
} while (num1 + num2 > MAX_SUM);
const answer = num1 + num2;
// Generate options, one of which is the correct answer
const options = new Set<number>();
options.add(answer);
while (options.size < 3) {
const option = getRandomNumber(0, 10); // Options can be up to 10
if (option !== answer) { // Ensure options are not trivially easy if sum is 0 or 1
options.add(option);
}
}
const object1 = getRandomEmoji();
let object2 = getRandomEmoji();
// Ensure objects are different if numbers are different, or if it's the same number, it's fine.
// This logic primarily ensures visual distinction when counts are different.
if (num1 > 0 && num2 > 0 && num1 !== num2) { // only ensure different emojis if counts are different and non-zero
while (object2 === object1) {
object2 = getRandomEmoji();
}
} else if (num1 > 0 && num2 > 0 && num1 === num2) { // if numbers are same and non-zero, make sure emojis are same for clarity
object2 = object1;
}
setCurrentQuestion({
num1,
num2,
answer,
options: Array.from(options).sort(() => Math.random() - 0.5), // Shuffle options
object1,
object2,
});
setFeedback('');
};
useEffect(() => {
generateQuestion();
}, []);
// Handle answer submission
const handleAnswer = (selectedOption: number) => {
if (currentQuestion && selectedOption === currentQuestion.answer) {
setFeedback('Correct! 🎉');
setScore(score + 1);
setTimeout(() => {
generateQuestion();
}, 1500);
} else if (currentQuestion) { // Added currentQuestion check here
setFeedback('Try again! 🤔');
setTimeout(() => {
setFeedback('');
}, 1000);
}
};
if (!currentQuestion) {
return <div className="loading">Loading game...</div>;
}
const { num1, num2, answer, options, object1, object2 } = currentQuestion;
// const sumObject = object1; // No longer needed as sum is not displayed with objects here
return (
<div className="app-container">
<header className="game-header">
<h1>Addition Game</h1>
<div className="display-mode-selector">
<button onClick={() => setDisplayMode('numbers')} className={displayMode === 'numbers' ? 'active' : ''}>Number</button>
<button onClick={() => setDisplayMode('objects')} className={displayMode === 'objects' ? 'active' : ''}>Object</button>
<button onClick={() => setDisplayMode('both')} className={displayMode === 'both' ? 'active' : ''}>Both</button>
</div>
<div className="score-display">Score: {score}</div>
</header>
<main className="game-area">
<div className="question-container-new">
{/* Operand 1 Column */}
<div className="operand-column">
{(displayMode === 'numbers' || displayMode === 'both') && (
<div className="number-box">
<span className="number-text">{num1}</span>
</div>
)}
{(displayMode === 'objects' || displayMode === 'both') && (
<div className="objects-display">
{Array(num1).fill(null).map((_, i) => (
<span key={`obj1-${i}`} className="item-object">{object1}</span>
))}
</div>
)}
{/* If only objects mode and num1 is 0, show nothing or a placeholder if desired*/}
{displayMode === 'objects' && num1 === 0 && <div className="objects-display" style={{minHeight: '4rem'}}></div>}
</div>
{/* Operator + Column */}
<div className="operator-cell">
<span className="operator-symbol">+</span>
</div>
{/* Operand 2 Column */}
<div className="operand-column">
{(displayMode === 'numbers' || displayMode === 'both') && (
<div className="number-box">
<span className="number-text">{num2}</span>
</div>
)}
{(displayMode === 'objects' || displayMode === 'both') && (
<div className="objects-display">
{Array(num2).fill(null).map((_, i) => (
<span key={`obj2-${i}`} className="item-object">{object2}</span>
))}
</div>
)}
{displayMode === 'objects' && num2 === 0 && <div className="objects-display" style={{minHeight: '4rem'}}></div>}
</div>
{/* Operator = Column */}
<div className="operator-cell">
<span className="operator-symbol">=</span>
</div>
{/* Result Column - Now displays a question mark */}
<div className="result-column">
<span className="answer-placeholder-new">?</span>
</div>
</div>
<div className="options-container">
{options.map((option) => (
<button key={option} onClick={() => handleAnswer(option)} className="option-button">
{option}
</button>
))}
</div>
{feedback && <div className="feedback-message">{feedback}</div>}
</main>
</div>
);
}
export default App;
|