#include <MD_MAX72xx.h>
#define	MAX_DEVICES	1
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 x = 0;
int y = 0;
// Cria a matriz
char matriz [8][8];
//preenchidos
int preenchidos [30][2];
// Cria a variável do Level
byte level = 1;
// cria a variável para a comida
byte comidax;
byte comiday;
// Cria variável para o tamanho da cobrinha
int tam = 1;
// cria a variável do sentido/direção que a cobrinha vai
// 1 vai para direita
// 2 vai para esquerda
// 3 vai para cima
// 4 vai para baixo
byte sentido = 0;
#define DIREITA 1
#define ESQUERDA 2
#define CIMA 3
#define BAIXO 4
//
//Função Inicio zera tudas as variáveis
void inicio(){
  x = 0;
  y = 0;
  tam = 1;
  sentido=1;
  level = 1;
   for (int l = 0; l < 8; l++){
    for (int k =0; k < 8; k++){
      matriz[l][k]='z';
    }
   }
   //comida();
}
// Função aparece comida
void comida() {
  // Conta os espaços disponíveis
  int espacosLivres = 0;
  for (int l = 0; l < 8; l++) {
    for (int k = 0; k < 8; k++) {
      if (matriz[l][k] == 'z') espacosLivres++;
    }
  }
  // Se não houver espaço livre, termina
  if (espacosLivres == 0) return;
  bool ocupado = true;
  while (ocupado) {
    comidax = random(0, 8);
    comiday = random(0, 8);
    if (matriz[comiday][comidax] == 'z') { // Verifica se está livre
      ocupado = false;
      matriz[comiday][comidax] = 'x';
    }
  }
}
//
void move() {
  // Atualiza a posição da cobra com base no sentido
  int novoX = x;
  int novoY = y;
  if (sentido == DIREITA) {
    novoX = min(x + 1, maxX);
  } else if (sentido == ESQUERDA) {
    novoX = max(x - 1, 0);
  } else if (sentido == CIMA) {
    novoY = max(y - 1, 0);
  } else if (sentido == BAIXO) {
    novoY = min(y + 1, maxY);
  }
  // Verifica colisão com o corpo ou bordas
  if (matriz[novoY][novoX] == 'c') {
    Serial.println("Game Over!");
    inicio();
    return;
  }
  // Verifica se a cobra comeu comida
  if (novoX == comidax && novoY == comiday) {
    tam++; // Aumenta o tamanho
    comida(); // Gera nova comida
    level++; // Incrementa o nível
  } else {
    // Atualiza o rastro e remove a cauda
    int caudaX = preenchidos[tam - 1][1];
    int caudaY = preenchidos[tam - 1][0];
    matriz[caudaY][caudaX] = 'z'; // Remove a cauda
  }
  // Atualiza matriz e rastro
  for (int i = tam - 1; i > 0; i--) {
    preenchidos[i][0] = preenchidos[i - 1][0];
    preenchidos[i][1] = preenchidos[i - 1][1];
  }
  preenchidos[0][0] = y;
  preenchidos[0][1] = x;
  matriz[y][x] = 'c'; // Marca nova posição da cabeça
  x = novoX;
  y = novoY;
  matriz[y][x] = 'c'; // Define nova posição na matriz
  delay(1000 / (level + 1)); // Controla a velocidade
  Serial.println("Movimento atualizado.");
}
  // Atualiza a matriz e o rastro da cobrinha
  atualizaRastro(); // Atualiza o corpo da cobra
  matriz[y][x] = 'c'; // Atual posição da cabeça vira corpo
  x = novoX;          // Atualiza coordenadas da cabeça
  y = novoY;
  matriz[y][x] = 'c'; // Nova posição da cabeça
  if (x == comidax && y == comiday) {
    tam++; // Aumenta o tamanho da cobra
    comida(); // Gera nova comida
    level++; // Avança o nível
  }
  Serial.println("Movimento atualizado.");
  delay(1000 / (level + 1)); // Controla a velocidade do jogo
}
//
void atualizaRastro() {
  // Remove a cauda da cobra na matriz
  int caudaX = preenchidos[tam - 1][1];
  int caudaY = preenchidos[tam - 1][0];
  matriz[caudaY][caudaX] = 'z'; // Limpa a última posição
  
  // Move o rastro
  for (int i = tam - 1; i > 0; i--) {
    preenchidos[i][0] = preenchidos[i - 1][0];
    preenchidos[i][1] = preenchidos[i - 1][1];
  }
  preenchidos[0][0] = y;
  preenchidos[0][1] = x;
}
//
void exibe() {
  mx.clear();
  void exibe() {
  mx.clear();
  // Exibe o rastro da cobra
  for (int i = 0; i < tam; i++) {
    mx.setPoint(preenchidos[i][0], preenchidos[i][1], true);
  }
  // Exibe a comida
  mx.setPoint(comiday, comidax, true);
  mx.update();
}
//
void setup() {
  // Serial apenas para printar variáveis na tela e testar
  Serial.begin(9600);
  mx.begin();
  mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY / 2);
  mx.clear();
  pinMode(VERT_PIN, INPUT);
  pinMode(HORZ_PIN, INPUT);
  pinMode(SEL_PIN, INPUT_PULLUP);
   inicio();
}
// o loop
void loop() {
  int horz = analogRead(HORZ_PIN);
  int vert = analogRead(VERT_PIN);
  if (vert < 300) {
    // vai para baixo
    sentido = 3;
  }
  if (vert > 700) {
    // vai para cima
    sentido = 4;
  }
  if (horz > 700) {
    // vai para esquerda
    sentido = 2;
  }
  if (horz < 300) {
    // vai para direita
    sentido = 1;
  }
  move();
  exibe();
  Serial.print("Y: ");
  Serial.print(y);
  Serial.print(" X: ");
  Serial.println(x);
}