#include <Adafruit_NeoPixel.h>
#define PIN1 2
#define PIN2 3
#define PIN3 4
#define PIN4 5
#define NUM_LEDS 16
// Initialize LED rings
Adafruit_NeoPixel rings[] = {
Adafruit_NeoPixel(NUM_LEDS, PIN1, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUM_LEDS, PIN2, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUM_LEDS, PIN3, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUM_LEDS, PIN4, NEO_GRB + NEO_KHZ800)
};
const int buttons[] = {6, 7, 8, 12};
int currentGreenLED = -1, level = 1, successCount = 0, lives = 2;
unsigned long ledOnTime = 0;
bool gameStarted = false;
uint8_t r, g, b;
bool mistakeMade[4] = {false, false, false, false}; // Track mistakes for each ring
void setup() {
for (int i = 0; i < 4; i++) {
rings[i].begin();
rings[i].show();
pinMode(buttons[i], INPUT_PULLUP); // Set button pins as input with pull-up resistors
}
randomSeed(analogRead(0));
Serial.begin(9600);
welcomeSound();
flashMulticolorLEDs();
randomizeColor();
setSpeedSound(0);
}
void loop() {
if (!gameStarted) {
setAllRingsColor(255, 255, 255);
if (digitalRead(buttons[0]) == LOW) {
ledOnTime += 1000; // Increase LED on time
setSpeedSound(1);
delay(300);
}
if (digitalRead(buttons[1]) == LOW) {
gameStarted = true; // Start the game
if (ledOnTime == 0) ledOnTime = 2000;
delay(300);
}
return;
}
if (currentGreenLED == -1) {
resetRound();
currentGreenLED = random(0, 4); // Select a random ring
directionSound(currentGreenLED); // play target ring direction sound
setRingsColorExcept(currentGreenLED, r, g, b); // Set color for all rings except the selected one
unsigned long startTime = millis();
for (int i = 0; i < 4; i++) {
if (mistakeMade[i]) {
setRingMistakeColor(rings[i], 255, 0, 0); // Keep mistake LEDs red
}
}
while (millis() - startTime < ledOnTime) {
for (int i = 0; i < 4; i++) {
if (digitalRead(buttons[i]) == LOW) {
if (i == currentGreenLED) {
successCount++;
flashLED(rings[i], r, g, b); // Flash the correct LED
if (successCount >= 10) levelUp(); // Level up if enough successes
} else {
lives--;
mistakeMade[i] = true; // Mark mistake
wrongSound();
flashLED(rings[i], 255, 0, 0); // Flash red for mistake
if (lives == 0) {
gameOver(); // End game if no lives left
return;
}
}
resetRound();
return;
}
}
}
lives--;
mistakeMade[currentGreenLED] = true; // Mark mistake
flashLED(rings[currentGreenLED], 255, 0, 0); // Flash red for mistake
slowSound();
resetRound();
if (lives == 0) {
gameOver(); // End game if no lives left
return;
}
}
}
void flashLED(Adafruit_NeoPixel & ring, uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < 3; i++) {
setRingColor(ring, r, g, b);
delay(ledOnTime / 6);
setRingColor(ring, 0, 0, 0);
delay(ledOnTime / 6);
}
}
void levelUp() {
levelCompletedSound();
level++;
successCount = 0;
lives = 2;
ledOnTime = (ledOnTime * 80) / 100;
flashGreenLEDs();
randomizeColor();
memset(mistakeMade, false, sizeof(mistakeMade));
}
void flashGreenLEDs() {
flashColor(0, 255, 0);
}
void flashMulticolorLEDs() {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 4; j++) {
setRingColor(rings[j], random(0, 256), random(0, 256), random(0, 256));
}
delay(200);
setAllRingsColor(0, 0, 0);
delay(200);
}
}
void flashColor(uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < 5; i++) {
setAllRingsColor(r, g, b);
delay(200);
setAllRingsColor(0, 0, 0);
delay(200);
}
}
void gameOver() {
gameOverSound();
flashColor(255, 0, 0);
level = 1;
successCount = 0;
lives = 2;
ledOnTime = 0;
gameStarted = false;
memset(mistakeMade, false, sizeof(mistakeMade));
flashColor(255, 255, 255);
setAllRingsColor(255, 255, 255);
currentGreenLED = -1;
setSpeedSound(0);
}
void resetRound() {
for (int i = 0; i < 4; i++) {
if (mistakeMade[i]) {
setRingMistakeColor(rings[i], 255, 0, 0);
}
}
currentGreenLED = -1;
}
void setRingColor(Adafruit_NeoPixel & ring, uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < NUM_LEDS; i++) {
ring.setPixelColor(i, ring.Color(r, g, b));
}
ring.show();
}
void setRingMistakeColor(Adafruit_NeoPixel & ring, uint8_t r, uint8_t g, uint8_t b) {
ring.setPixelColor(0, ring.Color(r, g, b));
ring.setPixelColor(1, ring.Color(r, g, b));
ring.setPixelColor(15, ring.Color(r, g, b));
ring.show();
}
void setAllRingsColor(uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < 4; i++) {
setRingColor(rings[i], r, g, b);
}
}
void setRingsColorExcept(int exclude, uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < 4; i++) {
setRingColor(rings[i], (i == exclude) ? 0 : r, (i == exclude) ? 0 : g, (i == exclude) ? 0 : b);
}
}
void randomizeColor() {
r = random(75, 256);
g = random(75, 256);
b = random(75, 256);
}
// sound functions
void setSpeedSound(int i) {
switch (i) {
case 1:
Serial.println(String(ledOnTime / 1000) + " Second(s)");
return;
case 0:
Serial.println("Set starting Speed");
return;
}
}
void welcomeSound() {
Serial.println("Welcome");
}
void levelCompletedSound() {
Serial.println("Level Completed");
}
void wrongSound() {
Serial.println("Wrong");
}
void gameOverSound() {
Serial.println("Game Over");
}
void directionSound(int i) {
switch (i) {
case 0 : // Direction Right
Serial.println("Right");
return;
case 1 : // Direction UP
Serial.println("UP");
return;
case 2 : // Direction Down
Serial.println("Down");
return;
case 3 : // Direction Left
Serial.println("Left");
return;
}
}
void slowSound() {
Serial.println("Slow");
}