arduino-snake/snake.ino

266 lines
7.5 KiB
C++

#define BOARD_LENGTH 8
#define SNAKE_MAX_SIZE 32
struct pair {
int x;
int y;
};
class Snake {
private:
char state;
int snake_size;
pair pos[64];
pair get_next_move(pair p);
pair fruit_pos;
bool fruit;
public:
Snake() {
this->state = 'R';
this->snake_size = 4;
fruit = false;
for (int i = 0; i < snake_size ; ++i) {
pair p;
p.x = 7;
p.y = i;
this->pos[0] = p;
}
}
void change_state(char state) {
if (state != 'I') {
// if currently moving up or down and state change is
// left or right, then update
if ((state == 'R' || state == 'L') &&
(this->state == 'U' || this->state == 'D')) {
this->state = state;
}
else if ((state == 'U' || state == 'D') &&
(this->state == 'R' || this->state == 'L')) {
this->state = state;
}
}
//else ignore
}
void snake_to_matrix(int (*pixels)[BOARD_LENGTH]) {
for (int i = 0; i < BOARD_LENGTH; ++i) {
for (int j = 0; j < BOARD_LENGTH; ++j) {
pixels[i][j] = LOW; // CLEAR ALL PIXELS;
}
}
for (int i = 0; i < snake_size; ++i) {
pair p = pos[i];
pixels[p.x][p.y] = HIGH; // TURN ON PIXELS OF SNAKE
}
if (fruit) {
pixels[fruit_pos.x][fruit_pos.y] = HIGH;
}
}
pair snake_head() {
return pos[0];
}
void generate_fruit() {
if (!fruit) {
fruit = true;
// random inclusive (starts at 0)
fruit_pos.x = random(7);
fruit_pos.y = random(7);
}
}
void grow();
void next_move() {
for (int i = snake_size; i > 0; --i) {
pos[i] = pos[i - 1];
}
pos[0] = get_next_move(pos[0]);
if (fruit) {
if (pos[0].x == fruit_pos.x && pos[0].y == fruit_pos.y) {
grow();
fruit = false;
}
}
}
bool eats_itself() {
for (int i = 1; i < snake_size; ++i) {
if (pos[0].x == pos[i].x && pos[0].y == pos[i].y) {
return true;
}
}
return false;
}
};
pair Snake::get_next_move(pair p)
{
pair r(p);
switch (state) {
case 'U':
r.x = (p.x + BOARD_LENGTH - 1) % BOARD_LENGTH;
r.y = p.y;
break;
case 'D':
r.x = (p.x + 1) % BOARD_LENGTH;
r.y = p.y;
break;
case 'R':
r.x = p.x;
r.y = (p.y + 1) % BOARD_LENGTH;
break;
case 'L':
r.x = p.x;
r.y = (p.y + BOARD_LENGTH - 1) % BOARD_LENGTH;
break;
}
return r;
}
void Snake::grow()
{
if (snake_size < SNAKE_MAX_SIZE) {
pos[snake_size] = pos[snake_size - 1];
++snake_size;
}
}
const int row[8] = { 2, 7, 19, 5, 13, 18, 12, 16 };
const int col[8] = { 6, 11, 10, 3, 17, 4, 8, 9 };
// 2-dimensional array of pixels:
int pixels[8][8];
// cursor position:
int x = 5;
int y = 5;
Snake snake;
// A BIG SAD CROSS
int dead[8][8] = {
{HIGH, LOW, LOW, LOW, LOW, LOW, LOW, HIGH},
{LOW, HIGH, LOW, LOW, LOW, LOW, HIGH, LOW},
{LOW, LOW, HIGH, LOW, LOW, HIGH, LOW, LOW},
{LOW, LOW, LOW, HIGH, HIGH, LOW, LOW, LOW},
{LOW, LOW, LOW, HIGH, HIGH, LOW, LOW, LOW},
{LOW, LOW, HIGH, LOW, LOW, HIGH, LOW, LOW},
{LOW, HIGH, LOW, LOW, LOW, LOW, HIGH, LOW},
{HIGH, LOW, LOW, LOW, LOW, LOW, LOW, HIGH},
};
/**
* The setup routine runs once when you press reset.
*/
void setup()
{
Serial.begin(9600); // 9600 bps
// initialize the I/O pins as outputs
// iterate over the pins:
for (int this_pin = 0; this_pin < 8; ++this_pin) {
// initialize the output pins:
pinMode(col[this_pin], OUTPUT);
pinMode(row[this_pin], OUTPUT);
// take the col pins (i.e. the cathodes) high to ensure that
// the LEDS are off:
digitalWrite(col[this_pin], HIGH);
}
// initialize the pixel matrix:
for (int x = 0; x < 8; ++x) {
for (int y = 0; y < 8; ++y) {
pixels[x][y] = HIGH;
}
}
randomSeed(analogRead(0));
}
/**
* The loop routine runs over and over again forever.
*/
void loop()
{
snake.generate_fruit();
snake.next_move();
snake.snake_to_matrix(pixels);
for (int i = 0; i < 30; ++i) {
display_pixels();
snake.change_state(read_sensors());
}
// draw the screen:
if (snake.eats_itself()) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 100; ++j) {
display_pixels();
}
delay(500);
}
for (int i = 0; i < 8; ++i) {
for (int j = 0; j < 8; ++j) {
pixels[i][j] = dead[i][j];
}
}
while (true) {
display_pixels();
}
}
}
/**
* Prints the pixels array in the matrix
*/
void display_pixels()
{
for (int c = 0; c < 8; ++c) {
digitalWrite(col[c], LOW);
for (int r = 0; r < 8; ++r) {
digitalWrite(row[r], pixels[r][c]);
}
delay(1);
display_clear();
}
}
/**
* Remove empty display light
* 清空显示
*/
void display_clear()
{
for (int i = 0; i < 8; ++i) {
digitalWrite(row[i], LOW);
digitalWrite(col[i], HIGH);
}
}
/**
* Returns the current joystick input with some leeway
* I means Iddle
* L means Left
* R means Right
* U means Up
* D means Down
*/
char read_sensors()
{
//int clicked = digitalRead(z); // if 0, then clicked
//if(!clicked) return 'C';
x = map(analogRead(A0), 0, 1023, 0, 10) - 5;
y = map(analogRead(A1), 0, 1023, 0, 10) - 5;
// test if joystick is the middle with some leeway
if (abs(x) <= 3 && abs(y) <= 3) {
return 'I';
// test if move in x axis is > than in y axis
} else if (abs(x) > abs(y)) {
if (x > 1) {
return 'R';
} else {
return 'L';
}
} else {
if (y > 1) {
return 'U';
} else {
return 'D';
}
}
return 'I';
}