#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 4
MD_MAX72XX mx = MD_MAX72XX(MD_MAX72XX::PAROLA_HW, CS_PIN, MAX_DEVICES);
int x = 0;
int y = 0;
//// Buttons used for controlling the snake
#define left_button 2
#define right_button 3
volatile byte move_left = 0;
volatile byte move_right = 0;
// Varibles for snake
int snake_l = 2;
const int max_len = 30;
int snake[max_len][2];
byte cur_heading = 0;
// Variable for food blob
int blob[2] = { 0, 0 };
int is_eaten = 1;
// The game scene
byte scene[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Function to initialize the game variables
void init_game() {
is_eaten = 1;
move_left = 0;
move_right = 0;
cur_heading = 0;
snake_l = 2;
for (int i = 0; i < max_len; i++)
for (int j = 0; j < 2; j++)
snake[i][j] = 0;
snake[max_len - 1][0] = 2;
snake[max_len - 1][1] = 5;
snake[max_len - 2][0] = 1;
snake[max_len - 2][1] = 5;
refresh_scene();
while ((move_left || move_right) == 0)
;
move_left = 0;
move_right = 0;
}
// Function to draw snake on gamescene
void spawn_snake() {
// If the snake goes out of the scene, it enters from the other side
for (int j = max_len - snake_l; j < max_len; j++) {
if (snake[j][0] <= 0)
snake[j][0] = 8 + snake[j][0];
else if (snake[j][0] >= 9)
snake[j][0] = snake[j][0] - 8;
if (snake[j][1] <= 0)
snake[j][1] = 8 + snake[j][1];
else if (snake[j][1] >= 9)
snake[j][1] = snake[j][1] - 8;
// Draw the snake on the LED matrix
scene[snake[j][0] - 1] |= (1 << (snake[j][1] - 1));
}
}
// Function to update the position and length of the snake
void snake_move() {
// If snake eats a blob...Increase length
if (snake[max_len - 1][0] == blob[0] && snake[max_len - 1][1] == blob[1]) {
is_eaten = 1;
snake_l += 1;
}
// Move each pixel forward
for (int i = snake_l - 1; i >= 1; i--) {
snake[max_len - 1 - i][0] = snake[max_len - i][0];
snake[max_len - 1 - i][1] = snake[max_len - i][1];
}
// Move the head according to button input
if (move_left == 1) {
if (cur_heading == 0) {
cur_heading = 1;
snake[max_len - 1][1] -= 1;
} else if (cur_heading == 1) {
cur_heading = 2;
snake[max_len - 1][0] -= 1;
} else if (cur_heading == 2) {
cur_heading = 3;
snake[max_len - 1][1] += 1;
} else if (cur_heading == 3) {
cur_heading = 0;
snake[max_len - 1][0] += 1;
}
move_left = 0;
} else if (move_right == 1) {
if (cur_heading == 0) {
cur_heading = 3;
snake[max_len - 1][1] += 1;
} else if (cur_heading == 1) {
cur_heading = 0;
snake[max_len - 1][0] += 1;
} else if (cur_heading == 2) {
cur_heading = 1;
snake[max_len - 1][1] -= 1;
} else if (cur_heading == 3) {
cur_heading = 2;
snake[max_len - 1][0] -= 1;
}
move_right = 0;
} else {
if (cur_heading == 0) {
snake[max_len - 1][0] += 1;
} else if (cur_heading == 1) {
snake[max_len - 1][1] -= 1;
} else if (cur_heading == 2) {
snake[max_len - 1][0] -= 1;
} else if (cur_heading == 3) {
snake[max_len - 1][1] += 1;
}
}
}
// Function to generate a blob and draw the blob on the gamescene
void blob_generator() {
// If blob is eaten by the snake, generate one
if (is_eaten) {
blob[0] = random(1, 9);
blob[1] = random(1, 9);
}
// Draw the blob on the gamescene
scene[blob[0] - 1] |= (1 << (blob[1] - 1));
is_eaten = 0;
}
// Function to redraw the gamescene to the LED matrix with updated variables
void refresh_scene() {
for (int i = 0; i < 8; i++)
scene[i] = 0x00;
snake_move();
spawn_snake();
blob_generator();
for (int i = 1; i < 9; i++)
//SendData(i, scene[i - 1]);
mx.setPoint(i, scene[i - 1], true);
mx.update();
}
// Callback for interrupt attached to left button
void update_left() {
move_left = 1;
}
// Callback for interrupt attached to right button
void update_right() {
move_right = 1;
}
void setup() {
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);
//
// Random seed generation...Uses the noise in the analog channel 0 to create a random seed
randomSeed(analogRead(0));
// Attach interrupts to the buttons
attachInterrupt(digitalPinToInterrupt(left_button), update_left, FALLING);
attachInterrupt(digitalPinToInterrupt(right_button), update_right, FALLING);
// Enable interrupt
sei();
// Start the game
init_game();
}
// the loop function runs over and over again forever
void loop() {
int horz = analogRead(HORZ_PIN);
int vert = analogRead(VERT_PIN);
// Check if snake is at max length
if (snake_l == max_len) {
// If yes, display win and restart
byte win_scene[8] = { B11100011, B00100100, B01000010, B11100100, B00000011, 0, B00011100, 0 };
for (int i = 1; i < 9; i++)
//SendData(i, win_scene[i - 1]);
mx.setPoint(i, win_scene[i - 1], true);
mx.update();
delay(5000);
init_game();
}
// Check if snake has collided with itself
for (int i = 0; i < max_len - 1; i++) {
if (snake[i][0] == snake[max_len - 1][0] && snake[i][1] == snake[max_len - 1][1]) {
// If yes, blink all leds and restart the game
delay(1000);
for (int j = 0; j < 4; j++) {
//SendData(DISPLAY_TEST, 0x01);
mx.setPoint(0, 0x01, true);
mx.update();
delay(500);
//SendData(DISPLAY_TEST, 0x00);
mx.setPoint(0, 0x00, true);
mx.update();
delay(500);
}
init_game();
break;
}
}
// Keep refreshing the matrix with updated data....
refresh_scene();
// ...Every 0.5 secs
delay(250);
/*if (vert < 300) {
y = min(y + 1, maxY);
}
if (vert > 700) {
y = max(y - 1, 0);
}
if (horz > 700) {
x = min(x + 1, maxX);
}
if (horz < 300) {
x = max(x - 1, 0);
}
if (digitalRead(SEL_PIN) == LOW) {
mx.clear();
}
mx.setPoint(y, x, true);
mx.update();
delay(100);*/
}