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

LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C Address and display size

// Custom character definitions
byte DINO_STANDING_PART_1[8] = {B00000, B00000, B00010, B00010, B00011, B00011, B00001, B00001};
byte DINO_STANDING_PART_2[8] = {B00111, B00111, B00111, B00100, B11100, B11100, B11000, B01000};
byte DINO_RIGHT_LEG_PART_1[8] = {B00000, B00000, B00010, B00010, B00011, B00011, B00001, B00001};
byte DINO_RIGHT_LEG_PART_2[8] = {B00111, B00111, B00111, B00100, B11100, B11100, B11000, B00000};
byte DINO_LEFT_LEG_PART_1[8] = {B00000, B00000, B00010, B00010, B00011, B00011, B00001, B00000};
byte DINO_LEFT_LEG_PART_2[8] = {B00111, B00111, B00111, B00100, B11100, B11100, B11000, B01000};
byte TWO_BRANCHES_PART_1[8] = {B00000, B00100, B00100, B10100, B10100, B11100, B00100, B00100};
byte TWO_BRANCHES_PART_2[8] = {B00100, B00101, B00101, B10101, B11111, B00100, B00100, B00100};
byte BIRD_WINGS_PART1[8] = {B00001, B00001, B00001, B00001, B01001, B11111, B00000, B00000};
byte BIRD_WINGS_PART2[8] = {B00000, B10000, B11000, B11100, B11110, B11111, B00000, B00000};

// Variables and declarations
int dino_column1 = 1;
int dino_column2 = 2;
int dino_row = 1;
unsigned long clock = 0; // to use millis() instead of delay
int period = 100; // period in milliseconds
int flag = 1;
int branch_row = 0;
int branch_column = 13;
int period2 = 100;
unsigned long clock2 = 0;
int a = 0;
int b = 1;
int c = 2;
int d = 0;
unsigned long clock3 = 0;
int period3 = 100;
int points = 0;
int point2 = 0;
int random_number = 0;
int bird_column = 13;
int e = 0;
int bird_row = 1;
int current_signal = 0;
int previous_signal = 0;
int f = 13;
int acceleration = 1;
unsigned long clock4 = 0;
int period4 = 800;
int button = 11; // Pushbutton pin - for making the Dinosaur jump
int buzzer = 10; // Passive Buzzer pin - for sound effects
bool game_started = false; // game state variable

void setup() {
  for (int i = 2; i <= 17; i++) pinMode(i, OUTPUT);

  pinMode(button, INPUT);
  pinMode(buzzer, OUTPUT);

  lcd.backlight();
  lcd.begin(16, 2);
  lcd.createChar(0, DINO_STANDING_PART_1);
  lcd.createChar(1, DINO_STANDING_PART_2);
  lcd.createChar(2, DINO_RIGHT_LEG_PART_1);
  lcd.createChar(3, DINO_RIGHT_LEG_PART_2);
  lcd.createChar(4, DINO_LEFT_LEG_PART_1);
  lcd.createChar(5, DINO_LEFT_LEG_PART_2);
  lcd.createChar(6, TWO_BRANCHES_PART_1);
  lcd.createChar(7, TWO_BRANCHES_PART_2);

  // Initial message
  lcd.setCursor(0, 0);
  lcd.print("Press the");
  lcd.setCursor(0, 1);
  lcd.print("button to start");
}

void loop() {
  if (!game_started) { // Wait for the button press to start the game
    if (digitalRead(button) == HIGH) {
      lcd.clear();
      game_started = true;
    } else {
      return;
    }
  }

  // Game logic starts here
  if (millis() > clock + period) { // delay for dinosaur legs
    clock = millis();
    if (flag == 1) {
      flag = 2;
    } else if (flag == 2) {
      flag = 1;
    }
  }

  if (millis() > clock2 + period2) { // delay for branch speed
    clock2 = millis();

    branch_column = branch_column - 1;
    if (branch_column < 0) {
      branch_column = 13;
      period2 = period2 - acceleration; // acceleration
      random_number = random(0, 3); // random number since it's every time it returns to column 13
    }

    f = branch_column + 1;
    lcd.setCursor(f, 1); // clear below
    lcd.print(" ");

    f = branch_column + 1;
    lcd.setCursor(f, 0); // clear above
    lcd.print(" ");

    lcd.setCursor(0, 1); // clear above
    lcd.print(" ");

    lcd.setCursor(0, 0);
    lcd.print(" ");

    a = 1;
  }

  if (d == 0) {
    if (flag == 1) {
      lcd.setCursor(dino_column1, dino_row);
      lcd.write(byte(2));
      lcd.setCursor(dino_column2, dino_row);
      lcd.write(byte(3));
    }
    if (flag == 2) {
      lcd.setCursor(dino_column1, dino_row);
      lcd.write(byte(4));
      lcd.setCursor(dino_column2, dino_row);
      lcd.write(byte(5));
    }
  }

  if (a == 1) {
    if (random_number == 1) {
      branch_row = 1;
      lcd.createChar(6, TWO_BRANCHES_PART_1);
      lcd.setCursor(branch_column, branch_row);
      lcd.write(byte(6));
    } else if (random_number == 2) {
      branch_row = 1;
      lcd.createChar(7, TWO_BRANCHES_PART_2);
      lcd.setCursor(branch_column, branch_row);
      lcd.write(byte(7));
    } else {
      bird_column = branch_column;
      bird_column = bird_column - 1;
      branch_row = 0;
      lcd.createChar(6, BIRD_WINGS_PART1);
      lcd.setCursor(bird_column, branch_row);
      lcd.write(byte(6));
      lcd.createChar(7, BIRD_WINGS_PART2);
      lcd.setCursor(branch_column, branch_row);
      lcd.write(byte(7));
    }
    a = 0;
  }

  if (digitalRead(button) == HIGH && (branch_column == 1 || branch_column == 2 || bird_column == 1 || bird_column == 2) && branch_row == 0 ) {
    lcd.clear();
    lcd.setCursor(3, 0);
    lcd.print("GAME OVER");
    delay(2000);
    lcd.clear();
    branch_column = 15;
    period2 = 100;
    points = 0;
    point2 = 0;
    period2 = 100;
  }

  if ((branch_column == b || branch_column == c) && branch_row == 1) { // branch condition
    int note[] = {200, 150};
    for (int i = 0; i < 2; i++) {
      tone(buzzer, note[i], 250);
      delay(200);
    }
    lcd.clear();
    lcd.setCursor(3, 0);
    lcd.print("GAME OVER");
    lcd.setCursor(0, 1);
    lcd.print("Press the button");
    delay(2000);

    // Wait for button press to start the game again
    while (digitalRead(button) == LOW) {
      // Wait until the button is pressed
    }

    lcd.clear();
    branch_column = 15;
    period2 = 100;
    points = 0;
    points = 0;
    period2 = 100;
    game_started = false; // Reset game state to start again
    return; // Exit from loop() function to start the game again
  }

  if (digitalRead(button) == HIGH) {
    b = 50;
    c = 50;
    if (d == 0) {
      lcd.setCursor(0, 1);
      lcd.print("    ");
    }
    d = 1;
    lcd.setCursor(dino_column1, 0);
    lcd.write(byte(2));
    lcd.setCursor(dino_column2, 0);
    lcd.write(byte(3));

    if (millis() > clock4 + period4) {
      clock4 = millis();
      int note[] = {600};
      for (int i = 0; i < 1; i++) {
        tone(buzzer, note[i], 150);
        delay(20);
      }
    }
  } else {
    b = 1;
    c = 2;
    d = 0;
  }

  if (millis() > clock3 + period3) { // delay for accumulated points
    clock3 = millis();
    lcd.setCursor(14, 1);
    lcd.print(points);
    points = points + 1;

    if (points == 100) {
      int note[] = {800, 900};
      for (int i = 0; i < 2; i++) {
        tone(buzzer, note[i], 150);
        delay(150);
        points = 0;
        point2 = point2 + 1;
        if (point2 == 100) {
          point2 = 0;
        }
      }
    }
    lcd.setCursor(14, 1);
    lcd.print(points);
    lcd.setCursor(14, 0);
    lcd.print(point2);

    current_signal = digitalRead(button);
    if (current_signal != previous_signal) {
      lcd.setCursor(1, 0);
      lcd.print("  ");
    }
    previous_signal = current_signal;
  }
}
$abcdeabcde151015202530354045505560fghijfghij