// Simon relooké pour atelier AIR2
const int LED_Jaune  = 10; // LED pin Jaune
const int LED_Bleu    = 11; // LED pin Bleu
const int LED_Verte   = 12; // LED pin Verte
const int LED_Rouge     = 13; // LED pin Rouge

const int Send_Main_OK = 2; // Message to mega Main = win
const int Send_Main_KO = 3; // Message to mega Main = win
//const int Main_Send_RAZ = 3; // Message to mega Main = lost

const int Bouton_Jaune = 4;  // Bouton Jaune input pin
const int Bouton_Bleu   = 5;  // Bouton Bleu input pin
const int Bouton_Vert  = 6;  // Bouton vert input pin
const int Bouton_Rouge    = 7;  // Bouton Rouge input pin

const int PIEZO         = 9;  // pin du piezo

const int STATE_START_GAME        = 0;  // Etat Initial
const int STATE_PICK_RND_SEQUENCE = 1;  // définition d'une séquence de LEDs
const int STATE_SHOW_RND_SEQUENCE = 2;  // Lancement de la séquence de LED
const int STATE_READ_PLAYER_GUESS = 3;  // lecture de la réponse du joueur
const int STATE_VERIFY_GUESS      = 4;  // Vérification de la réponse par rapport à la séquence de référence
const int STATE_GUESS_CORRECT     = 5;  // Le joueur a réussi
const int STATE_GUESS_INCORRECT   = 6;  // Le joueur à fait une erreur
const int STATE_END               = 7;  // Le joueur à gagné ou perdu. Attente de la fin de la bombe.

const int Niveau_Max_Difficile    = 9;  // Niveau de difficulté Maximum
const int Nbr_Max_erreur = 2; // nbr de fois ou le joueur peut perdre
int Nbr_erreur = 0; // nbr de fois ou le joueur a fait une erreur

// Tableau utilisé pour stocker la séquence random générée
int randomSequence[Niveau_Max_Difficile];

// Tableau utilisé pour stocker la séquence du joueur
int playerGuess[Niveau_Max_Difficile];

// Un compteur pour enregristrer le nombre de frappe de bouton du joueur
int numButtonPresses;

// The current state the game is in
int currentState;
int nextState;

// The difficulty level (1..Niveau_Max_Difficile)
int difficultyLevel = 1; // Niveau de difficulté de départ, Ne pas mettre à zéro !

void setup() {
  // Initialise input buttons
  for (int i = Bouton_Jaune; i <= Bouton_Rouge; i++) {
    pinMode(i, INPUT_PULLUP);
  }
  // Initialise LEDs
  for (int i = LED_Jaune; i <= LED_Rouge; i++) {
    pinMode(i, OUTPUT);
  }
  // Set initial difficulty level to 1 random flash && put game in start state
  currentState = STATE_START_GAME;
  nextState = currentState;
  numButtonPresses = 0;

  // Initialise message from/to Main
  pinMode(Send_Main_OK, OUTPUT);
  pinMode(Send_Main_KO, OUTPUT);
  //pinMode(Main_Send_RAZ, INTPUT_PULLUP);

}

void loop() {

  // Run the state machine controlling the game's states
  switch ( currentState ) {
    case STATE_START_GAME:
      delay(1000); // Give player time to get ready
      nextState = STATE_PICK_RND_SEQUENCE;
      break;

    case STATE_PICK_RND_SEQUENCE:
      generateRndSequence();
      nextState = STATE_SHOW_RND_SEQUENCE;
      break;

    case STATE_SHOW_RND_SEQUENCE:
      showRndSequence();  // Display the rnd sequence to the player
      nextState = STATE_READ_PLAYER_GUESS;
      break;

    case STATE_READ_PLAYER_GUESS:
      readPlayerGuess();  // Poll buttons and record each button press
      // If all inputs have been made then verify the guess
      if ( numButtonPresses >= difficultyLevel ) {
        numButtonPresses = 0;
        nextState = STATE_VERIFY_GUESS;
      }
      break;

    case STATE_VERIFY_GUESS:
      // Check player's guess against the generated random sequence
      if ( verifyGuess() ) {
        nextState = STATE_GUESS_CORRECT;
      } else {
        nextState = STATE_GUESS_INCORRECT;
      }
      break;

    case STATE_GUESS_CORRECT:
      // Player was right. Increase difficulty level and goto start game
      soundCorrectGuess();
      difficultyLevel++;
      if ( difficultyLevel > Niveau_Max_Difficile ){
        difficultyLevel = Niveau_Max_Difficile;
      nextState = STATE_END;
      digitalWrite(Send_Main_OK, HIGH);
      }
      else{nextState = STATE_START_GAME;}
      break;

    case STATE_GUESS_INCORRECT:
      // Player was wrong. Sound buzzer, show correct sequence, set difficulty level to 1 and re-start game
      soundBuzzer();
      showRndSequence();
      if (Nbr_erreur < Nbr_Max_erreur) {
        Nbr_erreur++;
        nextState = STATE_START_GAME;
      }
      else {
        nextState = STATE_END;
        difficultyLevel = 1;
      }

      break;

    case STATE_END:
      // Player was wrong or Win.
      //while (digitalRead(Main_Send_RAZ) == 1) {} //boucle tant qu'il n'y a pas de remise à zéro de la mega
      //Nbr_erreur = 0; // RAZ du nombre d'erreur
      //nextState = STATE_START_GAME; //RAZ du jeu
      digitalWrite(Send_Main_KO, HIGH);
      break;
  }
  currentState = nextState;
}


// Generate a random sequence of LED pin numbers
void generateRndSequence() {
  for (int i = 0; i < difficultyLevel; i++) {
    randomSequence[i] = rndLEDPin();
  }
}

// Show random sequence
void showRndSequence() {
  for (int i = 0; i < difficultyLevel; i++) {
    flashLED(randomSequence[i], true);
  }
}

// Read a button press representing a guess from player
void readPlayerGuess() {
  if ( digitalRead(Bouton_Jaune) == LOW ) {
    playerGuess[numButtonPresses] = LED_Jaune;
    numButtonPresses++;
    flashLED(LED_Jaune, true);
    blockUntilRelease(Bouton_Jaune);
  } else if ( digitalRead(Bouton_Bleu) == LOW ) {
    playerGuess[numButtonPresses] = LED_Bleu;
    numButtonPresses++;
    flashLED(LED_Bleu, true);
    blockUntilRelease(Bouton_Bleu);
  } else if ( digitalRead(Bouton_Vert) == LOW ) {
    playerGuess[numButtonPresses] = LED_Verte;
    numButtonPresses++;
    flashLED(LED_Verte, true);
    blockUntilRelease(Bouton_Vert);
  } else if ( digitalRead(Bouton_Rouge) == LOW ) {
    playerGuess[numButtonPresses] = LED_Rouge;
    numButtonPresses++;
    flashLED(LED_Rouge, true);
    blockUntilRelease(Bouton_Rouge);

  }
}

void blockUntilRelease(int buttonNumber) {
  while ( digitalRead(buttonNumber) == LOW )
    ;
}
// Compare the guess with the random sequence and return true if identical
bool verifyGuess() {
  bool identical = true;
  for (int i = 0; i < difficultyLevel; i++) {
    if ( playerGuess[i] != randomSequence[i] ) {
      identical = false;
      break;
    }
  }
  return identical;
}

// Sound the buzzer for incorrect guess
void soundBuzzer() {
  tone(PIEZO, 100, 500);
  delay(200);
}

void soundCorrectGuess() {
  tone(PIEZO, 700, 50);
  delay(100);
  tone(PIEZO, 800, 50);
  delay(100);
  tone(PIEZO, 900, 50);
  delay(100);
  tone(PIEZO, 1000, 50);
  delay(100);
  tone(PIEZO, 1100, 50);
  delay(100);
  tone(PIEZO, 1200, 50);
  delay(50);
}
// Flash the LED on the given pin
void flashLED(int ledPinNum, bool playSound) {
  digitalWrite(ledPinNum, HIGH);
  if ( playSound )
    playSoundForLED(ledPinNum);
  delay(200);
  digitalWrite(ledPinNum, LOW);
  delay(200);
}

void playSoundForLED(int ledPinNum) {
  int pitch = 0;
  switch (ledPinNum) {
    case LED_Jaune: pitch = 200; break;
    case LED_Bleu: pitch = 250; break;
    case LED_Verte: pitch = 300; break;
    case LED_Rouge: pitch = 350; break;
  }
  tone(PIEZO, pitch, 200);
}
// Get a random LED pin number
int rndLEDPin() {
  return random(LED_Jaune, LED_Rouge + 1);
}
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
bz1:1
bz1:2
led1:A
led1:C
r1:1
r1:2
r2:1
r2:2
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
r3:1
r3:2
r4:1
r4:2
led5:A
led5:C
r5:1
r5:2
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
led6:A
led6:C
r6:1
r6:2