#include "Snake.h" #include "string.h" #include "GameUtil.h" #define FOOD 129 #define BOUNDRY 130 #define START_COL 3 #define START_ROW 7 enum { START_STATE, RUNNING_STATE, LOST_STATE, }; static int key_state[4]; static uint32_t seed; static int game_tick = 0; static uint8_t board[height][width]; static pos_t no_dir = {0, 0}; static pos_t up_dir = {-1, 0}; static pos_t down_dir = {1, 0}; static pos_t left_dir = {0, -1}; static pos_t right_dir = {0, 1}; static pos_t snake_last_dir = {0, 0}; static pos_t snake_dir = {0, 0}; static pos_t snake_head = {7, 3}; static pos_t snake_tail = {5, 3}; static int snake_len = 3; static int snake_tick = 2; static void generate_food() { int row = rand(&seed) % height; int col = rand(&seed) % width; int i = 0; while (board[row][col] && i < 10) { row = rand(&seed) % height; col = rand(&seed) % width; i++; } i = 0; while (board[row][col] && i < height * width) { col += 1; row += col / width; row = row % height; col = col % width; i++; } board[row][col] = FOOD; } static void snake_respawn() { snake_dir = down_dir; snake_last_dir = no_dir; memset(board, 0, sizeof(board)); snake_tail.r = snake_head.r = START_ROW; snake_tail.c = snake_head.c = START_COL; snake_len = 1; snake_tick = 0; seed = game_tick; board[snake_head.r][snake_head.c] = snake_tick % 128 + 1; generate_food(); } int snake_init() { memset(key_state, 0, sizeof(key_state)); snake_respawn(); return 0; } static pos_t add_pos(pos_t a, pos_t b) { pos_t res; res.r = a.r + b.r; res.c = a.c + b.c; return res; } static int equ_pos (pos_t a, pos_t b) { return a.r == b.r && a.c == b.c; } static int inside_pos (pos_t a) { return inside(a.r, a.c); } static uint8_t *board_pos (pos_t a) { return &board[a.r][a.c]; } static void advance_tail() { uint8_t search_for = (snake_tick - snake_len + 1) % 128 + 1; pos_t tail_up = add_pos(snake_tail, up_dir); pos_t tail_down = add_pos(snake_tail, down_dir); pos_t tail_left = add_pos(snake_tail, left_dir); pos_t tail_right = add_pos(snake_tail, right_dir); *board_pos(snake_tail) = 0; if (inside_pos(tail_up) && *board_pos(tail_up) == search_for) { snake_tail = tail_up; return; } if (inside_pos(tail_down) && *board_pos(tail_down) == search_for) { snake_tail = tail_down; return; } if (inside_pos(tail_left) && *board_pos(tail_left) == search_for) { snake_tail = tail_left; return; } if (inside_pos(tail_right) && *board_pos(tail_right) == search_for) { snake_tail = tail_right; return; } } int snake_update() { static int state = START_STATE; game_tick++; switch (state) { case START_STATE: { board[START_ROW][START_COL] = 1; if (press_once(key_state, KEY_UP)) { return 1; } if (press_once(key_state, KEY_DOWN)) { state = RUNNING_STATE; snake_respawn(); } } break; case RUNNING_STATE: { if (press_once(key_state, KEY_DOWN) && !equ_pos(snake_last_dir, up_dir)) { snake_dir = down_dir; } else if (press_once(key_state, KEY_UP) && !equ_pos(snake_last_dir, down_dir)) { snake_dir = up_dir; } else if (press_once(key_state, KEY_LEFT) && !equ_pos(snake_last_dir, right_dir)) { snake_dir = left_dir; } else if (press_once(key_state, KEY_RIGHT) && !equ_pos(snake_last_dir, left_dir)) { snake_dir = right_dir; } static int speed_div = 15; if (game_tick % speed_div == 0) { snake_last_dir = snake_dir; pos_t next_head = add_pos(snake_head, snake_dir); if (!inside_pos(next_head)) { state = LOST_STATE; } else if (*board_pos(next_head) <= 128 && *board_pos(next_head) > 0) { state = LOST_STATE; } else if (*board_pos(next_head) == BOUNDRY){ state = LOST_STATE; } else { if (*board_pos(next_head) == FOOD || snake_len < 4) { snake_len++; if (*board_pos(next_head) == FOOD) generate_food(); } else advance_tail(); snake_tick++; *board_pos(next_head) = snake_tick % 128 + 1; snake_head = next_head; } } } break; case LOST_STATE: { if (press_once(key_state, KEY_UP)) { memset(board, 0, sizeof(board)); state = START_STATE; } } break; } draw_board(board); return 0; }