Last active
August 29, 2015 14:03
-
-
Save kamiyaowl/98df263356ecea657a22 to your computer and use it in GitHub Desktop.
snake for Arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <stdint.h> | |
typedef int8_t boolean; | |
#define true 1 | |
#define false 0 | |
#define WIDTH 32 | |
#define HEIGHT 16 | |
#define CENTER_X (WIDTH / 2) | |
#define CENTER_Y (HEIGHT / 2) | |
#define QUEUE_SIZE (WIDTH * HEIGHT) | |
#define UP 0 | |
#define DOWN 1 | |
#define LEFT 2 | |
#define RIGHT 3 | |
#define DIRECTIONS 4 | |
#define DIRECTION_NONE 10 | |
#define EMPTY '+' | |
#define FILL '*' | |
#define TARGET '@' | |
//ゲームグラフィックならめっちゃ楽に書ける | |
char snake_draw_field[HEIGHT][WIDTH]; | |
uint16_t current_x,current_y,target_x,target_y; | |
uint8_t snake_dir; | |
uint32_t search_data; | |
boolean is_found; | |
/* ======================================== */ | |
uint32_t queue_data[QUEUE_SIZE]; | |
uint16_t queue_head; | |
uint16_t queue_size; | |
void queue_init() { | |
uint16_t i; | |
for(i = 0 ; i < QUEUE_SIZE ; ++i) | |
queue_data[i] = 0; | |
queue_head = 0; | |
queue_size = 0;//ADCで最初にenqueueできるように | |
} | |
void enqueue(uint32_t data) { | |
if(queue_size >= QUEUE_SIZE) abort(); | |
uint16_t p = (queue_head + queue_size) % QUEUE_SIZE; | |
queue_data[p] = data; | |
++queue_size; | |
} | |
uint32_t dequeue() { | |
if(queue_size == 0) abort(); | |
uint32_t data = queue_data[queue_head]; | |
queue_head = (queue_head + 1) % QUEUE_SIZE; | |
--queue_size; | |
return data; | |
} | |
//Queueの要素全てに関数を適用します | |
void queue_all(void (*f)(uint32_t)){ | |
uint16_t i; | |
for(i = 0 ; i < queue_size ; ++i) | |
f(queue_data[(i + queue_head) % QUEUE_SIZE]); | |
} | |
void queue_print_all() { | |
uint16_t i; | |
for(i = 0 ; i < QUEUE_SIZE ; ++i) { | |
if(i == queue_head) printf("["); | |
if(i == (queue_head + queue_size) % QUEUE_SIZE) printf("]"); | |
printf("%0x ",queue_data[i]); | |
} | |
printf("\n"); | |
} | |
void queue_elem_print(uint32_t data) { | |
printf("%d ",data); | |
} | |
void queue_print() { | |
uint16_t i; | |
queue_all(queue_elem_print); | |
printf("\n"); | |
} | |
/* ======================================== */ | |
///private functions | |
uint16_t snake_score() { | |
return queue_size; | |
} | |
boolean snake_is_crear(){ | |
return queue_size == QUEUE_SIZE; | |
} | |
void snake_add_head(uint16_t x,uint16_t y){ | |
enqueue(x << 16 | y); | |
} | |
void snake_remove_tail(){ | |
dequeue(); | |
} | |
void snake_field_init(){ | |
uint16_t i,j; | |
for(j = 0 ; j < HEIGHT ; ++j) | |
for(i = 0 ; i < WIDTH ; ++i) | |
snake_draw_field[j][i] = EMPTY; | |
} | |
void snake_field_map(uint32_t data) { | |
snake_draw_field[data & 0xff][data >> 16] = FILL; | |
} | |
void snake_target_map(){ | |
snake_draw_field[target_y][target_x] = TARGET; | |
} | |
void snake_search(uint32_t data) { | |
if(data == search_data) is_found = true; | |
} | |
boolean snake_find(uint16_t x,uint16_t y){ | |
search_data = x << 16 | y; | |
is_found = false; | |
queue_all(snake_search); | |
return is_found; | |
} | |
void snake_create_target(){ | |
uint16_t nx,ny; | |
do { | |
nx = rand() % WIDTH; | |
ny = rand() % HEIGHT; | |
}while(snake_find(nx,ny)); | |
//apply | |
target_x = nx; | |
target_y = ny; | |
} | |
boolean snake_ahead(uint8_t dir){ | |
if(dir != DIRECTION_NONE) snake_dir = dir; | |
//valid | |
//アンダーフローを考慮 | |
uint16_t nx = current_x; | |
uint16_t ny = current_y; | |
switch(snake_dir) { | |
case UP: | |
--ny; | |
break; | |
case DOWN: | |
++ny; | |
break; | |
case LEFT: | |
--nx; | |
break; | |
case RIGHT: | |
++nx; | |
break; | |
} | |
if(nx >= WIDTH || ny >= HEIGHT) return false; | |
if(snake_find(nx,ny)) return false; | |
//add | |
current_x = nx; | |
current_y = ny; | |
snake_add_head(current_x,current_y); | |
//target get? | |
if(current_x == target_x && current_y == target_y) { | |
if(snake_is_crear()) { | |
printf("+++++ GAME CLEAR +++++\n"); | |
return true; | |
} | |
snake_create_target(); | |
} else { | |
snake_remove_tail(); | |
} | |
return true; | |
} | |
/* ======================================== */ | |
//public functions | |
void snake_init() { | |
queue_init(); | |
snake_field_init(); | |
current_x = CENTER_X; | |
current_y = CENTER_Y; | |
snake_add_head(current_x,current_y); | |
snake_dir = rand() % DIRECTIONS; | |
snake_create_target(); | |
} | |
boolean snake_update(uint8_t dir) { | |
if(!snake_ahead(dir)) return false; | |
//ゲーム描画なら別の方法でかける | |
snake_field_init(); | |
snake_target_map(); | |
queue_all(snake_field_map); | |
return true; | |
} | |
void snake_print() { | |
uint16_t i,j; | |
//init | |
for(j = 0 ; j < HEIGHT ; ++j) { | |
for(i = 0 ; i < WIDTH ; ++i) { | |
printf("%c",snake_draw_field[j][i]); | |
} | |
printf("\n"); | |
} | |
printf("score = %d\n",snake_score()); | |
} | |
/* ======================================== */ | |
int main(void) { | |
uint8_t dir = DIRECTION_NONE; | |
char c; | |
srand(time(NULL));//TODO replace other | |
snake_init(); | |
while(true) { | |
printf("W,S,A,D>"); | |
scanf("%c%*c",&c); | |
switch(c){ | |
case 'w': | |
dir = UP; | |
break; | |
case 's': | |
dir = DOWN; | |
break; | |
case 'a': | |
dir = LEFT; | |
break; | |
case 'd': | |
dir = RIGHT; | |
break; | |
case 'n': | |
snake_init(); | |
break; | |
case 'q': | |
return 0; | |
} | |
if(!snake_update(dir)){ | |
printf("===== GAME OVER =====\n"); | |
printf("score = %d\n",snake_score()); | |
snake_init(); | |
} else { | |
snake_print(); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment