jag

snake_c

public

Small snake game in C

Star0
Watch0

Commit 538a98a3ec03

tarball

Jaglekon <58274093+Jaglekon@users.noreply.github.com>2026-03-21 15:15 UTC

1 file changed+274-56
snek 1.0
Modified file: snake.c+274 additions−56 deletions
@@ -3,9 +3,11 @@
33 #include <stdio.h>
44 #include <stdint.h>
55 #include <stdbool.h>
6+#include <stdlib.h>
67
8+#include <time.h>
9+#include <sys/time.h>
710 #include <string.h>
8-
911 #include <termios.h>
1012
1113 #define RIGHT_CODE 'C'
@@ -13,20 +15,40 @@
1315 #define UP_CODE 'A'
1416 #define DOWN_CODE 'B'
1517
16-#define WIDTH 256
17-#define HEIGHT 256
18+#define WIDTH 50
19+#define HEIGHT 50
20+
21+#define SPEED 100 /* in ms */
22+
23+#define MAX_LENGTH 1000
24+#define STARTING_LENGTH 2
1825
1926 typedef enum {
2027 UP, DOWN, LEFT, RIGHT
2128 } direction;
2229
30+typedef enum {
31+ EMPTY, SNAKE, HEAD, FRUIT
32+} field_content;
33+
2334 typedef struct selected {
24- uint8_t x;
25- uint8_t y;
35+ int16_t x;
36+ int16_t y;
2637 } selected;
2738
39+typedef struct snake {
40+ selected position[MAX_LENGTH];
41+ uint16_t length;
42+} snake;
43+
44+
45+void update_field(snake my_snake, field_content board[HEIGHT][WIDTH], selected fruit);
46+selected new_fruit(field_content board[HEIGHT][WIDTH]);
2847
29-void draw_board(selected square_selected, bool redraw);
48+void draw_board(field_content board[HEIGHT][WIDTH], bool redraw);
49+void draw_pause();
50+
51+direction read_direction (char* string, direction shift);
3052
3153
3254 int main() {
@@ -43,11 +65,46 @@ int main() {
4365
4466 tcsetattr(STDIN_FILENO, TCSANOW, &new);
4567
68+ srand(time(NULL));
69+
70+
71+ snake my_snake = {};
72+ my_snake.length = STARTING_LENGTH;
73+
74+ {
75+ uint16_t i;
76+
77+ my_snake.position[0].x = HEIGHT >> 1;
78+ my_snake.position[0].y = WIDTH >> 1;
79+ for (i = 1; i < my_snake.length; i++) {
80+ my_snake.position[i].y = -1;
81+ my_snake.position[i].x = -1;
82+ }
83+ }
84+
85+ selected fruit = {-1, -1};
86+
87+ field_content board[HEIGHT][WIDTH] = {0};
88+
89+ update_field(my_snake, board, fruit);
90+
91+ fruit = new_fruit(board);
92+ update_field(my_snake, board, fruit);
93+
94+
95+ printf("\033[?25l");
96+ draw_board(board, false);
97+
98+
99+ direction shift = RIGHT;
46100
47- selected square_selected = {0, 0};
48101
49- draw_board(square_selected, false);
102+ struct timeval start, current;
50103
104+ gettimeofday(&start, NULL);
105+
106+
107+ bool paused = false;
51108 bool run = true;
52109
53110 while (run) {
@@ -55,83 +112,244 @@ int main() {
55112 char string[1000] = {};
56113 ssize_t n = read(STDIN_FILENO, string, sizeof(string) - 1);
57114
115+ gettimeofday(&current, NULL);
58116
59117 if (n > 0) {
60118 string[n] = '\0';
119+
120+ if (!paused)
121+ shift = read_direction(string, shift);
61122
62- if (strlen(string) >= 3) {
63- if (string[0] == '\033') {
64- if (string[1] == '[') {
65-
66- direction shift;
67-
68- switch (string[2]) {
69- case RIGHT_CODE:
70- shift = RIGHT;
71- break;
72- case LEFT_CODE:
73- shift = LEFT;
74- break;
75- case UP_CODE:
76- shift = UP;
77- break;
78- case DOWN_CODE:
79- shift = DOWN;
80- break;
81- }
82-
83- switch (shift) {
84- case UP:
85- square_selected.y = ((square_selected.y + HEIGHT - 1) % HEIGHT);
86- break;
87- case DOWN:
88- square_selected.y = ((square_selected.y + 1) % HEIGHT);
89- break;
90- case LEFT:
91- square_selected.x = ((square_selected.x + WIDTH - 1) % WIDTH);
92- break;
93- case RIGHT:
94- square_selected.x = ((square_selected.x + 1) % WIDTH);
95- break;
96- }
97-
98- draw_board(square_selected, true);
99-
100- }
101- }
102- }
103123 if (strstr(string, "q"))
104124 run = false;
125+
126+ if (strstr(string, "p")) {
127+ paused = !paused;
128+ if (paused)
129+ draw_pause();
130+ }
131+ }
132+
133+ uint64_t time_diff = (current.tv_sec - start.tv_sec) * 1000000 + (current.tv_usec - start.tv_usec);
134+
135+ if ((time_diff >= SPEED * 1000) && !paused) {
136+
137+ start = current;
138+
139+ uint16_t i;
140+ for (i = my_snake.length; i > 0; i--) {
141+ my_snake.position[i].y = my_snake.position[i - 1].y;
142+ my_snake.position[i].x = my_snake.position[i - 1].x;
143+ }
144+
145+ switch (shift) {
146+ case UP:
147+ my_snake.position[0].y = ((my_snake.position[0].y + HEIGHT - 1) % HEIGHT);
148+ break;
149+ case DOWN:
150+ my_snake.position[0].y = ((my_snake.position[0].y + 1) % HEIGHT);
151+ break;
152+ case LEFT:
153+ my_snake.position[0].x = ((my_snake.position[0].x + WIDTH - 1) % WIDTH);
154+ break;
155+ case RIGHT:
156+ my_snake.position[0].x = ((my_snake.position[0].x + 1) % WIDTH);
157+ break;
158+ }
159+
160+ uint8_t head_y = my_snake.position[0].y;
161+ uint8_t head_x = my_snake.position[0].x;
162+
163+ if (head_y == fruit.y && head_x == fruit.x) {
164+ my_snake.length++;
165+ fruit = new_fruit(board);
166+ }
167+
168+
169+ update_field(my_snake, board, fruit);
170+ draw_board(board, true);
171+
172+ for (i = 1; i < my_snake.length; i++) {
173+ int16_t x = my_snake.position[i].x;
174+ int16_t y = my_snake.position[i].y;
175+
176+ if (
177+ x == head_x &&
178+ y == head_y
179+ ) {
180+ printf("\n\nHAHA LOST!!!\n\n");
181+ goto end_of_program;
182+ }
183+ }
184+
105185 }
186+
106187 }
107188
189+end_of_program:
108190
109191 tcsetattr(STDIN_FILENO, TCSANOW, &old);
192+ printf("\033[?25h");
110193
111194 return 0;
112195 }
113196
114197
115-void draw_board (selected square_selected, bool redraw) {
198+
199+
200+
201+void update_field(snake my_snake, field_content board[HEIGHT][WIDTH], selected fruit) {
202+
203+ uint8_t i, j;
204+
205+ for (i = 0; i < HEIGHT; i++) {
206+ for (j = 0; j < WIDTH; j++) {
207+ board[i][j] = EMPTY;
208+ }
209+ }
210+
211+ for (i = 0; i < my_snake.length; i++) {
212+ int16_t x = my_snake.position[i].x;
213+ int16_t y = my_snake.position[i].y;
214+ if (x >= 0 && y >= 0)
215+ board[y][x] = (i == 0) ? HEAD : SNAKE;
216+ }
217+
218+ if (fruit.x >= 0 && fruit.y >= 0)
219+ board[fruit.y][fruit.x] = FRUIT;
220+}
221+
222+
223+selected new_fruit(field_content board[HEIGHT][WIDTH]) {
224+ bool found_space = false;
225+
226+ uint8_t x;
227+ uint8_t y;
228+
229+ while (!found_space) {
230+ x = rand() % WIDTH;
231+ y = rand() % HEIGHT;
232+
233+ if (board[y][x] == EMPTY)
234+ found_space = true;
235+ }
236+
237+ selected fruit = {y, x};
238+
239+ return fruit;
240+}
241+
242+
243+void draw_board (field_content board[HEIGHT][WIDTH], bool redraw) {
116244
117245 uint8_t i, j;
118246
119247 if (redraw) {
120- for (i = 0; i < HEIGHT; i++)
248+ for (i = 0; i < HEIGHT + 2; i++)
121249 printf("\033[A");
122250 printf("\r");
123251 }
124252
253+ printf("+");
254+ for (i = 0; i < WIDTH; i++)
255+ printf("--");
256+ printf("+\n");
257+
125258 for ( i = 0; i < HEIGHT; i++) {
259+
260+ printf("|");
261+
126262 for (j = 0; j < WIDTH; j++) {
127- char character = ' ';
128263
129- if (i == square_selected.y && j == square_selected.x) {
130- character = 'O';
264+ switch (board[i][j]) {
265+ case EMPTY:
266+ printf(" ");
267+ break;
268+ case SNAKE:
269+ printf("\033[31m x\033[0m");
270+ break;
271+ case HEAD:
272+ printf("\033[32m X\033[0m");
273+ break;
274+ case FRUIT:
275+ printf("\033[34m O\033[0m");
276+ break;
131277 }
278+ }
279+ printf("|\n");
280+ }
281+
282+ printf("+");
283+ for (i = 0; i < WIDTH; i++)
284+ printf("--");
285+ printf("+\n");
286+}
287+
288+
289+void draw_pause() {
290+
291+ const uint8_t height = 5;
292+ const uint8_t width = 14;
293+
294+ char *pause_menu [] = {
295+ "+------------+",
296+ "| |",
297+ "| PAUSED |",
298+ "| |",
299+ "+------------+"
300+ };
132301
133- printf("\033[32m%5c\033[0m", character);
302+ uint8_t i, j;
303+
304+ const uint8_t going_up = (HEIGHT + height) >> 1;
305+ const uint8_t going_right = (WIDTH * 2 - width) >> 1;
306+
307+ for (i = 0; i < going_up; i++)
308+ printf("\033[%c", UP_CODE);
309+ printf("\r");
310+
311+ for (i = 0; i < height; i++) {
312+ for (j = 0; j < going_right; j++)
313+ printf("\033[%c", RIGHT_CODE);
314+
315+ printf("\033[30m%s\033[0m\033[%c\r", pause_menu[i], DOWN_CODE);
316+ }
317+
318+ for (i = 0; i < going_up - height; i++)
319+ printf("\033[%c", DOWN_CODE);
320+ printf("\r");
321+
322+ fflush(stdout);
323+}
324+
325+
326+direction read_direction (char* string, direction shift) {
327+
328+ if (strlen(string) >= 3) {
329+ if (string[0] == '\033') {
330+ if (string[1] == '[') {
331+
332+ switch (string[2]) {
333+ case RIGHT_CODE:
334+ if (shift != LEFT)
335+ return RIGHT;
336+ break;
337+ case LEFT_CODE:
338+ if (shift != RIGHT)
339+ return LEFT;
340+ break;
341+ case UP_CODE:
342+ if (shift != DOWN)
343+ return UP;
344+ break;
345+ case DOWN_CODE:
346+ if (shift != UP)
347+ return DOWN;
348+ break;
349+ }
350+ }
134351 }
135- printf("\n");
136352 }
353+
354+ return shift;
137355 }