Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save ehaliewicz/398624323bd993f9ff3c37388ad072d3 to your computer and use it in GitHub Desktop.

Select an option

Save ehaliewicz/398624323bd993f9ff3c37388ad072d3 to your computer and use it in GitHub Desktop.
snake
#include "exotique.h"
#define CELL_SIZE 16
#define GAME_SIZE 32
#define MAX_SNAKE_LEN (GAME_SIZE*GAME_SIZE)
/* required screen dim constants for exotique */
const int kScreenWidth = (CELL_SIZE*GAME_SIZE);
const int kScreenHeight = (CELL_SIZE*GAME_SIZE);
typedef struct {
int x,y;
} seg;
seg segments[GAME_SIZE*GAME_SIZE];
int snake_len;
int snake_start = 0;
#define GREEN_IDX 0
#define RED_IDX 1
#define BROWN_IDX 2
#define UP 0
#define RIGHT 1
#define DOWN 2
#define LEFT 3
int frame = 0;
int has_apple = 0;
int apple_x = 0;
int apple_y = 0;
int cur_dir = LEFT;
int growing = 0;
/*
just gonna steal doom's random array :)
*/
const unsigned char rnd_tbl[256] = {
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 ,
74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 ,
95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 ,
52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 ,
149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 ,
145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 ,
175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 ,
25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 ,
94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 ,
136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 ,
135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 ,
80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 ,
24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 ,
145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 ,
28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 ,
71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 ,
17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 ,
197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 ,
120, 163, 236, 249
};
int rand_idx = 0;
int rand() {
return (rnd_tbl[(rand_idx++)&0xFF]);
}
void game_load(ExotiqueInterface *ei) {
/* initialize palette */
ei->palette[GREEN_IDX] = 0x00FF00FF;
ei->palette[RED_IDX] = 0xFF0000FF;
ei->palette[BROWN_IDX] = 0x6F4E37FF;
/* setup initial snake segment */
/* note, this is kind of a circular buffer (unless I copy snake elements forward/back in the segment list) */
snake_len = 1;
snake_start = 0;
segments[snake_start].x = GAME_SIZE/2;
segments[snake_start].y = GAME_SIZE/2;
frame = 0;
has_apple = 0;
rand_idx = 0;
growing = 0;
}
int valid_pos(int x, int y) {
int seg_idx;
if(x < 0 || x >= GAME_SIZE) {
return 0;
}
if(y < 0 || y >= GAME_SIZE) {
return 0;
}
for(seg_idx = 0; seg_idx < snake_len; seg_idx++) {
seg cur_seg = segments[(seg_idx + snake_start) % MAX_SNAKE_LEN];
if(cur_seg.x == x && cur_seg.y == y) {
return 0;
}
}
return 1;
}
int try_move_snake(int dx, int dy, int grow) {
/* head of the snake is at snake_start + snake len */
int head_x = segments[(snake_start+snake_len-1)%MAX_SNAKE_LEN].x;
int head_y = segments[(snake_start+snake_len-1)%MAX_SNAKE_LEN].y;
if(valid_pos(head_x + dx, head_y + dy)) {
/* move the segment at the end of the snake to the front, with a further left position */
if(grow) {
segments[(snake_start+snake_len)%MAX_SNAKE_LEN].x = head_x+dx;
segments[(snake_start+snake_len++)%MAX_SNAKE_LEN].y = head_y+dy;
} else {
snake_start++;
segments[(snake_start+snake_len-1)%MAX_SNAKE_LEN].x = head_x+dx;
segments[(snake_start+snake_len-1)%MAX_SNAKE_LEN].y = head_y+dy;
}
return 0;
} else {
/* can't move here, end game. ignore for now */
return 1;
}
}
int snake_overlaps_apple() {
int head_x = segments[(snake_start+snake_len-1)%MAX_SNAKE_LEN].x;
int head_y = segments[(snake_start+snake_len-1)%MAX_SNAKE_LEN].y;
return (head_x == apple_x && head_y == apple_y);
}
int game_step(int timer) {
return (timer & 0xF) == 0xF;
}
void game_update(ExotiqueInterface *ei) {
int failed_to_move = 0;
if(ei->input->right) {
cur_dir = RIGHT;
}
if(ei->input->left) {
cur_dir = LEFT;
}
if(ei->input->up) {
cur_dir = UP;
}
if(ei->input->down) {
cur_dir = DOWN;
}
if(!game_step(frame++)) {
/* hacky way to not step every frame :) */
return;
}
/* try to move the snake */
switch(cur_dir) {
case LEFT:
failed_to_move = try_move_snake(-1, 0, growing);
break;
case UP:
failed_to_move = try_move_snake(0, -1, growing);
break;
case DOWN:
failed_to_move = try_move_snake(0, 1, growing);
break;
case RIGHT:
failed_to_move = try_move_snake(1, 0, growing);
break;
default:
/* do nothing for now */
break;
}
if(failed_to_move) {
/* reset game */
game_load(ei);
return;
}
if(!has_apple) {
/* pick random coordinate for apple that doesn't overlap snake */
int rx = rand()&31;
int ry = rand()&31;
while(!valid_pos(rx, ry)) {
rx = rand()&31;
ry = rand()&31;
}
has_apple = 1;
apple_x = rx;
apple_y = ry;
} else if(snake_overlaps_apple()) {
has_apple = 0;
growing = 3;
} else if (growing) {
growing--;
}
}
void draw_cell(ExotiqueInterface *ei, int x, int y, u8 pal_idx) {
int dx,dy;
for(dy = y * CELL_SIZE; dy < (y+1)*CELL_SIZE; dy++) {
for(dx = x * CELL_SIZE; dx < (x+1)*CELL_SIZE; dx++) {
ei->screen[dy*kScreenWidth + dx] = pal_idx;
}
}
}
void game_draw(ExotiqueInterface *ei) {
/* draw background */
int x,y, snake_seg_idx;
for(y = 0; y < kScreenHeight; y++) {
for(x = 0; x < kScreenWidth; x++) {
ei->screen[y*kScreenWidth + x] = BROWN_IDX;
}
}
/* draw snake */
for(snake_seg_idx = 0; snake_seg_idx < snake_len; snake_seg_idx++) {
seg snake_seg = segments[(snake_start+snake_seg_idx) % MAX_SNAKE_LEN];
draw_cell(ei, snake_seg.x, snake_seg.y, GREEN_IDX);
}
/* draw apple */
if(has_apple) {
draw_cell(ei, apple_x, apple_y, RED_IDX);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment