#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

#define TRIGGER_PIN  11  
#define ECHO_PIN     12  
#define PUSH_BUTTON  10  
#define BUZZER_PIN 13 

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {6,7,8,9}; 
byte colPins[COLS] = {2,3,4,5}; 

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

LiquidCrystal_I2C lcd(0x27, 16, 2); 

void setup() {
  Serial.begin(9600);
  
  pinMode(TRIGGER_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(PUSH_BUTTON, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  
  lcd.init();
  lcd.backlight();
  lcd.print("Push to Start");
}

void loop() {
  if (digitalRead(PUSH_BUTTON) == HIGH) {
    float distance = calculateDistance();
    lcd.clear();
    lcd.print("Guess the dist:");
    
    
    char guess[5] = {0};
    int i = 0;
    char key = keypad.getKey();
    while (key != '#' && i < 4) {
      if (key != NO_KEY) {
        guess[i++] = key;
        lcd.setCursor(0, 1);
        lcd.print(guess);
      }
      key = keypad.getKey();
    }
    
    
    float guessDistance = atof(guess);
    
    
    if (abs(distance - guessDistance) <= 1) {
      lcd.clear();
      lcd.print("Correct!");
      lcd.setCursor(0, 1);
      lcd.print(guessDistance, 2);
      lcd.setCursor(10, 1);
      lcd.print(distance, 2);
      correctGuessSound();
      delay(2000);
    } else {
      lcd.clear();
      lcd.print("Incorrect");
      lcd.setCursor(0, 1);
      lcd.print(guessDistance, 2);
      lcd.setCursor(10, 1);
      lcd.print(distance, 2);
      incorrectGuessSound();
      delay(2000);
      
    }
    
    // Reset the game
    lcd.clear();
    lcd.print("Push to Start");
  }
}

float calculateDistance() {
  digitalWrite(TRIGGER_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIGGER_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGER_PIN, LOW);
  
  float duration = pulseIn(ECHO_PIN, HIGH);
  float distance = duration * 0.034 / 2;
  return distance;
}

void correctGuessSound() {
  tone(BUZZER_PIN, 1000, 500); 
  delay(100);
  noTone(BUZZER_PIN); 
}

void incorrectGuessSound() {
  int freq = 2000; 
  for (int i = 0; i < 3; i++) {
    freq -= 500;
    tone(BUZZER_PIN, freq, 50);
    delay(50);
  }
  delay(100);
  noTone(BUZZER_PIN); 
}