Introduction
Remember the classic Simon Says game? It’s the perfect project to learn about arrays, state machines, and user input handling on Arduino. In this tutorial, we’ll build a fully functional Simon Says game using four LEDs and four pushbuttons, all simulated right in your browser with Velxio. No hardware needed!

Circuit Walkthrough
Let’s look at the components and how they’re connected.
Components
| Component | ID | Purpose |
|---|---|---|
| Arduino Uno | arduino-uno | The brain of the game |
| Red LED | led-red | Output for red sequence |
| Green LED | led-green | Output for green sequence |
| Blue LED | led-blue | Output for blue sequence |
| Yellow LED | led-yellow | Output for yellow sequence |
| Red Button | button-red | User input for red |
| Green Button | button-green | User input for green |
| Blue Button | button-blue | User input for blue |
| Yellow Button | button-yellow | User input for yellow |
Wiring
Each LED’s anode (A) connects to a digital pin on the Arduino, and its cathode (C) goes to GND through a current-limiting resistor (simulated internally). The buttons are wired with one leg (1.l) to a digital pin and the other leg (2.l) to GND, using the Arduino’s internal pull-up resistors.
- Red LED: Pin 8 (red wire) to anode, cathode to GND (black wire).
- Green LED: Pin 9 (green wire) to anode, cathode to GND.
- Blue LED: Pin 10 (blue wire) to anode, cathode to GND.
- Yellow LED: Pin 11 (yellow wire) to anode, cathode to GND.
- Red Button: Pin 2 (light blue wire) to 1.l, 2.l to GND.
- Green Button: Pin 3 (light blue wire) to 1.l, 2.l to GND.
- Blue Button: Pin 4 (light blue wire) to 1.l, 2.l to GND.
- Yellow Button: Pin 5 (light blue wire) to 1.l, 2.l to GND.
All ground connections share the Arduino’s GND pin.
Code Walkthrough
Open the code editor in Velxio to see the full sketch.

Constants and Variables
const int LED_PINS[] = {8, 9, 10, 11};
const int BUTTON_PINS[] = {2, 3, 4, 5};
const int NUM_LEDS = 4;
int sequence[100];
int sequenceLength = 0;
int currentStep = 0;
We define arrays for LED and button pins, matching the wiring. sequence stores the random pattern (up to 100 steps). sequenceLength tracks how many steps the player must repeat, and currentStep tracks the player’s progress.
Setup
void setup() {
Serial.begin(9600);
for (int i = 0; i < NUM_LEDS; i++) {
pinMode(LED_PINS[i], OUTPUT);
pinMode(BUTTON_PINS[i], INPUT_PULLUP);
}
randomSeed(millis());
newGame();
}
We set LED pins as outputs and button pins as inputs with internal pull-ups (so buttons read LOW when pressed). randomSeed(millis()) ensures a different sequence each game. newGame() starts the first round.
Game Logic
newGame() resets the sequence length to 1, adds a random step, and plays the sequence.
void newGame() {
sequenceLength = 1;
currentStep = 0;
addToSequence();
playSequence();
}
void addToSequence() {
sequence[sequenceLength - 1] = random(0, NUM_LEDS);
}
void playSequence() {
for (int i = 0; i < sequenceLength; i++) {
flashLED(sequence[i]);
delay(500);
}
}
void flashLED(int led) {
digitalWrite(LED_PINS[led], HIGH);
delay(300);
digitalWrite(LED_PINS[led], LOW);
}
playSequence() iterates through the stored sequence, flashing each LED for 300ms with a 500ms gap.
Main Loop
void loop() {
for (int i = 0; i < NUM_LEDS; i++) {
if (digitalRead(BUTTON_PINS[i]) == LOW) {
flashLED(i);
if (i == sequence[currentStep]) {
currentStep++;
if (currentStep == sequenceLength) {
delay(1000);
sequenceLength++;
currentStep = 0;
addToSequence();
playSequence();
}
} else {
// Wrong button - game over
for (int j = 0; j < 3; j++) {
for (int k = 0; k < NUM_LEDS; k++) {
digitalWrite(LED_PINS[k], HIGH);
}
delay(200);
for (int k = 0; k < NUM_LEDS; k++) {
digitalWrite(LED_PINS[k], LOW);
}
delay(200);
}
newGame();
}
delay(300);
while (digitalRead(BUTTON_PINS[i]) == LOW);
}
}
}
The loop continuously checks all buttons. When a button is pressed (LOW), it flashes the corresponding LED. If the pressed button matches the expected step (sequence[currentStep]), we advance. If the player completes the sequence, we add a new step and play the longer sequence. If wrong, all LEDs flash three times and a new game starts.
Key Concepts
- Arrays: Using arrays to store pin numbers and the game sequence makes the code scalable and clean.
- Internal Pull-up Resistors:
INPUT_PULLUPeliminates external resistors; buttons read LOW when pressed. - Debouncing: The
delay(300)andwhile(digitalRead(...)==LOW)loop provide simple debouncing. - Randomness:
randomSeed(millis())andrandom()generate unpredictable sequences. - State Machine: The game tracks
currentStepandsequenceLengthto manage progress.
Common Pitfalls & Debugging Tips
- Buttons not responding? Check that the button pins are set to
INPUT_PULLUPand wired correctly (1.l to pin, 2.l to GND). - LEDs not lighting? Verify the LED pins are
OUTPUTand the anode/cathode connections are correct. - Sequence too fast? Adjust
delay()values inflashLED()andplaySequence(). - Game resets unexpectedly? Ensure
randomSeed(millis())is called only once insetup(). - Use Serial Monitor: Add
Serial.println()statements to debug sequence values.
Suggested Extensions
- Add a buzzer: Play a tone for each LED color.
- Difficulty levels: Increase speed as the sequence grows.
- High score: Track the longest sequence achieved.
- Multiplayer: Alternate turns between two players.
- Visual feedback: Use different LED brightness or patterns.
Try It Yourself!
Ready to play? Open the live example on Velxio and start the simulation. Press the buttons to repeat the sequence. How far can you go?
Happy building!