#include <Arduino.h>
#include <Bounce2.h>
#include <Adafruit_NeoPixel.h>
#define DEBUG
//#define GAME_DEBUG
// #define BUTTON_DEBUG
// #define BLINK_DEBUG
#define INITIAL_STATE LOW
#define NUM_LEDS 7
#define NEOPIXEL_PIN 23
#define NUM_NEOPIXELS 16
#define MAX_LEVEL 3
Adafruit_NeoPixel ring = Adafruit_NeoPixel(NUM_NEOPIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
const byte startButtonPin = A8;
const byte repeatLedPin = 9;
struct INFOS
{
const byte buttonPin;
const byte ledPin;
};
INFOS info[NUM_LEDS] =
{
{A0, 2},
{A1, 3},
{A2, 4},
{A3, 5},
{A4, 6},
{A5, 7},
{A6, 8}
};
Bounce2::Button button[NUM_LEDS] = {Bounce2::Button()};
Bounce2::Button startButton = Bounce2::Button();
uint8_t sequence[NUM_LEDS] = {0, 1, 2, 3, 4, 5, 6};
byte sequenceIndex = 0;
byte level = 1;
byte numShowSequence = 1; // Number of times to show sequence for the player
byte numLedsPerSequence = 4; // Amount of LEDs that will blink in sequence
bool gameStarted = false;
bool startTimer = false;
unsigned long levelMillis = 0;
unsigned long ledMillis = 0;
byte countLed = 0;
byte max_level_time = 8; // Time in seconds
void checkInput(byte i);
void showSequence();
void newGame();
void swapEntries(byte a, byte b);
void rainbowCycle(int wait);
int32_t Wheel(byte WheelPos);
#ifdef DEBUG
#define LOG(...) Serial.print(__VA_ARGS__)
#define LOGLN(...) Serial.println(__VA_ARGS__)
#else
#define LOG(...)
#define LOGLN(...)
#endif
void printDebug(byte i)
{
LOG("Button ");
LOG(i);
LOG(" pressed!");
}
void setup()
{
Serial.begin(9600);
startButton.attach(startButtonPin, INPUT_PULLUP);
startButton.setPressedState(LOW);
startButton.interval(5);
for (byte i = 0; i < NUM_LEDS; i++)
{
button[i].attach(info[i].buttonPin, INPUT_PULLUP);
button[i].setPressedState(LOW);
button[i].interval(5);
pinMode(info[i].ledPin, OUTPUT);
digitalWrite(info[i].ledPin, INITIAL_STATE);
}
pinMode(repeatLedPin, OUTPUT);
digitalWrite(repeatLedPin, INITIAL_STATE);
ring.begin();
ring.show();
LOGLN("Press start for new game.");
}
void loop()
{
if(gameStarted == false)
{
startButton.update();
if(startButton.pressed())
{
newGame();
}
}
else
{
for (byte i = 0; i < NUM_LEDS; i++)
{
button[i].update();
if (button[i].pressed())
{
digitalWrite(info[i].ledPin, HIGH);
checkInput(i);
#ifdef BUTTON_DEBUG
printDebug(i);
#endif
break;
}
}
}
if((startTimer == true) && (gameStarted == true))
{
if((millis() - levelMillis) < (max_level_time * 1000UL))
{
if((millis() - ledMillis) >= ((max_level_time * 1000UL) / NUM_NEOPIXELS))
{
ring.setPixelColor(countLed, ring.Color(255, 128, 0));
ring.show();
countLed++;
ledMillis = millis();
}
}
else
{
gameStarted = false;
startTimer = false;
countLed = 0;
LOGLN("\nYOU LOSE!\nPress start for new game.");
digitalWrite(repeatLedPin, LOW);
for (byte i = 0; i < NUM_LEDS; i++)
{
digitalWrite(info[i].ledPin, LOW);
}
for (byte i = 0; i < ring.numPixels(); i++)
{
ring.setPixelColor(i, ring.Color(255, 0, 0));
ring.show();
delay(100);
}
delay(2000);
ring.clear();
ring.show();
}
}
}
void newGame()
{
LOGLN("Starting new game...");
delay(2000);
gameStarted = true;
level = 1;
sequenceIndex = 0;
countLed = 0;
startTimer = false;
showSequence();
}
void showSequence()
{
LOG("Current level: ");
LOGLN(level);
for (int i = 0; i < 10; i++) // Perform 10 swaps
{
randomSeed(micros());
swapEntries(random(0, NUM_LEDS), random(0, NUM_LEDS)); // perform 10 swaps
}
#ifdef GAME_DEBUG
LOG("Seq. = [");
for(byte i = 0; i < numLedsPerSequence; i++)
{
LOG(sequence[i]);
if(i < (numLedsPerSequence - 1))
{
LOG(", ");
}
}
LOGLN("]");
#endif
for (int j = 0; j < numShowSequence; j++)
{
#ifdef BLINK_DEBUG
LOG("Blink sequence = [");
#endif
for (byte i = 0; i < numLedsPerSequence; i++)
{
#ifdef BLINK_DEBUG
LOG(sequence[i]);
if(i < (numLedsPerSequence - 1))
{
LOG(", ");
}
else
{
LOGLN("]");
}
#endif
digitalWrite(info[sequence[i]].ledPin, HIGH);
delay(600);
digitalWrite(info[sequence[i]].ledPin, LOW);
delay(600);
}
digitalWrite(repeatLedPin, HIGH);
delay(600);
digitalWrite(repeatLedPin, LOW);
startTimer = true;
levelMillis = millis();
}
#ifdef GAME_DEBUG
LOG("Inp. = [");
#endif
}
void checkInput(byte button)
{
bool victory = false;
if (sequence[sequenceIndex] == button)
{
#ifdef GAME_DEBUG
LOG(button);
if(sequenceIndex < (numLedsPerSequence - 1))
{
LOG(", ");
}
else
{
LOGLN("]");
}
#endif
sequenceIndex++;
if(sequenceIndex == numLedsPerSequence)
{
level++;
sequenceIndex = 0;
victory = true;
LOGLN("Level up!");
digitalWrite(repeatLedPin, LOW);
for (byte i = 0; i < NUM_LEDS; i++)
{
digitalWrite(info[i].ledPin, LOW);
}
if (level <= MAX_LEVEL)
{
for (byte i = 0; i < ring.numPixels(); i++)
{
ring.setPixelColor(i, ring.Color(0, 255, 0));
ring.show();
delay(100);
}
delay(2000);
}
ring.clear();
ring.show();
}
}
else
{
gameStarted = false;
LOGLN("\nYOU LOSE!\nPress start for new game.");
digitalWrite(repeatLedPin, LOW);
for (byte i = 0; i < NUM_LEDS; i++)
{
digitalWrite(info[i].ledPin, LOW);
}
for (byte i = 0; i < ring.numPixels(); i++)
{
ring.setPixelColor(i, ring.Color(255, 0, 0));
ring.show();
delay(100);
}
delay(2000);
ring.clear();
ring.show();
}
if(victory == true)
{
if (level > MAX_LEVEL)
{
gameStarted = false;
LOGLN("YOU WON!");
rainbowCycle(10);
}
else
{
showSequence();
}
}
}
void swapEntries(byte a, byte b)
{
byte temp = sequence[a];
sequence[a] = sequence[b];
sequence[b] = temp;
}
void rainbowCycle(int wait)
{
uint16_t i, j;
for (j = 0; j < 256 * 5; j++)
{
for (i = 0; i < ring.numPixels(); i++)
{
ring.setPixelColor(i, Wheel(((i * 256 / ring.numPixels()) + j) & 255));
}
ring.show();
delay(wait);
}
ring.clear();
ring.show();
LOGLN("Press start for new game.");
}
int32_t Wheel(byte WheelPos)
{
WheelPos = 255 - WheelPos;
if (WheelPos < 85)
{
return ring.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170)
{
WheelPos -= 85;
return ring.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return ring.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}