Small snake game in C
Commit 538a98a3ec03
tarball1 file changed+274-56
@@ -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 25617
-#define HEIGHT 25618
+#define WIDTH 5019
+#define HEIGHT 5020
+21
+#define SPEED 100 /* in ms */22
+23
+#define MAX_LENGTH 100024
+#define STARTING_LENGTH 21825
1926
typedef enum {2027
UP, DOWN, LEFT, RIGHT2128
} direction;2229
30
+typedef enum {31
+ EMPTY, SNAKE, HEAD, FRUIT32
+} 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(¤t, 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_y179
+ ) {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
}