#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
int buttonPin[] = { 13, 12, 11, 10, 9, 8};
#define SPEAKER_PIN 2
const int gameTones[] = { 262, 296, 330, 349, 364, 393 };


byte urutan[225] = {0};
byte indexgame = 0;
byte score = 0;

uint8_t unPressedBtn[8] = { 
  0b00000,
  0b00000, 
  0b00000, 
  0b00000,  
  0b01110, 
  0b00000, 
  0b11011, 
  0b00000,
};
uint8_t pressedBtn[8] = { 
  0b00000, 
  0b00000, 
  0b00000,
  0b00000,     
  0b00000, 
  0b01110, 
  0b11011, 
  0b00000,
};
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.createChar(3, unPressedBtn);
  lcd.createChar(2, pressedBtn);
  lcd.begin(16, 2);
  pinMode(SPEAKER_PIN, OUTPUT);
  for (byte i = 0; i < 6; i++) {
    pinMode(buttonPin[i], INPUT_PULLUP);
  }
  start();
}

void start() {
  tone(SPEAKER_PIN, 262, 50);
  delay(50);
  tone(SPEAKER_PIN, 330, 100);

  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("MEMORY GAMES");
  lcd.setCursor(1, 1);
  lcd.print("ORDER THE LAMP");
  delay(1500);
  tone(SPEAKER_PIN, 330, 100);

  lcd.clear();
  lcd.setCursor(4, 0);
  lcd.print("MADE BY");
  lcd.setCursor(5, 1);
  lcd.print("REAZON");
  delay(1500);
  tone(SPEAKER_PIN, 330, 100);

  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("FIND CORRECT");
  lcd.setCursor(1, 1);
  lcd.print("ORDER OF LAMP!");
  delay(1500);

  tone(SPEAKER_PIN, 330, 100);
  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print("LETS BEGIN!");
  delay(1500);
  
  lcd.clear();
  delay(700);
  
}


void playOrder() {

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("SCORE :");
  lcd.setCursor(7, 0);
  lcd.print(score);

  lcd.setCursor(4, 1);
  lcd.print("[\x03\x03\x03\x03\x03\x03]");
  for (byte i = 0; i < indexgame; i++) {

    lcd.setCursor(5 + urutan[i], 1);
    lcd.print("\x02");
    tone(SPEAKER_PIN, gameTones[urutan[i]], 300);
    delay(300);
    noTone(SPEAKER_PIN);
    lcd.setCursor(5 + urutan[i], 1);
    lcd.print("\x03");
    delay(500);
  }

}

byte readButtons() {
  while (true) {
    for (byte i = 0; i < 6; i++) {
      byte button = buttonPin[i];
      if (digitalRead(button) == LOW) {
        return i;
      }
    }
    delay(1);
  }
}

bool isCorrect() {
  for (byte u = 0; u < indexgame; u++) {

    lcd.setCursor(7, 0);
    lcd.print(score);

    byte pressed = readButtons();
    lcd.setCursor(5 + pressed, 1);
    lcd.print("\x02");
    tone(SPEAKER_PIN, gameTones[pressed], 300);
    delay(300);
    lcd.setCursor(5 + pressed, 1);
    lcd.print("\x03");
    noTone(SPEAKER_PIN);
    if (pressed != urutan[u]) return false;
    score++;
  }

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("CORRECT!! LETS");
  lcd.setCursor(0, 1);
  lcd.print("TO NEXT LEVEL!");
  tone(SPEAKER_PIN, 349, 50);
  delay(50);
  tone(SPEAKER_PIN, 330, 100);
  return true;
}

void gameOver(){
   lcd.setCursor(0, 0);
    lcd.print("NOO.. YOU FAIL!");

    tone(SPEAKER_PIN, 462, 50);
    delay(50);
    tone(SPEAKER_PIN, 100, 500);

    for (byte i = 0; i < 2; i++) {
      for (byte i = 0; i < 6; i++) {
        lcd.setCursor(5 + i, 1);
        lcd.print("\x02");
      }
      delay(200);
      for (byte i = 0; i < 6; i++) {
        lcd.setCursor(5 + i , 1);
        lcd.print("\x03");
      }
      delay(200);

    }
    delay(500);
    indexgame = 0;
    score = 0;
}

void loop() {
  //put your main code here, to run repeatedly:
  for (byte i = 0; i < indexgame; i++) {
    byte rand = random(0, 4);
    urutan[i] = rand;
  }
  // urutan[indexgame] = random(0, 6);

  indexgame++;
  playOrder();

  if (!isCorrect()) {
    gameOver();
  }
  delay(400);
}