#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);


int positionen[100][2] = {{12, 16}, {12, 17}, {12, 18}};   
int apple_position[2];
int score = 0;
int highscore = 0;
int speed = 300;
int elemente = 3;
int richtung = 1;


void setup() {
  pinMode(2, INPUT_PULLUP);
  tft.begin();
}

void loop() {
  game();                               
}


void game() {
  draw_design();
  spawn_apple();

  for (int i = 0; i < elemente; i++) {
    draw_quadrat(positionen[i][0], positionen[i][1], ILI9341_BLACK); 
  }

  check_direction();
}

void check_direction(){ 
  while (true) {
    if (richtung == 1) {      
      if (positionen[0][1] == 3) {
        gameover();
      }
      step();
      positionen[0][1] -= 1;
    }

    else if (richtung == 2) {     
      if (positionen[0][0] == 22) {
        gameover();
      }
      step();
      positionen[0][0] += 1;
    }

    else if (richtung == 3) {      
      if (positionen[0][1] == 30) {
        gameover();
      }
      step();
      positionen[0][1] += 1;
    }

    else if (richtung == 4) {     
      if (positionen[0][0] == 1) {
        gameover();
      }
      step();
      positionen[0][0] -= 1;
    }

    draw_quadrat(positionen[0][0], positionen[0][1], ILI9341_BLACK); 
    check_and_delay(speed);
  }
}

void step() { 
  int last = elemente - 1;
  draw_quadrat(positionen[last][0], positionen[last][1], ILI9341_DARKGREEN);

  for (int i = last; i > 0; i--) {
    positionen[i][0] = positionen[i - 1][0];
    positionen[i][1] = positionen[i - 1][1];
  }
  check_apple();
  check_collision();
}


void check_apple() { 
 
  if (positionen[0][0] == apple_position[0] and positionen[1][1] == apple_position[1]) {
    score += 1;
    draw_score();
    append_square();
    spawn_apple();

    if (300 - score * 10 < 80) {
      speed = 50;                           
    } else {
      speed = 300 - score * 10; 
    }
  }
}

void check_collision() { 
  for (int i = 2; i < elemente; i++) {
    if (positionen[0][0] == positionen[i][0] and positionen[0][1] == positionen[i][1]) {
      gameover();
    }
  }
}


void append_square() {
  positionen[elemente][0] = positionen[elemente - 1][0];
  positionen[elemente][1] = positionen[elemente - 1][1];

  elemente ++;
}

void check_and_delay(int ms) { 
  for (int i = 0; i < ms; i++) {
    delay(1);
    if (analogRead(A0) == 1023 and richtung != 3) {
      richtung = 1; 
    }
    if (analogRead(A1) == 0    and richtung != 4) {
      richtung = 2; 
    }
    if (analogRead(A0) == 0    and richtung != 1) {
      richtung = 3; 
    }
    if (analogRead(A1) == 1023 and richtung != 2) {
      richtung = 4; 
    }
  }
}

void draw_design() { 
  tft.fillScreen(ILI9341_DARKGREEN);    
  tft.drawRect(9, 29, 222, 282, ILI9341_BLACK); 

  tft.setCursor(50, 5);
  tft.setTextColor(ILI9341_BLACK);
  tft.setTextSize(3);
  tft.println("SCORE: ");
  tft.setCursor(175, 5);
  tft.println(score);
  draw_apple();
}

void draw_score () { 
  tft.setCursor(175, 5);
  tft.setTextSize(3);
  tft.setTextColor(ILI9341_DARKGREEN);
  tft.println(score - 1);

  tft.setCursor(175, 5);
  tft.setTextSize(3);
  tft.setTextColor(ILI9341_BLACK);
  tft.println(score);
}

void spawn_apple() {  
  int random_x = random(1, 23); 
  int random_y = random(3, 31);   

  for (int i = 0; i < sizeof(positionen) / 4; i++) { 
    if (positionen[i][0] == random_x and positionen[i][1] == random_y) {
      spawn_apple();
      exit(0);
    }
  }

  apple_position[0] = random_x;
  apple_position[1] = random_y;
  draw_quadrat(random_x, random_y, ILI9341_RED);  
}

void draw_quadrat (int x_pos, int y_pos, int color) {
  for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
      tft.drawPixel(x_pos * 10 + i, y_pos * 10 + j, color);
    }
  }
}


void draw_apple() { 
  tft.fillCircle(220, 17, 8, ILI9341_RED);
  tft.drawCircle(220, 17, 9, ILI9341_BLACK);
  tft.fillCircle(223, 8, 2, ILI9341_GREEN);
  tft.fillCircle(224, 8, 2, ILI9341_GREEN);
  tft.fillCircle(224, 9, 2, ILI9341_GREEN);
  tft.drawLine(220, 13, 223, 3, ILI9341_MAROON);
  tft.drawLine(219, 13, 222, 3, ILI9341_MAROON);
}

void check_highscore() { 
  if (score > highscore) {    
    highscore = score;

    tft.setCursor(40, 230);        
    tft.setTextColor(ILI9341_YELLOW);
    tft.setTextSize(2);
    tft.println("NEW HIGHSCORE!");
  }

  tft.setCursor(40, 5);          
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println("HIGHSCORE:");
  tft.setCursor(180, 5);
  tft.println(highscore);
}

void gameover() { 
  tft.fillScreen(ILI9341_BLACK);    
  tft.setCursor(15, 140);
  tft.setTextColor(ILI9341_RED);
  tft.setTextSize(4);
  tft.println("GG LOSER");

  tft.setCursor(70, 200);       
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.println("Score:");
  tft.setCursor(155, 200);
  tft.println(score);

  check_highscore();

  tft.setCursor(7, 300);           
  tft.setTextColor(ILI9341_DARKGREY);
  tft.setTextSize(2);
  tft.println("<continue>");

  while (digitalRead(2) == HIGH) {};
  reset_game();
}

void reset_game() { 

  richtung = 1;
  score = 0;
  speed = 300;
  elemente = 3;

  for (int i = 0; i < 3; i++) {
    positionen[i][0] = 12;
    positionen[i][1] = 16 + i;
  }

  game();
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd1:VCC
lcd1:GND
lcd1:CS
lcd1:RST
lcd1:D/C
lcd1:MOSI
lcd1:SCK
lcd1:LED
lcd1:MISO
joystick1:VCC
joystick1:VERT
joystick1:HORZ
joystick1:SEL
joystick1:GND