#include <MD_MAX72xx.h>

#define MAX_DEVICES  2
#define MAX_INTENSITY  5  // Adjust intensity as needed

const int maxX = MAX_DEVICES * 8 - 1;
const int maxY = 7;

#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

#define VERT_PIN A0
#define HORZ_PIN A1
#define SEL_PIN  2

MD_MAX72XX mx = MD_MAX72XX(MD_MAX72XX::PAROLA_HW, CS_PIN, MAX_DEVICES);

int snakeMaxLength = 20;  // Maximum length of the snake
int snakeLength = 1;      // Initial length of the snake
int snakeX[20];           // Array to store snake segments x-coordinates
int snakeY[20];           // Array to store snake segments y-coordinates
int foodX;                // X-coordinate of food
int foodY;                // Y-coordinate of food
int direction = 0;        // 0 - right, 1 - down, 2 - left, 3 - up
bool gameover = false;

void setup() {
  mx.begin();
  mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY);
  mx.clear();
  
  pinMode(VERT_PIN, INPUT);
  pinMode(HORZ_PIN, INPUT);
  pinMode(SEL_PIN, INPUT_PULLUP);
  
  // Initialize snake starting position
  snakeX[0] = 0;
  snakeY[0] = 0;
  
  // Place initial food randomly
  randomSeed(analogRead(0));
  spawnFood();
}

void loop() {
  if (!gameover) {
    handleInput();
    moveSnake();
    checkCollision();
    updateDisplay();
    delay(200);  // Adjust speed of the game
  }
}

void handleInput() {
  int horz = analogRead(HORZ_PIN);
  int vert = analogRead(VERT_PIN);
  
  if (vert < 300 && direction != 3) {
    direction = 1;  // Down
  } else if (vert > 700 && direction != 1) {
    direction = 3;  // Up
  }
  if (horz > 700 && direction != 2) {
    direction = 0;  // Right
  } else if (horz < 300 && direction != 0) {
    direction = 2;  // Left
  }
  
  if (digitalRead(SEL_PIN) == LOW) {
    gameover = true;
    mx.clear();
  }
}

void moveSnake() {
  // Move the snake body
  for (int i = snakeLength - 1; i > 0; i--) {
    snakeX[i] = snakeX[i - 1];
    snakeY[i] = snakeY[i - 1];
  }
  
  // Move the snake head in the current direction
  switch (direction) {
    case 0:  // Right
      snakeX[0]++;
      break;
    case 1:  // Down
      snakeY[0]++;
      break;
    case 2:  // Left
      snakeX[0]--;
      break;
    case 3:  // Up
      snakeY[0]--;
      break;
  }
  
  // Check if snake hits the screen edge
  if (snakeX[0] < 0 || snakeX[0] > maxX || snakeY[0] < 0 || snakeY[0] > maxY) {
    gameover = true;
  }
  
  // Check if snake eats the food
  if (snakeX[0] == foodX && snakeY[0] == foodY) {
    snakeLength++;
    if (snakeLength < snakeMaxLength) {
      spawnFood();
    } else {
      gameover = true;
    }
  }
}

void checkCollision() {
  // Check if snake collides with itself
  for (int i = 1; i < snakeLength; i++) {
    if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
      gameover = true;
      break;
    }
  }
}

void updateDisplay() {
  mx.clear();
  
  // Draw snake
  for (int i = 0; i < snakeLength; i++) {
    mx.setPoint(snakeX[i], snakeY[i], true);
  }
  
  // Draw food
  mx.setPoint(foodX, foodY, true);
  
  mx.update();
}

void spawnFood() {
  foodX = random(0, maxX + 1);
  foodY = random(0, maxY + 1);
}