// SPDX-License-Identifier: MIT // Written by: Sonny X. #include #include /* Constants */ #define GRID_SZ_DEFAULT 24 #define SCREEN_SZ_DEFAULT (GRID_SZ_DEFAULT * GRID_SZ_DEFAULT) #define COLOR_BG (Color){199.f, 217.f, 240.f, 255.f} #define COLOR_FG (Color){61.f, 70.f, 82.f, 255.f} #define SNAKE_MAX 1 #define FOOD_MAX 1 #define SNAKE_SZ_DEFAULT 4 #define SNAKE_GAME_SPEED 12 typedef struct { int x; int y; } food_t; food_t *new_food(void); void food_move(food_t *, int, int); void food_update(food_t *); void food_draw(food_t *); food_t *food[FOOD_MAX]; typedef struct { int x[SCREEN_SZ_DEFAULT]; int y[SCREEN_SZ_DEFAULT]; int dir_x, dir_y; int score; int dead; // n = 0 == dead! } snake_t; snake_t *new_snake(void); void snake_move(snake_t *, int, int); void snake_update(snake_t *); void snake_draw(snake_t *); snake_t *snake[SNAKE_MAX]; food_t *new_food(void) { food_t *f = malloc(sizeof(snake_t)); if (!f) return (void *)0; f->x = 15; f->y = 10; return f; } void food_move(food_t *f, int x, int y) { f->x = x; f->y = y; } void food_update(food_t *f) { int rx, ry; rx = rand() % GRID_SZ_DEFAULT; ry = rand() % GRID_SZ_DEFAULT; food_move(f, rx, ry); } void food_draw(food_t *f) { DrawRectangle(f->x * GRID_SZ_DEFAULT, f->y * GRID_SZ_DEFAULT, GRID_SZ_DEFAULT, GRID_SZ_DEFAULT, COLOR_FG); } snake_t *new_snake(void) { snake_t *s = malloc(sizeof(snake_t)); if (!s) return (void *)0; s->x[0] = 5; s->y[0] = 10; s->dir_x = 1; s->dir_y = 0; s->score = 4; s->dead = 0; return s; } void snake_move(snake_t *s, int dir_x, int dir_y) { if (dir_x == 1) { if (s->dir_x == -1) { return; } } if (dir_y == 1) { if (s->dir_y == -1) { return; } } if (dir_x == -1) { if (s->dir_x == 1) { return; } } if (dir_y == -1) { if (s->dir_y == 1) { return; } } s->dir_x = dir_x; s->dir_y = dir_y; } void snake_update(snake_t *s) { int k; if (s->dead) return; k = GetKeyPressed(); switch (k) { case KEY_D: snake_move(s, 1, 0); break; case KEY_S: snake_move(s, 0, 1); break; case KEY_A: snake_move(s, -1, 0); break; case KEY_W: snake_move(s, 0, -1); break; } for (int i = s->score - 1; i > 0; i--) { s->x[i] = s->x[i - 1]; s->y[i] = s->y[i - 1]; } s->x[0] += s->dir_x; s->y[0] += s->dir_y; for (int i = 1; i < s->score; i++) { if (s->x[0] == s->x[i] && s->y[0] == s->y[i]) { s->dead = 1; } } if (s->x[0] > (GRID_SZ_DEFAULT-1) || s->y[0] > (GRID_SZ_DEFAULT-1)) s->dead = 1; if (s->x[0] < 0 || s->y[0] < 0) s->dead = 1; } void snake_draw(snake_t *s) { if (!s) return; for (int i = 0; i < s->score; i++) { DrawRectangle(s->x[i] * GRID_SZ_DEFAULT, s->y[i] * GRID_SZ_DEFAULT, GRID_SZ_DEFAULT, GRID_SZ_DEFAULT, COLOR_FG); } } void __update(void); void __draw(void); void __init(void); void __exit(void); void __loop(void); void __update(void) { for (int i = 0; i < SNAKE_MAX; i++) { snake_update(snake[i]); } if (snake[0]->x[0] == food[0]->x && snake[0]->y[0] == food[0]->y) { snake[0]->score++; food_update(food[0]); } } void __draw(void) { BeginDrawing(); ClearBackground(COLOR_BG); for (int i = 0; i < SNAKE_MAX; i++) { snake_draw(snake[i]); } for (int i = 0; i < FOOD_MAX; i++) { food_draw(food[i]); } DrawText(TextFormat("%d", (snake[0]->score - SNAKE_SZ_DEFAULT)), GRID_SZ_DEFAULT, GRID_SZ_DEFAULT, GRID_SZ_DEFAULT, COLOR_FG); if (snake[0]->dead) { DrawText("game over", GRID_SZ_DEFAULT, 2 * GRID_SZ_DEFAULT, GRID_SZ_DEFAULT, COLOR_FG); } EndDrawing(); } void __init(void) { ClearWindowState(FLAG_WINDOW_RESIZABLE); InitWindow(SCREEN_SZ_DEFAULT, SCREEN_SZ_DEFAULT, "Snake"); SetTargetFPS(SNAKE_GAME_SPEED); snake[0] = new_snake(); food[0] = new_food(); } void __exit(void) { for (int i = 0; i < FOOD_MAX; i++) { free(food[i]); } for (int i = 0; i < SNAKE_MAX; i++) { free(snake[i]); } CloseWindow(); } void __loop(void) { __init(); do { __update(); __draw(); } while (!WindowShouldClose()); __exit(); } int main(void) { __loop(); return 0; }