In this capstone you build a complete game: the classic memory game where the machine shows a pattern of lights and sounds, and you have to repeat it. Each round adds one more step and the game gets faster. Four LEDs stand for up, right, down and left, and you answer by pushing the joystick in the same direction. Your best score is stored in the UNO's permanent memory, so it's still there after you unplug it.
What you'll learn
- How to store a growing sequence in an array
- How to turn two analog joystick readings into four directions
- How to play notes with a passive buzzer and
tone() - How to keep a value in EEPROM when the power is off
What you need
- UNO R3 board and USB cable (UNO R3 Starter Kit)
- Joystick module (UNO R3 Starter Kit)
- Red, yellow, green and white LEDs and 4 resistors, 220 Ω (UNO R3 Starter Kit)
- Passive buzzer module (45-in-1 Sensor Kit)
- Breadboard and jumper wires (UNO R3 Starter Kit)
Wiring
Place the four LEDs in a row. Later you can bend their legs or use longer wires to arrange them as a cross: up, right, down, left.

| From | To |
|---|---|
| Joystick GND | GND |
| Joystick +5V | 5V |
| Joystick VRx | UNO pin A0 |
| Joystick VRy | UNO pin A1 |
| Joystick SW | UNO pin 7 |
| UNO pin 2 | 220 Ω resistor, then the red LED's long leg (up) |
| UNO pin 3 | 220 Ω resistor, then the yellow LED's long leg (right) |
| UNO pin 4 | 220 Ω resistor, then the green LED's long leg (down) |
| UNO pin 5 | 220 Ω resistor, then the white LED's long leg (left) |
| All LED short legs | GND |
| Passive buzzer module S | UNO pin 8 |
| Passive buzzer module − | GND |
Sensor modules from different makers can label and order their pins differently. Always follow the labels printed on your module.
How to play
- After power-up the four LEDs chase each other. Press the joystick down (it clicks) to start.
- Watch and listen: the game shows the pattern.
- Repeat the pattern by pushing the joystick in each direction and letting it spring back.
- A correct answer adds one more step. A wrong direction, or waiting longer than five seconds, ends the game.
- The LEDs blink once for each point you scored. A new record plays a short tune.
The sketch
#include <EEPROM.h>
const int LED_PINS[4] = {2, 3, 4, 5}; // up, right, down, left
const int NOTES[4] = {262, 330, 392, 523}; // one note per direction (Hz)
const int BUZZER_PIN = 8;
const int X_PIN = A0;
const int Y_PIN = A1;
const int SW_PIN = 7;
const int MAX_STEPS = 50;
byte pattern[MAX_STEPS];
byte highScore = 0;
// Returns 0 = up, 1 = right, 2 = down, 3 = left, -1 = joystick in the middle
int readDirection() {
int x = analogRead(X_PIN);
int y = analogRead(Y_PIN);
if (y < 250) return 0;
if (x > 770) return 1;
if (y > 770) return 2;
if (x < 250) return 3;
return -1;
}
void show(int direction, int ms) {
digitalWrite(LED_PINS[direction], HIGH);
tone(BUZZER_PIN, NOTES[direction]);
delay(ms);
digitalWrite(LED_PINS[direction], LOW);
noTone(BUZZER_PIN);
}
// Waits up to 5 seconds for a push. Returns the direction, or -1 if time runs out.
int waitForMove() {
unsigned long start = millis();
while (millis() - start < 5000) {
int direction = readDirection();
if (direction >= 0) {
digitalWrite(LED_PINS[direction], HIGH);
tone(BUZZER_PIN, NOTES[direction]);
while (readDirection() != -1) delay(10); // wait until the stick is released
delay(80);
digitalWrite(LED_PINS[direction], LOW);
noTone(BUZZER_PIN);
return direction;
}
}
return -1;
}
void allLeds(bool on) {
for (int i = 0; i < 4; i++) digitalWrite(LED_PINS[i], on);
}
// Plays one game and returns the score
int playGame() {
int steps = 0;
while (steps < MAX_STEPS) {
pattern[steps] = random(4); // add one new step
steps++;
int speed = max(150, 500 - steps * 25); // each round is a little faster
for (int i = 0; i < steps; i++) {
show(pattern[i], speed);
delay(speed / 3);
}
for (int i = 0; i < steps; i++) {
if (waitForMove() != pattern[i]) return steps - 1; // wrong or too slow
}
delay(700);
}
return MAX_STEPS;
}
void setup() {
Serial.begin(9600);
for (int i = 0; i < 4; i++) pinMode(LED_PINS[i], OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(SW_PIN, INPUT_PULLUP);
randomSeed(analogRead(A5)); // a different pattern every time
highScore = EEPROM.read(0);
if (highScore > MAX_STEPS) highScore = 0; // a new chip contains 255
Serial.print(F("High score: "));
Serial.println(highScore);
}
void loop() {
// Attract mode: chase the LEDs until the joystick is pressed
int i = 0;
while (digitalRead(SW_PIN) == HIGH) {
digitalWrite(LED_PINS[i], HIGH);
delay(120);
digitalWrite(LED_PINS[i], LOW);
i = (i + 1) % 4;
}
delay(800);
int score = playGame();
Serial.print(F("Score: "));
Serial.println(score);
tone(BUZZER_PIN, 131, 600); // low "game over" note
delay(900);
for (int n = 0; n < score; n++) { // one blink per point
allLeds(true);
delay(180);
allLeds(false);
delay(180);
}
if (score > highScore) {
highScore = score;
EEPROM.write(0, highScore); // survives without power
Serial.println(F("New high score!"));
for (int n = 0; n < 3; n++) {
for (int d = 0; d < 4; d++) show(d, 90);
}
}
delay(1000);
}
How it works
The pattern lives in the array pattern. Each round, random(4) picks a number from 0 to 3 and stores it in the next free place. The game then replays the whole array from the start and checks your answers against it one by one. The old steps never change, which is why the pattern grows instead of being new each time.
The joystick is two potentiometers at right angles. In the middle, both read about 512. The sketch treats a reading below 250 or above 770 as a clear push and ignores everything in between, so small movements don't count. waitForMove() also waits for the stick to return to the middle before it accepts the next answer; otherwise one long push would count several times.
Computers can't produce truly random numbers by themselves. randomSeed(analogRead(A5)) reads the electrical noise on an unconnected pin and uses it as the starting point, so the pattern is different every time you play.
EEPROM is a small memory inside the UNO that keeps its contents without power. EEPROM.write(0, highScore) stores one byte at address 0. Each EEPROM cell can be rewritten about 100,000 times, so the sketch writes only when there's a new record.
Try this next
- Make the joystick button during a game repeat the pattern once, as a "hint" that costs a point.
- Hold the joystick button while plugging in to reset the high score to zero.
- Add a two-player mode: players take turns, and each one adds a step of their own.
- Show the score on the 4-digit display from the stopwatch project.
Troubleshooting
-
The wrong LED lights when you push the joystick: your joystick is turned differently. Either turn the module, or reorder the four pin numbers in
LED_PINSuntil the directions match. -
Up and down are swapped: swap
y < 250andy > 770inreadDirection(). Do the same with x for left and right. - The game starts by itself: check the SW wire on pin 7.
- No sound: make sure you're using the passive buzzer module. An active buzzer only makes one fixed tone.
- The pattern is the same after every restart: something is connected to A5. Leave that pin empty.