#include <TinyWireM.h>
#include <Tiny4kOLED.h>

// UP button
int btn1 = PB3;

// Down button
int btn2 = PB4;

// Button Debounce delay
int debounceDelay = 200;
// Animation Speed
int speed = 300;

// variables
int mode = 0;
int pos = 5;
int k = 4;
int x = 0;
bool win;
int score = 0;
unsigned long lastMillis;

void setup() {
  oled.begin();
  pinMode(btn1, INPUT_PULLUP);
  pinMode(btn2, INPUT_PULLUP);

  // random seed for generating random numbers
  randomSeed(analogRead(1));
  
  // Two rotations are supported,
  // The begin() method sets the rotation to 1.
  //oled.setRotation(0);

  oled.setFont(FONT6X8);
  oled.on();

  // To clear all the memory, clear both rendering frames:
  oled.clear();
  oled.switchRenderFrame();
  oled.clear();
  oled.switchRenderFrame();
}

void loop() {
  // manu mode
  if (mode == 0) {
    oled.setCursor(30, 0);
    oled.print(F("Floppy Bird"));

    oled.setCursor(0, 1);
    oled.fillToEOL(0x10);

    oled.setCursor(20, 3);
    oled.print(F("start the game"));

    oled.setCursor(0, 5);
    oled.print(F("switch off the screen"));

    // Press up button to enter the game 
    if (digitalRead(btn1) == LOW) {
      oled.setCursor(0, 4);
      oled.fillToEOL(0x0C);
      
      mode = 1;
      delay(300);

      // clear the screen
      oled.clear();
      oled.switchRenderFrame();
      oled.clear();
      oled.switchRenderFrame();
    }

    // Press the down button to turn off the screen
    if (digitalRead(btn2) == LOW) {
      oled.setCursor(0, 6);
      oled.fillToEOL(0x0C);
      
      mode = 2;
      delay(300);
    }
  }

  // Off screen mode
  if (mode == 2) {
    oled.clear();
    oled.switchRenderFrame();
    oled.clear();
    oled.switchRenderFrame();

    // when the screen is turned off,
    // press down button to turn it on again
    if (digitalRead(btn2) == LOW) {
      mode = 0;
      delay(debounceDelay);
    }
  }

  // Game mode
  if (mode == 1) {
    // move the bird Down by pressing down button
    if (digitalRead(btn2) == LOW) {
      oled.setCursor(10, pos);
      oled.print(F(" "));
      
      pos++;
      // limit the downward movement
      if (pos > 7) {
        pos = 7;
      }
      delay(debounceDelay);
    }

    // move the bird Up by pressing up button
    if (digitalRead(btn1) == LOW) {
      oled.setCursor(10, pos);
      oled.print(F(" "));
      
      pos--;
      // limit the upward movement
      if (pos < 0) {
        pos = 0;
      }
      delay(debounceDelay);
    }

    // display the bird
    oled.setCursor(10, pos);
    oled.print(F("e"));

    // generate the open space
    openWall(120 - (x * 10), k);
    openWall(120 - (x * 10), k + 1);

    // generate the walls
    for (int i = 0; i < k; i++) {
      solidWall(120 - (x * 10), i);
    }

    for (int i = k + 2; i < 8; i++) {
      solidWall(120 - (x * 10), i);
    }

    // move the walls forward in every render time
    if (millis() - lastMillis > speed) {
      lastMillis = millis();

      // clear the previous wall
      clearWall();
      
      x++;
      // reset the x coordinate when it hits max distance
      if (x > 12) {
        x = 0;
        // generate random number for the next open space
        k = random(1, 7);
      }

      // increase the score when the bird successfully 
      // enters through the open space
      if (win) {
        score += 1;
        win = false;
      }
    }

    // check if the bird enters through the open space
    // or crashes into the wall
    if (x == 11) {
      // entered through the open space
      if (pos == k || pos == k + 1) {
        oled.setCursor(10, pos);
        oled.print(F("e"));
        win = true;
      }

      // collides with the wall
      else {
        // change the mode to menu mode
        mode = 0;
        oled.setCursor(10, pos);
        oled.print(F(" "));

        oled.setCursor(30, 2);
        oled.print(F("Game Over!"));

        // display score
        oled.setCursor(30, 4);
        oled.print(F("Score : "));
        oled.print(score);

        delay(3000);
        // clear the screen and exit the game mode
        oled.clear();
        oled.switchRenderFrame();
        oled.clear();
        oled.switchRenderFrame();
      }
    }
  }
}

// generates solid walls
void solidWall(int px, int py) {
  oled.setCursor(px, py);
  oled.startData();
  
  for (int i = 0; i < 7; i++) {
    oled.sendData(255);
  }
  oled.endData();
}

// generates open space in the wall
void openWall(int px, int py) {
  oled.setCursor(px, py);
  oled.startData();
  
  for (int i = 0; i < 7; i++) {
    oled.sendData(0);
  }
  oled.endData();
}

// remove the wall
void clearWall() {
  for (int i = 0; i < 9; i++) {
    oled.setCursor(120 - (x * 10), i);
    oled.startData();
    
    for (int i = 0; i < 7; i++) {
      oled.sendData(0);
    }
    oled.endData();
  }
}
ATTINY8520PU