#include <LedControl.h>
#define CLK 13
#define DIN 11
#define CS 10
#define VERT_PIN A5
#define HORZ_PIN A4
LedControl lc = LedControl(DIN, CLK, CS, 4);
const int rows = 16;
const int cols = 16;
typedef struct {
int x;
int y;
} Coord;
typedef struct {
Coord *coords;
Coord head;
int size;
} CoordsArray;
CoordsArray snake;
int moveDirection = -1;
Coord food;
void setup() {
Serial.begin(115200);
for (int i = 0; i < lc.getDeviceCount(); i++) {
lc.shutdown(i, false);
lc.setIntensity(i, 8);
lc.clearDisplay(i);
}
randomSeed(analogRead(0));
pinMode(VERT_PIN, INPUT);
pinMode(HORZ_PIN, INPUT);
initSnake(6);
generateFood();
Serial.println("Game started! Good luck!");
}
void loop() {
updateSnake();
draw();
delay(300);
}
void initSnake(int length) {
snake.head = { 7, 9 };
snake.coords = malloc(length * sizeof(Coord));
snake.size = length;
for (int i = 0; i < length; i++) {
snake.coords[i].x = snake.head.x;
snake.coords[i].y = snake.head.y - snake.size + 1 + i;
}
// Serial.println(sizeof(snake.coords) / sizeof(Coord));
Serial.println("Snake spawned");
}
void pushCoords(Coord coord, CoordsArray *coordsArray) {
coordsArray->coords = realloc(coordsArray->coords, (coordsArray->size + 1) * sizeof(Coord));
coordsArray->coords[coordsArray->size].x = coord.x;
coordsArray->coords[coordsArray->size].y = coord.y;
coordsArray->size++;
}
void printCoords(Coord *coords, int length) {
for (int i = 0; i < length; i++) {
Serial.print(i);
Serial.print(" - {");
Serial.print(coords[i].x);
Serial.print(",");
Serial.print(coords[i].y);
Serial.println("}");
}
}
bool isSnakeCoord(Coord coord) {
bool is_snake = false;
for (int i = 0; i < snake.size; i++) {
if (snake.coords[i].x == coord.x && snake.coords[i].y == coord.y) {
is_snake = true;
}
}
return is_snake;
}
void draw() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
drawPixel({ i, j }, isSnakeCoord({ i, j }) || food.x == i && food.y == j);
}
}
}
int getDirection() {
int direction = -1;
int vert = analogRead(VERT_PIN);
int horz = analogRead(HORZ_PIN);
if (vert < 512 && moveDirection != 2) {
direction = 0;
} else if (vert > 512 && moveDirection != 0) {
direction = 2;
} else if (horz < 512 && moveDirection != 3) {
direction = 1;
} else if (horz > 512 && moveDirection != 1) {
direction = 3;
}
return direction;
}
void updateSnake() {
int direction = getDirection();
if (moveDirection != direction && direction != -1) {
moveDirection = direction;
}
// W 0
// A + D = 3 + 1
// S 2
switch (moveDirection) {
case 0: // up
snake.head.y++;
break;
case 1: // right
snake.head.x++;
break;
case 2: // down
snake.head.y--;
break;
case 3: // left
snake.head.x--;
break;
default: // wait for game to start
return;
}
// wall collision
if (snake.head.x < 0 || snake.head.x >= rows || snake.head.y < 0 || snake.head.y >= cols) {
free(snake.coords);
Serial.println("Game Over! You loose X_X");
delay(1000);
exit(0);
}
// food collision
if (snake.head.x == food.x && snake.head.y == food.y) {
pushCoords({ snake.head.x, snake.head.y }, &snake);
generateFood();
return;
}
// body collision
if (isSnakeCoord(snake.head)) {
free(snake.coords);
Serial.println("Game Over! You loose X_X");
delay(1000);
exit(0);
}
// win the game
if (snake.size == rows * cols) {
free(snake.coords);
Serial.println("Game Over! You WIN ^_^");
delay(1000);
exit(0);
}
// body move
for (int i = 0; i < snake.size - 1; i++) {
snake.coords[i].x = snake.coords[i + 1].x;
snake.coords[i].y = snake.coords[i + 1].y;
}
snake.coords[snake.size - 1].x = snake.head.x;
snake.coords[snake.size - 1].y = snake.head.y;
}
CoordsArray getEmptyCoords() {
CoordsArray empty;
empty.size = rows * cols - snake.size;
empty.coords = malloc(empty.size * sizeof(Coord));
int index = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (!isSnakeCoord({ i, j })) {
empty.coords[index].x = i;
empty.coords[index].y = j;
index++;
}
}
}
return empty;
}
void generateFood() {
CoordsArray empty = getEmptyCoords();
int index = rand() % empty.size;
food = empty.coords[index];
Serial.println("Food spawned");
free(empty.coords);
}
void drawPixel(Coord coord, bool active) {
int display = 3;
if (coord.x > 7) display -= 1;
if (coord.y > 7) display -= 2;
int led_x = 7 - coord.x % 8;
int led_y = coord.y % 8;
lc.setLed(display, led_y, led_x, active);
}