/*
  Arduino | hardware-help
  reaction time game
  jubilant_quokka_50345 Saturday, October 25, 2025 11:34 AM
  can someone verify?
  https://www.tinkercad.com/things/lfNQY2mWsLY-ingenious-densor-snaget?sharecode=HJ7A-mKtT0La3KH2qbXO1Fd5YlKFHwHzeK_G8P0NIt0
*/
#include <LiquidCrystal.h>
// Pin definitions
const int buttonPins[] = {6, 4, A3, A1};   // Button pins corresponding to LEDs
const int ledPins[] = {5, 3, A2, A0};      // LED pins (3 red, 1 yellow)
// LCD pins: RS, EN, D4, D5, D6, D7
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// Game states
enum GameState { WAIT_LED, WAIT_PRESS, SHOW_RESULT, SHOW_WRONG };
GameState state = WAIT_LED;
unsigned long stateStartTime = 0;
unsigned long ledOnTime = 0;
unsigned long randomDelay = 0;
int targetIndex = 0;          // Index of the correct LED/button
unsigned long reactionTime = 0;
void setup() {
  // Initialize LED pins as outputs and set LOW
  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], LOW);
  }
  // Initialize button pins as inputs with pull-up resistors
  for (int i = 0; i < 4; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  // Initialize LCD with 16 columns and 2 rows
  lcd.begin(16, 2);
  // Seed random using an unconnected analog pin
  randomSeed(analogRead(A5));
  // Display initial message
  lcd.print("Get Ready...");
  // Set initial random delay between 1 and 5 seconds (1000-5000 ms)
  randomDelay = random(1000, 5001);
  stateStartTime = millis();
}
void loop() {
  unsigned long currentTime = millis();
  switch (state) {
    case WAIT_LED:
      // After random delay, light up a random LED
      if (currentTime - stateStartTime >= randomDelay) {
        targetIndex = random(0, 4);  // 0 to 3
        digitalWrite(ledPins[targetIndex], HIGH);
        ledOnTime = currentTime;
        // Prompt user to react
        lcd.clear();
        lcd.print("Go!");
        state = WAIT_PRESS;
      }
      break;
    case WAIT_PRESS:
      // Check for button press (active LOW)
      for (int i = 0; i < 4; i++) {
        if (digitalRead(buttonPins[i]) == LOW) {
          // Turn off the LED immediately
          digitalWrite(ledPins[targetIndex], LOW);
          // Check if correct button
          if (i == targetIndex) {
            reactionTime = currentTime - ledOnTime;
            lcd.clear();
            lcd.print("Time: ");
            lcd.print(reactionTime);
            lcd.print(" ms");
            state = SHOW_RESULT;
          } else {
            lcd.clear();
            lcd.print("Wrong Button!");
            state = SHOW_WRONG;
          }
          stateStartTime = currentTime;
          break;
        }
      }
      break;
    case SHOW_RESULT:
      // Display result for 2 seconds, then start new round
      if (currentTime - stateStartTime >= 2000) {
        lcd.clear();
        lcd.print("Get Ready...");
        randomDelay = random(1000, 5001);
        stateStartTime = currentTime;
        state = WAIT_LED;
      }
      break;
    case SHOW_WRONG:
      // Display wrong message for 2 seconds, then start new round
      if (currentTime - stateStartTime >= 2000) {
        lcd.clear();
        lcd.print("Get Ready...");
        randomDelay = random(1000, 5001);
        stateStartTime = currentTime;
        state = WAIT_LED;
      }
      break;
  }
}