/*
   Arduino Uno Memory Game (Version 2)
   Tarundeep K.
*/

//create the buttons and led's into array's so its easier to call on them when generating random orders
int button[] = {12, 10, 8, 4}; //yellow is button[0], green is button[1], red is button[2], blue is button[3]
int led[] = {13, 11, 9, 7}; //yellow is led[0], green is led[1], red is led[2], blue is led[3]

int tones[] = {265, 330, 392, 494}; //tones to play with eavh button (c, e, g, b)
const int buzzerPin = 3;

const int blue_RGB = 5; //blue will be used to indicate that they won the game
//const int green_RGB = 5; //use              ` `d to indicate if user is correct
const int red_RGB = 6; //used to indicate if user is wrong

int roundsToWin = 5; //number of round the player has to play to win.
int buttonSequence[6]; //makes an array of numbers that will be sequences that the user will need to remember

int pressedButton = 4; //a variavle to remeber which vutton is pressed. 4 is no button pressed.
int roundCounter = 1; //keeps track of round the player is on

long startTime = 0; //time variale for time limit on button press
long timeLimit = 2000; //time limit to hit a button

boolean gameStarted = false;

const int a = A3; //makes 1 part of the 7 Segment Display Light up
const int b = A4; //makes 1 part of the 7 Segment Display Light up
const int c = A5; //makes 1 part of the 7 Segment Display Light up
const int d = A0; //makes 1 part of the 7 Segment Display Light up
const int e = 2; //makes 1 part of the 7 Segment Display Light up
const int f = A2; //makes 1 part of the 7 Segment Display Light up
const int g = A1; //makes 1 part of the 7 Segment Display Light up

void setup() {
  pinMode(button[0], INPUT);
  pinMode(button[1], INPUT);
  pinMode(button[2], INPUT);
  pinMode(button[3], INPUT);

  pinMode(led[0], OUTPUT);
  pinMode(led[1], OUTPUT);
  pinMode(led[2], OUTPUT);
  pinMode(led[3], OUTPUT);

  pinMode(blue_RGB, OUTPUT);
  //pinMode (green_RGB, OUTPUT);
  pinMode(red_RGB, OUTPUT);

  pinMode(a, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);
  pinMode(f, OUTPUT);
  pinMode(g, OUTPUT);

  pinMode(buzzerPin, OUTPUT); 
}

void smiley() {
  digitalWrite(a, LOW); 
  digitalWrite(b, HIGH); 
  digitalWrite(c, LOW); 
  digitalWrite(d, HIGH); 
  digitalWrite(e, LOW); 
  digitalWrite(f, HIGH); 
  digitalWrite(g, HIGH);
}

void one() {
  digitalWrite(a, HIGH); 
  digitalWrite(b, HIGH); 
  digitalWrite(c, HIGH); 
  digitalWrite(d, HIGH); 
  digitalWrite(e, LOW); 
  digitalWrite(f, LOW); 
  digitalWrite(g, HIGH); 
  }

void two() {
  digitalWrite(a, LOW); 
  digitalWrite(b, LOW); 
  digitalWrite(c, HIGH); 
  digitalWrite(d, LOW); 
  digitalWrite(e, LOW); 
  digitalWrite(f, HIGH); 
  digitalWrite(g, LOW);
}

void three() {
  digitalWrite(a, LOW); 
  digitalWrite(b, HIGH); 
  digitalWrite(c, HIGH); 
  digitalWrite(d, LOW); 
  digitalWrite(e, LOW); 
  digitalWrite(f, LOW); 
  digitalWrite(g, LOW);
}

void four() {
  digitalWrite(a, HIGH); 
  digitalWrite(b, HIGH); 
  digitalWrite(c, LOW); 
  digitalWrite(d, HIGH); 
  digitalWrite(e, LOW); 
  digitalWrite(f, LOW); 
  digitalWrite(g, LOW);
}

void five() {
  digitalWrite(a, LOW); 
  digitalWrite(b, HIGH); 
  digitalWrite(c, LOW); 
  digitalWrite(d, LOW); 
  digitalWrite(e, HIGH); 
  digitalWrite(f, LOW); 
  digitalWrite(g, LOW);
}

void six() {
  digitalWrite(a, LOW); 
  digitalWrite(b, LOW); 
  digitalWrite(c, LOW); 
  digitalWrite(d, LOW); 
  digitalWrite(e, HIGH); 
  digitalWrite(f, LOW); 
  digitalWrite(g, LOW);
}

void seven() {
  digitalWrite(a, HIGH); 
  digitalWrite(b, HIGH); 
  digitalWrite(c, HIGH); 
  digitalWrite(d, LOW); 
  digitalWrite(e, LOW); 
  digitalWrite(f, LOW); 
  digitalWrite(g, HIGH);
}

void eight() {
  digitalWrite(a, LOW); 
  digitalWrite(b, LOW); 
  digitalWrite(c, LOW); 
  digitalWrite(d, LOW); 
  digitalWrite(e, LOW); 
  digitalWrite(f, LOW); 
  digitalWrite(g, LOW);
}

void nine() {
  digitalWrite(a, LOW); 
  digitalWrite(b, HIGH); 
  digitalWrite(c, LOW); 
  digitalWrite(d, LOW); 
  digitalWrite(e, LOW); 
  digitalWrite(f, LOW); 
  digitalWrite(g, LOW);
}

//Flashes LED in generated sequence
void flashLED (int ledNumber) {
  digitalWrite(led[ledNumber], HIGH); 
  tone(buzzerPin, tones[ledNumber]);
}

void setColour(int r,  int b) {
  analogWrite(red_RGB, r); 
  //analogWrite(green_RGB, g); 
  analogWrite(blue_RGB, b);
}

//Turns off all the leds
void allLEDoff() {
  digitalWrite(led[0], LOW);
  digitalWrite(led[1], LOW);
  digitalWrite(led[2], LOW);
  digitalWrite(led[3], LOW);

  noTone(buzzerPin); 
}

//Checks which button is pressed
int buttonCheck() {
  if (digitalRead(button[0]) == HIGH){
    tone(buzzerPin, tones[0]);
    return 0;}
  else if (digitalRead(button[1]) == HIGH){
    tone(buzzerPin, tones[1]);
    return 1;}
  else if (digitalRead(button[2]) == HIGH){
    tone(buzzerPin, tones[2]);
    return 2;}
  else if (digitalRead(button[3]) == HIGH){
    tone(buzzerPin, tones[3]);
    return 3;}
  else
    return 4; //this will be the value for no button being pressed
}

//Checks if any button is pressed to restart the game 
int restartCheck() {
  if (digitalRead(button[0]) == HIGH){
    return 0;}
  else if (digitalRead(button[1]) == HIGH){
    return 1;}
  else if (digitalRead(button[2]) == HIGH){
    return 2;}
  else if (digitalRead(button[3]) == HIGH){
    return 3;}
  else
    return 4; //this will be the value for no button being pressed
}

//Generated random sequence and starts the sequence

void startSequence() {

//wait until a button is pressed
  do {
    pressedButton = buttonCheck();

    //RGB LED off 
    setColour(255,255);
  
  } while (pressedButton > 3);
  delay(100);
  
  //randomSeed(analogRead(A0)); //makes sure the random numbers are generated

  //takes these generated values and stores it in the buttonSequence array with random numbers from 0 to 3
  for (int i = 0; i <= roundsToWin; i++) {
    buttonSequence[i] = round(random(0, 4));
  }

  //flashes all the LEDs when game is starting
  for (int i = 0; i <= 4; i++){

  tone(buzzerPin, tones[i], 200); 
  
  //turns them all on
  digitalWrite(led[0], HIGH);
  digitalWrite(led[1], HIGH);
  digitalWrite(led[2], HIGH);
  digitalWrite(led[3], HIGH);

  delay(100);

  //turns them all off after a moment
  digitalWrite(led[0], LOW);
  digitalWrite(led[1], LOW);
  digitalWrite(led[2], LOW);
  digitalWrite(led[3], LOW);

  delay(100); }

  smiley();
  
}//this will repeat 4 times before the game starts

//implemented if user answer is wrong or they crossed time limit 
void loseSequence () {
  delay(100);
  setColour(0,255);
  delay(250);
  setColour(255,255);

  smiley(); 

  //lose Sequence plays
  tone(buzzerPin, 130, 250);   //E6
  delay(275);
  tone(buzzerPin, 73, 250);   //G6
  delay(275);
  tone(buzzerPin, 65, 150);   //E7
  delay(175);
  tone(buzzerPin, 98, 500);   //C7
  delay(500);
  
  //wait until a button is pressed
  do {
    pressedButton = restartCheck();
  } while (pressedButton > 3);
  delay(100);

  gameStarted = false;
}

//implemented if user wins all the round 
void winSequence() {
  delay(100);
  setColour(255,0);
  delay(1000);
  setColour(255,255);

  smiley(); 

  //Victory Sequence plays 
  tone(buzzerPin, 1318, 150);   //E6
  delay(175);
  tone(buzzerPin, 1567, 150);   //G6
  delay(175);
  tone(buzzerPin, 2637, 150);   //E7
  delay(175);
  tone(buzzerPin, 2093, 150);   //C7
  delay(175);
  tone(buzzerPin, 2349, 150);   //D7
  delay(175);
  tone(buzzerPin, 3135, 500);   //G7
  delay(500);
  
  //wait until a button is pressed
  do {
    pressedButton = restartCheck();
  } while (pressedButton > 3);
  delay(100);

  gameStarted = false; //resets the game so the start sequence will play again
}

void loop() {
  typedef void (*num_func) ();
  num_func roundDisplay[] = {smiley, one, two, three, four, five, six, seven, eight, nine};

  
  if (gameStarted == false) {
    startSequence(); //starts the start sequence
    roundCounter = 0; //resets the round counter
    delay(1500); //waits 1 1/2 seconds
    gameStarted = true; //sets gameStarted to true so the game doesn't restart
  }

  roundDisplay[roundCounter+1]();
  
  //Rounds start by flashing generated order
  for (int i = 0; i <= roundCounter; i++) { //gotes through the array up to the current round
    flashLED (buttonSequence[i]); //turns on the LED for that array
    delay(200);
    allLEDoff(); //turns all of the LEDS off
    delay(200);
  }

  //then starts going through the sequence one at a time to see if the user pressess the correct button
  for (int i = 0; i <= roundCounter; i++) {

    startTime = millis(); //starts recoridng the start time

    while (true) {
      pressedButton = buttonCheck(); //every loop check to see which button is pressed

      if (pressedButton < 4) { //if a button is pressed (4 means no button is pressed)
        flashLED(pressedButton);
        if (pressedButton == buttonSequence [i]) {
          delay(250);
          allLEDoff ();
          break;
        }
        else {
          delay(250);
          allLEDoff(); 
          loseSequence();
          break;
        }
      } 
      else {
        allLEDoff();
      }

      //check to see if the time limit is up

      if (millis() - startTime > timeLimit) {
        delay(250); 
        loseSequence();
        break;
      }
    }
  }

  roundCounter++;

  if (roundCounter >= roundsToWin) { 
    delay(250);
    winSequence(); 
  }

  delay(500); //waits for hald a second between each round 
}
