#include <MD_MAX72xx.h>
#include <SPI.h>
#include <Servo.h>
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 2
#define CLK_PIN  13
#define DATA_PIN 11
#define CS_PIN   10
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
Servo myservo;
int servoPin = 9;
const int VRx = A0;
const int VRy = A1;
const int SW = 2;
int xPosition = 0;
int yPosition = 0;
int a = 0;
int b = 1; 
int snakeX[64], snakeY[64];
int snakeLength = 3;
int initialSnakeLength = 3;
int foodX, foodY;
int direction = 1; 
int lastDirection = 1; 
unsigned long lastMoveTime = 0; 
const unsigned long moveInterval = 500; 
void setup() {
  mx.begin();
  mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY / 2);
  mx.clear();
  myservo.attach(servoPin);
  myservo.write(90);
  pinMode(SW, INPUT_PULLUP);
  initializeSnake();
  randomSeed(analogRead(0));
  spawnFood();
}
void loop() {
  xPosition = analogRead(VRx);
  yPosition = analogRead(VRy);
  a = digitalRead(SW);
  if (yPosition < 300 && lastDirection != 2) {
    direction = 0;
  } else if (xPosition > 700 && lastDirection != 3) {
    direction = 1;
  } else if (yPosition > 700 && lastDirection != 0) {
    direction = 2;
  } else if (xPosition < 300 && lastDirection != 1) {
    direction = 3;
  }
  if (direction != lastDirection) {
    lastDirection = direction;
  }
  if (a == LOW && b == HIGH) {
    resetGame();
  }
  b = a;
  unsigned long currentTime = millis();
  if (currentTime - lastMoveTime >= moveInterval) {
    lastMoveTime = currentTime;
    moveSnake();
    if (checkCollision()) {
      resetGame();
    }
    if (checkFood()) {
      snakeLength++;
      spawnFood();
    }
    if (snakeLength >= 10) {
      myservo.write(45);
      delay(500);
      myservo.write(135);
      delay(500);
    }
    drawGame();
  }
}
void moveSnake() {
  for (int i = snakeLength - 1; i > 0; i--) {
    snakeX[i] = snakeX[i - 1];
    snakeY[i] = snakeY[i - 1];
  }
  if (direction == 0) snakeY[0]--;
  else if (direction == 1) snakeX[0]++;
  else if (direction == 2) snakeY[0]++;
  else if (direction == 3) snakeX[0]--;
}
bool checkCollision() {
  if (snakeX[0] < 0 || snakeX[0] >= 16 || snakeY[0] < 0 || snakeY[0] >= 8) {
    return true;
  }
  for (int i = 1; i < snakeLength; i++) {
    if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
      return true;
    }
  }
  return false;
}
bool checkFood() {

  if (snakeX[0] == foodX && snakeY[0] == foodY) {
    return true;
  }
  return false;
}
void spawnFood() {
  bool validPosition = false;
  while (!validPosition) {
    foodX = random(0, 16);
    foodY = random(0, 8);
    validPosition = true;
    for (int i = 0; i < snakeLength; i++) {
      if (snakeX[i] == foodX && snakeY[i] == foodY) {
        validPosition = false;
        break;
      }
    }
  }
}
void drawGame() {
  mx.clear();
  mx.setPoint(foodY, foodX, true);
  for (int i = 0; i < snakeLength; i++) {
    mx.setPoint(snakeY[i], snakeX[i], true);
  }
}
void initializeSnake() {
  snakeLength = initialSnakeLength;
  snakeX[0] = 8;
  snakeY[0] = 4;
  snakeX[1] = 7;
  snakeY[1] = 4;
  snakeX[2] = 6;
  snakeY[2] = 4;
  direction = 1;
  lastDirection = 1;
}
void resetGame() {
  initializeSnake();
  myservo.write(90);
  spawnFood();
}