#include <TM1637Display.h>
#include <Adafruit_NeoPixel.h>

// LED
#define LED_PIN 32
#define LED_COUNT 78
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// AFFICHAGE DU SCORE
int CLK_combo = 25;
int DIO_combo = 23;
int CLK_best = 29;
int DIO_best = 27;
int CLK_sccore = 33;
int DIO_sccore = 31;

TM1637Display tm_best = TM1637Display(CLK_best, DIO_best);
TM1637Display tm_combo = TM1637Display(CLK_combo, DIO_combo);
TM1637Display tm_sccore = TM1637Display(CLK_sccore, DIO_sccore);

int input_pins[] = {53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34};
int pir_states[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};
bool doors_state[] = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};
int doors_line[] = {0, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7};
int doors_leds[] = {6, 16, 20, 34, 30, 40, 44, 48, 62, 58, 54, 64, 68, 72, 76};
int init_leds_1[] = {10, 12, 36, 38, 62, 64};
int init_leds_2[] = {0, 24, 26, 50, 52, 76};

int score;
int combo;
int last_line;
bool start_game;
const int plus_score = 20;
int best = 0;

void setup() {

  Serial.begin(9600);

  // reset des LEDs
  strip.begin();
  strip.clear();
  strip.show();

  // init des afficheurs
  tm_best.setBrightness(7);
  tm_combo.setBrightness(7);
  tm_sccore.setBrightness(7);
  tm_best.clear();
  tm_combo.clear();
  tm_sccore.clear();

  for (int x = 0; x < sizeof(input_pins) / sizeof(input_pins[0]); x++) {
    pinMode(input_pins[x], INPUT);
  }
  
  display_number(0, tm_best);
  display_number(0, tm_combo);
  display_number(0, tm_sccore);

  init_game();
  
}

void init_game() {
    score = 0;
    combo = 0;
    last_line = 0;
    start_game = false;
    memset(doors_state, false, sizeof(doors_state));
    init_led();
}

void init_led() {
  strip.clear();
  for (int i = 0; i < 6; i++) {
    strip.setPixelColor(init_leds_1[i], strip.Color(50, 0, 0));
    strip.setPixelColor(init_leds_1[i] + 1, strip.Color(50, 0, 0));
    strip.setPixelColor(init_leds_2[i], strip.Color(0, 0, 50));
    strip.setPixelColor(init_leds_2[i] + 1, strip.Color(0, 0, 50));
  }
  strip.show();
}

void display_number(int num, TM1637Display tm) {
    tm.showNumberDec(num);
}

void check_doors(int i) {
  
  if (!digitalRead(input_pins[i]) == HIGH) {
    if (pir_states[i] == LOW) {
      pir_states[i] = HIGH;
      if (!i) {
        strip.clear();
        strip.show();
      }
      Serial.println(input_pins[i]);
    }
  }
  else {
    if (pir_states[i] == HIGH) {
      pir_states[i] = LOW;

      if (!i) {
        if (!doors_state[i] && !start_game) {
          start_game = true;
        }
      }
      else if (i > 0 && i < 16) {
        if (!doors_state[i] && start_game) {
          if (last_line == (doors_line[i] - 1)) {
            combo++;
          }
          else {
            combo = 1;
          }
          
          last_line = doors_line[i];
          score += plus_score * combo;
          doors_state[i] = true;

          int i_leds = i - 1;
          strip.setPixelColor(doors_leds[i_leds], strip.Color(0, 150, 0));
          strip.setPixelColor(doors_leds[i_leds] + 1, strip.Color(0, 150, 0));
          strip.show();
          
        }
      }
      else {
        if (!doors_state[i] && start_game) {
          
          int multiplier = 0;
          
          switch (i) {
              case 16: multiplier = 10; break;
              case 17: multiplier = 0; break;
              case 18: multiplier = 2; break;
              case 19: multiplier = 5; break;
          }
          
          score *= multiplier;

          display_number(score, tm_sccore);
        
          if (score > best) {
              best = score;
              new_best();
          }
          else {
              leds_game_over();
          }

          init_game();
          
        }
      }
    }
  }  
}

void loop() {

    for (int i = 0; i <= 19; i++) {    
      check_doors(i);
    }

    display_number(best, tm_best);
    display_number(combo, tm_combo);
    display_number(score, tm_sccore);
  
}

void new_best() {
    for (int i = 0; i <= 10; i++) {
        display_number(best, tm_best);
        strip.clear();
        for (int l = 0; l <= LED_COUNT; l += 4) {
            int r = random(50, 255);
            int v = random(50, 255);
            int b = random(50, 255);
            strip.setPixelColor(l, strip.Color(r, v, b));
            strip.setPixelColor(l + 1, strip.Color(r, v, b));
        }
        strip.show();
        delay(100);
        tm_best.clear();
        strip.clear();
        for (int l = 2; l <= LED_COUNT; l += 4) {
            int r = random(50, 255);
            int v = random(50, 255);
            int b = random(50, 255);
            strip.setPixelColor(l, strip.Color(r, v, b));
            strip.setPixelColor(l + 1, strip.Color(r, v, b));
        }
        strip.show();
        delay(100);
    }
}

void leds_waiting() {
  
    strip.clear();
    for (int l = 0; l <= LED_COUNT; l += 4) {
        strip.setPixelColor(l, strip.Color(50, 50, 50));
        strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
    }
    strip.show();
    delay(1000);
    strip.clear();
    for (int l = 2; l <= LED_COUNT; l += 4) {
        strip.setPixelColor(l, strip.Color(50, 50, 50));
        strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
    }
    strip.show();
    delay(1000);
    
}

void leds_game_over() {

    for (int i = 0; i < 3; i++) {

        strip.clear();
        
        for (int l = 0; l <= 10; l += 2) {
            strip.setPixelColor(l, strip.Color(50, 50, 50));
            strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
        }
        strip.show();
    
        delay(100);
        
        for (int l = 12; l <= 24; l += 2) {
            strip.setPixelColor(l, strip.Color(50, 50, 50));
            strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
        }
        strip.show();
    
        delay(100);
        
        for (int l = 26; l <= 36; l += 2) {
            strip.setPixelColor(l, strip.Color(50, 50, 50));
            strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
        }
        strip.show();
    
        delay(100);
        
        for (int l = 38; l <= 50; l += 2) {
            strip.setPixelColor(l, strip.Color(50, 50, 50));
            strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
        }
        strip.show();
    
        delay(100);
        
        for (int l = 52; l <= 62; l += 2) {
            strip.setPixelColor(l, strip.Color(50, 50, 50));
            strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
        }
        strip.show();
    
        delay(100);
        
        for (int l = 64; l <= 76; l += 2) {
            strip.setPixelColor(l, strip.Color(50, 50, 50));
            strip.setPixelColor(l + 1, strip.Color(50, 50, 50));
        }
        strip.show();
    
        delay(100);
    
    }
}
