Loading challenge...
Preparing the challenge details...
Loading challenge...
Preparing the challenge details...
Build the classic Simon Says memory game in React with color sequence generation, player input validation, sound effects, increasing difficulty, and high score tracking.
Build a Simon Says game where players must repeat sequences of colored pads. The key challenges are generating random sequences, playing sequences with visual feedback, validating user input, and managing game state transitions. This classic memory game is perfect for practicing async/await patterns in React.
A Simon Says game displays a 3×3 grid of 9 colored pads. The game plays a sequence of colors, and players must repeat the sequence by clicking the pads in the correct order. Each round adds one more color to the sequence, making it progressively harder. The game ends when the player makes a mistake.
The game uses 9 colors arranged in a 3×3 grid:
TSXcomponent.tsx1const COLORS = ["green", "red", "yellow", "blue", "purple", "orange", "pink", "brown", "gray"]; 2 3const getRandomColor = () => 4 COLORS[Math.floor(Math.random() * COLORS.length)];
How it works:
COLORS array defines all available colorsgetRandomColor() selects a random color from the arrayThe implementation uses a single component with state-driven game flow:
TSXcomponent.tsx1const SimonSays = () => { 2 const [sequence, setSequence] = useState<string[]>([]); 3 const [userSequence, setUserSequence] = useState<string[]>([]); 4 const [activeColor, setActiveColor] = useState<string | null>(null); 5 const [isUserTurn, setIsUserTurn] = useState(false); 6 const [level, setLevel] = useState(0); 7 const [isPlaying, setIsPlaying] = useState(false); 8 9 const timeoutRef = useRef<number | null>(null); 10};
State Management:
sequence: The complete sequence the player must repeat (grows each round)userSequence: The colors the player has clicked so faractiveColor: Currently flashing color (for visual feedback)isUserTurn: Whether player can click padslevel: Current level (equals sequence length)isPlaying: Whether game is activetimeoutRef: Stores timeout ID for cleanup (using useRef)The game follows a sequence-play-input-validation pattern:
TSXcomponent.tsx1const startGame = () => { 2 resetGame(); 3 setIsPlaying(true); 4 nextRound([]); 5};
Flow:
Each round adds one color to the sequence:
TSXcomponent.tsx1const nextRound = (prevSequence: string[]) => { 2 const next = [...prevSequence, getRandomColor()]; 3 setSequence(next); 4 setLevel(next.length); 5 playSequence(next); 6};
How it works:
Example progression:
["green"] (level 1)["green", "red"] (level 2)["green", "red", "blue"] (level 3)The game plays the sequence with visual flashes:
TSXcomponent.tsx1const playSequence = async (seq: string[]) => { 2 setIsUserTurn(false); // Disable clicks during playback 3 4 for (let i = 0; i < seq.length; i++) { 5 await flash(seq[i]); 6 } 7 8 setUserSequence([]); // Reset user input 9 setIsUserTurn(true); // Enable clicks 10};
Flow:
isUserTurn = false)isUserTurn = true)Why async/await?
Each color flashes with timing:
TSXcomponent.tsx1const flash = (color: string) => { 2 return new Promise<void>((resolve) => { 3 setActiveColor(color); // Show color 4 5 timeoutRef.current = window.setTimeout(() => { 6 setActiveColor(null); // Hide color 7 8 timeoutRef.current = window.setTimeout(() => { 9 resolve(); // Continue to next color 10 }, 200); 11 }, 500); 12 }); 13};
Timing breakdown:
Visual effect:
When player clicks a pad, it flashes briefly:
TSXcomponent.tsx1const flashUserClick = (color: string) => { 2 setActiveColor(color); 3 if (timeoutRef.current) clearTimeout(timeoutRef.current); 4 timeoutRef.current = window.setTimeout(() => { 5 setActiveColor(null); 6 }, 200); 7};
Features:
activeColor state as sequence playbackPlayer clicks are validated against the sequence:
TSXcomponent.tsx1const handleClick = (color: string) => { 2 if (!isUserTurn) return; // Ignore clicks during sequence playback 3 4 flashUserClick(color); // Visual feedback 5 6 const nextInput = [...userSequence, color]; 7 setUserSequence(nextInput); 8 9 const currentIndex = nextInput.length - 1; 10 11 // Wrong input 12 if (sequence[currentIndex] !== color) { 13 gameOver(); 14 return; 15 } 16 17 // Completed round 18 if (nextInput.length === sequence.length) { 19 setIsUserTurn(false); 20 setTimeout(() => { 21 nextRound(sequence); 22 }, 800); 23 } 24};
Validation logic:
Example:
["green", "red", "blue"]["green", "red"] ✓["green", "red", "yellow"] ✗ (game over)When player makes a mistake:
TSXcomponent.tsx1const gameOver = () => { 2 alert("Game Over"); 3 resetGame(); 4 setIsPlaying(false); 5};
Actions:
Resets all state to initial values:
TSXcomponent.tsx1const resetGame = () => { 2 if (timeoutRef.current) clearTimeout(timeoutRef.current); 3 setSequence([]); 4 setUserSequence([]); 5 setActiveColor(null); 6 setIsUserTurn(false); 7 setLevel(0); 8};
Cleanup:
The game uses CSS Grid for the 3×3 pad layout:
CSSstyles.css1.board { 2 display: grid; 3 grid-template-columns: repeat(3, 120px); 4 gap: 16px; 5 justify-content: center; 6 margin-top: 20px; 7}
Features:
Each pad has base styling and active state:
CSSstyles.css1.pad { 2 width: 120px; 3 height: 120px; 4 border-radius: 12px; 5 opacity: 0.6; 6 cursor: pointer; 7 transition: opacity 0.15s ease, transform 0.1s ease; 8} 9 10.pad.active { 11 opacity: 1; 12 transform: scale(1.08); 13 box-shadow: 0 0 20px rgba(255,255,255,0.6); 14}
Visual states:
Color classes: Each color has its own background class:
.green, .red, .yellow, .blue, .purple, .orange, .pink, .brown, .grayasync/await with Promise to flash colors sequentiallysequence (game's sequence) and userSequence (player's input)isUserTurn to control when player can interactThe beauty of this implementation is its clear separation of concerns. The sequence playback is completely separate from user input validation. The async/await pattern creates smooth, sequential animations. The turn-based system (isUserTurn) ensures players can't click during sequence playback, preventing confusion and errors.
The progressive difficulty (one color per round) creates an engaging challenge that scales naturally. The visual feedback system provides clear indication of both game actions and player actions, making the game intuitive and satisfying to play.
Goal: Implement a Simon Says game component with sequence generation and player input validation.
Continue learning with these related challenges

Build a fun Whack-a-Mole game in React with random mole spawning, click detection, score tracking, countdown timer, and increasing difficulty levels. Perfect for React practice.

Create a card-matching memory game in React with flip animations, pair detection logic, move counter, timer, and win condition handling. A classic frontend coding challenge.

Create an interactive image carousel in React with smooth slide transitions, navigation arrows, dot indicators, autoplay, and touch/swipe support for mobile devices.

Build a fun Whack-a-Mole game in React with random mole spawning, click detection, score tracking, countdown timer, and increasing difficulty levels. Perfect for React practice.

Create a card-matching memory game in React with flip animations, pair detection logic, move counter, timer, and win condition handling. A classic frontend coding challenge.

Create an interactive image carousel in React with smooth slide transitions, navigation arrows, dot indicators, autoplay, and touch/swipe support for mobile devices.