/*
* Simon Says Memory Game
* 4 colored LEDs + buttons with sound feedback
* Increasing difficulty levels
*
* Hardware connections:
* - Red LED: Pin 2, Button: Pin 6
* - Green LED: Pin 3, Button: Pin 7
* - Blue LED: Pin 4, Button: Pin 8
* - Yellow LED: Pin 5, Button: Pin 9
* - Buzzer: Pin 10
*/
// Pin definitions
const int LED_PINS[] = {2, 3, 4, 5}; // Red, Green, Blue, Yellow LEDs
const int BUTTON_PINS[] = {6, 7, 8, 9}; // Corresponding buttons
const int BUZZER_PIN = 10;
// Tone frequencies for each color
const int TONES[] = {262, 330, 392, 494}; // C, E, G, B notes
// Game constants
const int MAX_SEQUENCE = 50;
const int INITIAL_SPEED = 500;
const int SPEED_DECREMENT = 20;
const int MIN_SPEED = 200;
// Game variables
int sequence[MAX_SEQUENCE];
int sequenceLength = 0;
int currentSpeed = INITIAL_SPEED;
int level = 1;
bool gameActive = false;
// Button debouncing
unsigned long lastDebounceTime[] = {0, 0, 0, 0};
const unsigned long debounceDelay = 50;
bool lastButtonState[] = {HIGH, HIGH, HIGH, HIGH};
void setup() {
Serial.begin(9600);
// Initialize LED pins as outputs
for (int i = 0; i < 4; i++) {
pinMode(LED_PINS[i], OUTPUT);
digitalWrite(LED_PINS[i], LOW);
}
// Initialize button pins as inputs with pullup
for (int i = 0; i < 4; i++) {
pinMode(BUTTON_PINS[i], INPUT_PULLUP);
}
// Initialize buzzer
pinMode(BUZZER_PIN, OUTPUT);
// Seed random number generator
randomSeed(analogRead(A0));
// Welcome sequence
welcomeAnimation();
Serial.println("Simon Says Memory Game");
Serial.println("Press any button to start!");
Serial.println("==========================");
}
void loop() {
if (!gameActive) {
// Wait for any button press to start
if (checkAnyButton()) {
startNewGame();
}
} else {
playRound();
}
}
void welcomeAnimation() {
// Flash all LEDs in sequence
for (int repeat = 0; repeat < 2; repeat++) {
for (int i = 0; i < 4; i++) {
digitalWrite(LED_PINS[i], HIGH);
tone(BUZZER_PIN, TONES[i], 150);
delay(150);
digitalWrite(LED_PINS[i], LOW);
delay(50);
}
}
// Flash all together
for (int i = 0; i < 4; i++) {
digitalWrite(LED_PINS[i], HIGH);
}
tone(BUZZER_PIN, 523, 300);
delay(300);
for (int i = 0; i < 4; i++) {
digitalWrite(LED_PINS[i], LOW);
}
noTone(BUZZER_PIN);
delay(500);
}
void startNewGame() {
sequenceLength = 0;
currentSpeed = INITIAL_SPEED;
level = 1;
gameActive = true;
Serial.println("\n>>> NEW GAME STARTED <<<");
Serial.println("Level 1");
delay(1000);
}
void playRound() {
// Add new color to sequence
addToSequence();
Serial.print("Round ");
Serial.print(sequenceLength);
Serial.print(" - Level ");
Serial.println(level);
// Show sequence to player
delay(1000);
playSequence();
// Get player input
if (getUserInput()) {
// Correct! Celebrate and continue
correctFeedback();
// Increase difficulty every 5 rounds
if (sequenceLength % 5 == 0) {
level++;
currentSpeed = max(MIN_SPEED, currentSpeed - SPEED_DECREMENT);
Serial.print(">>> LEVEL UP! Now at Level ");
Serial.println(level);
levelUpAnimation();
}
delay(1500);
} else {
// Wrong! Game over
gameOver();
}
}
void addToSequence() {
sequence[sequenceLength] = random(0, 4);
sequenceLength++;
}
void playSequence() {
for (int i = 0; i < sequenceLength; i++) {
int color = sequence[i];
// Light up LED and play tone
digitalWrite(LED_PINS[color], HIGH);
tone(BUZZER_PIN, TONES[color]);
delay(currentSpeed);
// Turn off
digitalWrite(LED_PINS[color], LOW);
noTone(BUZZER_PIN);
delay(200);
}
}
bool getUserInput() {
for (int i = 0; i < sequenceLength; i++) {
int expectedColor = sequence[i];
int pressedButton = waitForButtonPress();
if (pressedButton == -1) {
return false; // Timeout
}
// Light up the pressed button
digitalWrite(LED_PINS[pressedButton], HIGH);
tone(BUZZER_PIN, TONES[pressedButton], 200);
delay(200);
digitalWrite(LED_PINS[pressedButton], LOW);
noTone(BUZZER_PIN);
if (pressedButton != expectedColor) {
Serial.print("Wrong! Expected: ");
Serial.print(getColorName(expectedColor));
Serial.print(", Got: ");
Serial.println(getColorName(pressedButton));
return false;
}
delay(200);
}
return true;
}
int waitForButtonPress() {
unsigned long startTime = millis();
const unsigned long timeout = 5000; // 5 second timeout
while (millis() - startTime < timeout) {
for (int i = 0; i < 4; i++) {
int reading = digitalRead(BUTTON_PINS[i]);
if (reading != lastButtonState[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading == LOW) {
// Button pressed
while (digitalRead(BUTTON_PINS[i]) == LOW) {
delay(10); // Wait for release
}
lastButtonState[i] = HIGH;
return i;
}
}
lastButtonState[i] = reading;
}
}
Serial.println("Timeout!");
return -1; // Timeout
}
bool checkAnyButton() {
for (int i = 0; i < 4; i++) {
if (digitalRead(BUTTON_PINS[i]) == LOW) {
delay(300); // Debounce
while (digitalRead(BUTTON_PINS[i]) == LOW) {
delay(10);
}
return true;
}
}
return false;
}
void correctFeedback() {
Serial.println("✓ Correct!");
// Quick success sound
for (int i = 0; i < 3; i++) {
tone(BUZZER_PIN, 800, 100);
delay(150);
}
noTone(BUZZER_PIN);
}
void levelUpAnimation() {
// Celebratory light show
for (int repeat = 0; repeat < 3; repeat++) {
for (int i = 0; i < 4; i++) {
digitalWrite(LED_PINS[i], HIGH);
}
tone(BUZZER_PIN, 659, 200);
delay(200);
for (int i = 0; i < 4; i++) {
digitalWrite(LED_PINS[i], LOW);
}
delay(100);
}
noTone(BUZZER_PIN);
}
void gameOver() {
Serial.println("\n*** GAME OVER ***");
Serial.print("Final Score: ");
Serial.print(sequenceLength - 1);
Serial.print(" (Level ");
Serial.print(level);
Serial.println(")");
// Game over sound and animation
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
digitalWrite(LED_PINS[j], HIGH);
}
tone(BUZZER_PIN, 200, 300);
delay(300);
for (int j = 0; j < 4; j++) {
digitalWrite(LED_PINS[j], LOW);
}
delay(200);
}
noTone(BUZZER_PIN);
delay(1000);
Serial.println("\nPress any button to play again!");
gameActive = false;
}
String getColorName(int colorIndex) {
switch(colorIndex) {
case 0: return "Red";
case 1: return "Green";
case 2: return "Blue";
case 3: return "Yellow";
default: return "Unknown";
}
}