Simon Says Memory Game with Arduino Uno
Build the classic Simon Says memory game with Arduino Uno, four coloured LEDs, four push buttons, and a passive buzzer. Covers random seed with ADC noise, tone frequencies, game-over logic, and EEPROM high-score storage.
How Simon Works
The game generates a random sequence of colour flashes, one longer each round. After each display the player must reproduce the exact sequence by pressing the matching buttons. One wrong press ends the game — the board shows your score and compares it to the stored high score in EEPROM.
The classic difficulty curve:
- Level 1–4: 600 ms flash, 100 ms gap
- Level 5–9: 400 ms flash, 80 ms gap
- Level 10+: 250 ms flash, 60 ms gap
Components required
Pin Mapping
| Colour | LED Pin | Button Pin | Tone (Hz) | |--------|---------|------------|-----------| | Red | D5 | D9 | 262 (C4) | | Green | D6 | D10 | 330 (E4) | | Blue | D7 | D11 | 392 (G4) | | Yellow | D8 | D12 | 523 (C5) |
Passive buzzer positive → D4.
// ── Simon Says — Arduino Uno ──────────────────────────────────────────────────
#include <EEPROM.h>
// ── Pin tables ────────────────────────────────────────────────────────────────
const int LED_PINS[] = {5, 6, 7, 8};
const int BTN_PINS[] = {9, 10, 11, 12};
const int TONES[] = {262, 330, 392, 523};
const int BUZZER = 4;
const int NUM_COLOURS = 4;
// ── Game state ────────────────────────────────────────────────────────────────
int sequence[100];
int level = 0;
const int EEPROM_ADDR = 0; // High score stored here
// ── Helpers ───────────────────────────────────────────────────────────────────
void lightUp(int colour, int ms) {
digitalWrite(LED_PINS[colour], HIGH);
tone(BUZZER, TONES[colour], ms);
delay(ms);
digitalWrite(LED_PINS[colour], LOW);
noTone(BUZZER);
}
void gameOverEffect() {
for (int i = 0; i < 3; i++) {
for (int c = 0; c < NUM_COLOURS; c++) digitalWrite(LED_PINS[c], HIGH);
tone(BUZZER, 150, 200);
delay(200);
for (int c = 0; c < NUM_COLOURS; c++) digitalWrite(LED_PINS[c], LOW);
delay(200);
}
}
int waitForButton(unsigned long timeoutMs) {
unsigned long start = millis();
while (millis() - start < timeoutMs) {
for (int i = 0; i < NUM_COLOURS; i++) {
if (digitalRead(BTN_PINS[i]) == HIGH) {
while (digitalRead(BTN_PINS[i]) == HIGH); // wait release
return i;
}
}
}
return -1; // timeout
}
void setup() {
// Seed from floating ADC pin for true randomness
randomSeed(analogRead(A0) * analogRead(A1));
for (int i = 0; i < NUM_COLOURS; i++) {
pinMode(LED_PINS[i], OUTPUT);
pinMode(BTN_PINS[i], INPUT);
}
pinMode(BUZZER, OUTPUT);
Serial.begin(9600);
// Startup animation
for (int i = 0; i < NUM_COLOURS; i++) { lightUp(i, 150); delay(50); }
}
void loop() {
level = 0;
// ── Build and play the sequence ───────────────────────────────────────────
while (true) {
sequence[level] = random(NUM_COLOURS);
level++;
// Speed curve
int flashMs = (level <= 4) ? 600 : (level <= 9) ? 400 : 250;
int gapMs = (level <= 4) ? 100 : (level <= 9) ? 80 : 60;
delay(600);
for (int i = 0; i < level; i++) {
lightUp(sequence[i], flashMs);
delay(gapMs);
}
// ── Player input ──────────────────────────────────────────────────────
for (int i = 0; i < level; i++) {
int pressed = waitForButton(4000);
if (pressed == -1 || pressed != sequence[i]) {
// Wrong or timeout → game over
Serial.print("Game over at level: ");
Serial.println(level);
gameOverEffect();
int hiScore = EEPROM.read(EEPROM_ADDR);
if (level > hiScore) {
EEPROM.write(EEPROM_ADDR, level);
Serial.println("New high score!");
// Celebrate
for (int c = 0; c < NUM_COLOURS; c++) { lightUp(c, 200); }
}
return; // Restart
}
lightUp(pressed, 200);
delay(80);
}
Serial.print("Level cleared: ");
Serial.println(level);
}
}