Small snake game in C
Commit c28baaaf800e
tarball3 files changed+327-266
@@ -402,9 +402,10 @@ bool draw_board(
402402
403403
uint8_t i, j;404404
405
- uint8_t actual_height = game_size.y + 2 + 2;405
+ uint8_t actual_height = game_size.y + 2 + 2 + 1;406406
uint8_t actual_width = game_size.x * 2 + 1 + 2;407407
408
+408409
if (actual_width > window_size.ws_col || actual_height > window_size.ws_row) {409410
410411
printf("\033[2J\033[HToo small\n");@@ -466,11 +467,21 @@ bool draw_board(
466467
printf("╰");467468
for (i = 0; i < game_size.x; i++)468469
printf("──");469
- printf("─╯");470
+ printf("─╯\n");471
+472
+ if (paused) {473
+ if (paused == 2) {474
+ char *game_over = "Press ENTER to continue";475
+ 476
+ for (i = 0; i < (window_size.ws_col - strlen(game_over)) >> 1; i++)477
+ printf(" ");478
+ printf("%s", game_over);479
+ }470480
471
- if (paused)472481
draw_pause(window_size, actual_width, actual_height, paused);473482
483
+ }484
+474485
fflush(stdout);475486
476487
return false;@@ -483,14 +494,14 @@ void draw_pause(struct winsize window_size, uint8_t field_width,
483494
const uint8_t width = 14;484495
485496
const char *pause_menu[] = {486
- "+------------+", 487
- "| |",488
- "| PAUSED |",489
- "| |",490
- "+------------+"497
+ "┌────────────┐", 498
+ "│ │",499
+ "│ PAUSED │",500
+ "│ │",501
+ "└────────────┘"491502
};492503
493
- const char *game_over_menu = "| GAME OVER |";504
+ const char *game_over_menu = "│ GAME OVER │";494505
495506
const uint8_t going_up = (field_height + height) >> 1;496507
const uint8_t going_right = (field_width - width) >> 1;@@ -523,20 +534,40 @@ void draw_pause(struct winsize window_size, uint8_t field_width,
523534
fflush(stdout);524535
}525536
526
-void draw_highscore (int16_t new_score, score leader_board[SCORE_NUMBER]) {537
+void draw_highscore (int16_t new_score, score leader_board[SCORE_NUMBER], struct winsize window_size) {527538
528539
uint8_t i;529540
530541
printf("\033[2J\033[H");531542
543
+ printf("┏━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");544
+545
+ printf("┃ RANK NAME SCORE ┃\n");546
+ printf("┣━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n");547
+ 548
+532549
for (i = 0; i < SCORE_NUMBER; i++) {533
- printf("%-10s %05d\n", leader_board[i].name, leader_board[i].points);550
+551
+ char *ordinals[] = {552
+ "st", "nd", "rd", "th"553
+ };554
+555
+ printf("┃ %2d%-4s %-9s %06d ┃\n",i + 1, (i >= 3) ? ordinals[3] : ordinals[i] ,leader_board[i].name, leader_board[i].points);556
+ printf("┃ ┃\n");557
+ 534558
}559
+ 560
+ printf("\033[%c┗━━━━━━━━━━━━━━━━━━━━━━━━━━┛", UP_CODE);561
+ 562
+ fflush(stdout);535563
536564
if (new_score != -1) {537
- for (i = SCORE_NUMBER - new_score; i > 0; i--)565
+ for (i = (SCORE_NUMBER - new_score) * 2 - 1; i > 0; i--)538566
printf("\033[%c", UP_CODE);539
- printf("\r_");567
+ printf("\r");568
+ for (i = 0; i < 8 + 1; i++)569
+ printf("\033[%c", RIGHT_CODE);570
+ printf("_");540571
fflush(stdout);541572
542573
uint8_t number_characters = 0;@@ -35,7 +35,6 @@ int main(int argc, char *args[]) {
3535
selected game_size = {WIDTH, HEIGHT};3636
3737
score leader_board[SCORE_NUMBER] = {};38
- uint16_t score = 0;3938
4039
/* Handling Files to store settings & highscores */4140
@@ -158,10 +157,11 @@ int main(int argc, char *args[]) {
158157
current_size = init_size;159158
bool too_small = false;160159
160
+ bool gameloop = true;161161
162162
/* Animation at the start */163163
if (!start_animation())164
- goto end_of_program;164
+ gameloop = false;165165
166166
167167
/* Menu */@@ -173,362 +173,392 @@ int main(int argc, char *args[]) {
173173
main_menu selected_menu = NEW_GAME;174174
settings selected_setting = HEIGHT_S;175175
176
- struct timespec mili100 = {0, 1000000 * 100};176
+ uint16_t score = 0;177
+ 178
+ snake my_snake;179
+ my_snake.position = NULL;177180
178
-menu_start:181
+ board_state **board = NULL;182
+ board_state *values = NULL;179183
180
- while (menu) {181184
182
- direction pressed_key = DIRECTIONS;185
+ struct timespec mili100 = {0, 1000000 * 100};183186
184
- char string[STRING_LEN] = {};185
- ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);187
+ while(gameloop) {186188
189
+ bool play_game = false;187190
188
- ioctl(STDOUT_FILENO, TIOCGWINSZ, ¤t_size);191
+ while (menu) {189192
190
- if (current_size.ws_col != init_size.ws_col ||191
- current_size.ws_row != init_size.ws_row) {192
- init_size = current_size;193
- change_menu = true;194
- }193
+ direction pressed_key = DIRECTIONS;195194
195
+ char string[STRING_LEN] = {};196
+ ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);196197
197
- if (length_string > 0) {198
- string[length_string] = '\0';199198
200
- pressed_key = read_direction(string, false);201
- }199
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, ¤t_size);202200
203
- if (pressed_key == Q_KEY || pressed_key == ESCAPE)204
- goto end_of_program;201
+ if (current_size.ws_col != init_size.ws_col ||202
+ current_size.ws_row != init_size.ws_row) {203
+ init_size = current_size;204
+ change_menu = true;205
+ }205206
206207
207
- if (setting == MAIN_MENU) {208
- 209
- if (!too_small) {210
- switch (pressed_key) {211
- case UP:212
- selected_menu = (selected_menu + (MAIN_MENU - 1)) % MAIN_MENU;213
- change_menu = true;214
- break;215
- case DOWN:216
- selected_menu = (selected_menu + 1) % MAIN_MENU;217
- change_menu = true;218
- break;219
- default:220
- break;221
- }222
- }208
+ if (length_string > 0) {209
+ string[length_string] = '\0';223210
224
- if (change_menu) {225
- too_small = draw_menu(selected_menu, init_size);226
- change_menu = false;211
+ pressed_key = read_direction(string, false);227212
}228213
229
- if (pressed_key == ENTER && !too_small) {230
- switch (selected_menu) {231
- case NEW_GAME:232
- menu = false;233
- break;234
- case SETTINGS:235
- setting = SETTINGS;236
- break;237
- case HIGHSCORE:238
- setting = HIGHSCORE;239
- break;240
- default:241
- goto end_of_program; 214
+ if (pressed_key == Q_KEY || pressed_key == ESCAPE) {215
+ if (setting != MAIN_MENU) {216
+ setting = MAIN_MENU;217
+ change_menu = true;218
+ } else {219
+ gameloop = false;242220
break;243221
}244
- change_menu = true;245222
}246223
247
- } else if (setting == SETTINGS) {248224
249
- /* Settings Menu */250
-251
- if (change_menu) {225
+ if (setting == MAIN_MENU) {252226
253
- draw_settings(selected_setting, game_speed, game_size, init_size);254
-255
- change_menu = false;256
- }257
-258
-259
- if (pressed_key < DIRECTIONS) {227
+ if (!too_small) {228
+ switch (pressed_key) {229
+ case UP:230
+ selected_menu = (selected_menu + (MAIN_MENU - 1)) % MAIN_MENU;231
+ change_menu = true;232
+ break;233
+ case DOWN:234
+ selected_menu = (selected_menu + 1) % MAIN_MENU;235
+ change_menu = true;236
+ break;237
+ default:238
+ break;239
+ }240
+ }260241
261
- int8_t setting_change = 0;242
+ if (change_menu) {243
+ too_small = draw_menu(selected_menu, init_size);244
+ change_menu = false;245
+ }262246
263
- switch (pressed_key) {264
- case UP:265
- selected_setting = (selected_setting + (SETTINGS_MENU - 1)) % SETTINGS_MENU;266
- break;267
- case DOWN:268
- selected_setting = (selected_setting + 1) % SETTINGS_MENU;247
+ if (pressed_key == ENTER && !too_small) {248
+ switch (selected_menu) {249
+ case NEW_GAME:250
+ menu = false;251
+ play_game = true;269252
break;270
- case LEFT:271
- setting_change = 1;253
+ case SETTINGS:254
+ setting = SETTINGS;272255
break;273
- case RIGHT:274
- setting_change = -1;256
+ case HIGHSCORE:257
+ setting = HIGHSCORE;275258
break;276259
default:260
+ menu = false;261
+ gameloop = false; 277262
break;263
+ }264
+ change_menu = true;278265
}279
- 280
- if (setting_change) {281
- switch (selected_setting) {282
- case SPEED_S:283
- if (284
- game_speed + setting_change <= SPEED_L - 1 &&285
- ((int8_t) game_speed) + setting_change >= 0 286
- ) {287
- game_speed += setting_change;288
- }266
+267
+ } else if (setting == SETTINGS) {268
+269
+ /* Settings Menu */270
+271
+ if (change_menu) {272
+ 273
+ draw_settings(selected_setting, game_speed, game_size, init_size);274
+275
+ change_menu = false;276
+ }277
+278
+279
+ if (pressed_key < DIRECTIONS) {280
+281
+ int8_t setting_change = 0;282
+283
+ switch (pressed_key) {284
+ case UP:285
+ selected_setting = (selected_setting + (SETTINGS_MENU - 1)) % SETTINGS_MENU;289286
break;290
- case WIDTH_S:291
- if (292
- game_size.x - setting_change >= MIN_SIZE &&293
- game_size.x - setting_change <= MAX_SIZE294
- ) {295
- game_size.x -= setting_change;296
- }287
+ case DOWN:288
+ selected_setting = (selected_setting + 1) % SETTINGS_MENU;297289
break;298
- case HEIGHT_S:299
- if (300
- game_size.y - setting_change >= MIN_SIZE &&301
- game_size.y - setting_change <= MAX_SIZE302
- ) {303
- game_size.y -= setting_change;304
- }290
+ case LEFT:291
+ setting_change = 1;292
+ break;293
+ case RIGHT:294
+ setting_change = -1;305295
break;306296
default:307297
break;308298
}309
- }310
-311
- change_menu = true;299
+ 300
+ if (setting_change) {301
+ switch (selected_setting) {302
+ case SPEED_S:303
+ if (304
+ game_speed + setting_change <= SPEED_L - 1 &&305
+ ((int8_t) game_speed) + setting_change >= 0 306
+ ) {307
+ game_speed += setting_change;308
+ }309
+ break;310
+ case WIDTH_S:311
+ if (312
+ game_size.x - setting_change >= MIN_SIZE &&313
+ game_size.x - setting_change <= MAX_SIZE314
+ ) {315
+ game_size.x -= setting_change;316
+ }317
+ break;318
+ case HEIGHT_S:319
+ if (320
+ game_size.y - setting_change >= MIN_SIZE &&321
+ game_size.y - setting_change <= MAX_SIZE322
+ ) {323
+ game_size.y -= setting_change;324
+ }325
+ break;326
+ default:327
+ break;328
+ }329
+ }312330
313
- }331
+ change_menu = true;314332
315
- if (pressed_key == ENTER) {316
- switch (selected_setting) {317
- case BACK_S:318
- setting = MAIN_MENU;319
- break;320
- default:321
- break;322333
}323
- change_menu = true;324
- }325
- } else if (setting == HIGHSCORE) {326
- 327
- if(change_menu) {328
- uint8_t i;329334
330
- for (i = 0; i < SCORE_NUMBER; i++) {331
- if (score > leader_board[i].points)332
- break;335
+ if (pressed_key == ENTER) {336
+ switch (selected_setting) {337
+ case BACK_S:338
+ setting = MAIN_MENU;339
+ break;340
+ default:341
+ break;342
+ }343
+ change_menu = true;333344
}345
+ } else if (setting == HIGHSCORE) {346
+ 347
+ if(change_menu) {348
+ uint8_t i;349
+350
+ for (i = 0; i < SCORE_NUMBER; i++) {351
+ if (score > leader_board[i].points)352
+ break;353
+ }354
+355
+ if (i < SCORE_NUMBER) {334356
335
- if (i < SCORE_NUMBER) {357
+ uint8_t new_score = i;336358
337
- uint8_t new_score = i;359
+ for (i = SCORE_NUMBER - 1; i > new_score; i--) {360
+ leader_board[i] = leader_board[i -1]; 361
+ }362
+363
+ leader_board[new_score].points = score;364
+ leader_board[new_score].name[0] = '\0';365
+366
+ draw_highscore (new_score, leader_board, init_size);367
+ 368
+ score = 0;369
+ change_menu = true;338370
339
- for (i = SCORE_NUMBER - 1; i > new_score; i--) {340
- leader_board[i] = leader_board[i -1]; 371
+ } else {372
+ if (change_menu)373
+ draw_highscore (-1, leader_board, init_size); 341374
}375
+ }342376
343
- leader_board[new_score].points = score;344
- leader_board[new_score].name[0] = '\0';377
+ if(pressed_key == ENTER) {378
+ setting = MAIN_MENU;379
+ change_menu = true;380
+ }381
+ } else if(setting == NEW_GAME) {345382
346
- draw_highscore (new_score, leader_board);347
- 348
- score = 0;383
+ if (change_menu)384
+ draw_board(game_size, board, init_size, true, 2, score);385
+386
+ if(pressed_key == ENTER) {387
+ setting = HIGHSCORE;349388
change_menu = true;350389
351
- } else {352
- draw_highscore (-1, leader_board); 390
+ free(my_snake.position);391
+ free(board);392
+ free(values);393
+ my_snake.position = NULL;394
+ board = NULL;395
+ values = NULL;353396
}354397
}355398
356
- if(pressed_key == ENTER) {357
- setting = MAIN_MENU;358
- change_menu = true;359
- }360
- } else if(setting == NEW_GAME) {361
-362
- if(pressed_key == ENTER) {363
- setting = HIGHSCORE;364
- change_menu = true;365
- }399
+ nanosleep(&mili100, NULL);366400
}367401
368
- nanosleep(&mili100, NULL);369
- }402
+ menu = true;370403
371
- menu = true;404
+ /* initialisation of the game */405
+ 406
+ if(play_game) {372407
373
- /* initialisation of the game */408
+ bool run = true;374409
375
- snake my_snake;376
- my_snake.length = STARTING_LENGTH;410
+ my_snake.length = STARTING_LENGTH;377411
378
- my_snake.position = malloc((my_snake.length + 1) * sizeof(snake_part));412
+ my_snake.position = malloc((my_snake.length + 1) * sizeof(snake_part));379413
380
- direction shift = RIGHT;381
- direction tmp_direction = shift;414
+ direction shift = RIGHT;415
+ direction tmp_direction = shift;382416
383
- {384
- uint16_t i;385
-386
- my_snake.position[0].coords.y = game_size.y >> 1;387
- my_snake.position[0].coords.x = game_size.x >> 1;388
- my_snake.position[0].directions[0] = shift;389
- my_snake.position[0].directions[1] = shift;390
- for (i = 1; i <= my_snake.length; i++) {391
- my_snake.position[i].coords.y = -1;392
- my_snake.position[i].coords.x = -1;393
- }394
- }417
+ {418
+ uint16_t i;395419
396
- board_state **board = malloc(game_size.y * sizeof(board_state*));397
- board_state *values = calloc(game_size.y * game_size.x, sizeof(board_state));420
+ my_snake.position[0].coords.y = game_size.y >> 1;421
+ my_snake.position[0].coords.x = game_size.x >> 1;422
+ my_snake.position[0].directions[0] = shift;423
+ my_snake.position[0].directions[1] = shift;424
+ for (i = 1; i <= my_snake.length; i++) {425
+ my_snake.position[i].coords.y = -1;426
+ my_snake.position[i].coords.x = -1;427
+ }428
+ }398429
399
- if(board == NULL || values == NULL)400
- goto end_of_program;430
+ board = malloc(game_size.y * sizeof(board_state*));431
+ values = calloc(game_size.y * game_size.x, sizeof(board_state));401432
402
- {403
- uint8_t i;433
+ if(board == NULL || values == NULL)434
+ run = false; 404435
405
- for (i = 0; i < game_size.y; i++)406
- board[i] = values + i * game_size.x;407
- }436
+ {437
+ uint8_t i;408438
409
- update_field(my_snake, game_size, board, true);439
+ for (i = 0; i < game_size.y; i++)440
+ board[i] = values + i * game_size.x;441
+ }410442
411
- uint8_t paused = 0;443
+ update_field(my_snake, game_size, board, true);412444
445
+ uint8_t paused = 0;413446
414
- if ((too_small = draw_board(game_size, board, current_size, true, 0, score)))415
- paused = 1;416447
417
- bool run = true;448
+ if ((too_small = draw_board(game_size, board, current_size, true, 0, score)))449
+ paused = 1;418450
419
- struct timespec milispeed = {0, 1000000 * (SPEED + game_speed * 25)};420451
421
- /* start of the actual game loop */452
+ struct timespec milispeed = {0, 1000000 * (SPEED + game_speed * 25)};422453
423
- while (run) {454
+ /* start of the actual game loop */424455
425
- /* input handling */456
+ while (run) {426457
458
+ /* input handling */427459
428
- direction pressed_key;429460
430
- char string[STRING_LEN] = {};431
- ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);461
+ direction pressed_key;432462
433
- if (length_string > 0) {434
- string[length_string] = '\0';463
+ char string[STRING_LEN] = {};464
+ ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);435465
436
- pressed_key = read_direction(string, true);466
+ if (length_string > 0) {467
+ string[length_string] = '\0';437468
438
- if (!too_small) {439
- if (pressed_key == P_KEY || pressed_key == ENTER) {440
- paused = (paused == 1) ? 0 : 1;441
- if (paused)442
- draw_board(game_size, board, current_size, true, paused, score);443
- } 469
+ pressed_key = read_direction(string, true);444470
445
- if (!paused && pressed_key < DIRECTIONS)446
- tmp_direction = pressed_key;447
- }471
+ if (!too_small) {472
+ if (pressed_key == P_KEY || pressed_key == ENTER) {473
+ paused = (paused == 1) ? 0 : 1;474
+ if (paused)475
+ draw_board(game_size, board, current_size, true, paused, score);476
+ } 448477
449
- if (pressed_key == Q_KEY || pressed_key == ESCAPE)450
- run = false;451
- }452
- 478
+ if (!paused && pressed_key < DIRECTIONS)479
+ tmp_direction = pressed_key;480
+ }453481
454
- /* game logic */482
+ if (pressed_key == Q_KEY || pressed_key == ESCAPE)483
+ run = false;484
+ }455485
456
- /*457
- struct timeval current;458
- gettimeofday(¤t, NULL);*/486
+ /* game logic */459487
460
- if (/*time_diff >= SPEED * 1000*/ true) {488
+ /*489
+ struct timeval current;490
+ gettimeofday(¤t, NULL);*/461491
462
- ioctl(STDOUT_FILENO, TIOCGWINSZ, ¤t_size);492
+ if (/*time_diff >= SPEED * 1000*/ true) {463493
464
- if (current_size.ws_col != init_size.ws_col ||465
- current_size.ws_row != init_size.ws_row) {466
- init_size = current_size;494
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, ¤t_size);467495
468
- paused = 1;469
- too_small = draw_board(game_size, board, current_size, true, paused, score);470
- }496
+ if (current_size.ws_col != init_size.ws_col ||497
+ current_size.ws_row != init_size.ws_row) {498
+ init_size = current_size;471499
472
- if (!paused) {500
+ paused = 1;501
+ too_small = draw_board(game_size, board, current_size, true, paused, score);502
+ }473503
474
- if (tmp_direction < DIRECTIONS &&475
- ((shift + (DIRECTIONS >> 1)) % DIRECTIONS) != tmp_direction) {476
- shift = tmp_direction;477
- }504
+ if (!paused) {478505
479
- uint8_t update = update_snake(game_size ,&my_snake, shift);506
+ if (tmp_direction < DIRECTIONS &&507
+ ((shift + (DIRECTIONS >> 1)) % DIRECTIONS) != tmp_direction) {508
+ shift = tmp_direction;509
+ }480510
481
- uint8_t head_y = my_snake.position[0].coords.y;482
- uint8_t head_x = my_snake.position[0].coords.x;511
+ uint8_t update = update_snake(game_size ,&my_snake, shift);512
+513
+ uint8_t head_y = my_snake.position[0].coords.y;514
+ uint8_t head_x = my_snake.position[0].coords.x;515
+516
+ if (board[head_y][head_x] == FRUIT) {517
+ my_snake.length++;518
+ score += 1 + 519
+ (((MAX_SIZE >> 1) / (game_size.y) + 520
+ (MAX_SIZE >> 1) / (game_size.x) + 521
+ (my_snake.length - STARTING_LENGTH)) / (game_speed + 1));522
+ snake_part *tmp = realloc(my_snake.position, (my_snake.length + 1) * sizeof(snake_part));523
+ if (tmp == NULL) {524
+ gameloop = false;525
+ break;526
+ }527
+ my_snake.position = tmp;483528
484
- if (board[head_y][head_x] == FRUIT) {485
- my_snake.length++;486
- score += 1 + 487
- (((MAX_SIZE >> 1) / (game_size.y) + 488
- (MAX_SIZE >> 1) / (game_size.x) + 489
- (my_snake.length - STARTING_LENGTH)) / (game_speed + 1));490
- snake_part *tmp = realloc(my_snake.position, (my_snake.length + 1) * sizeof(snake_part));491
- if (tmp == NULL)492
- goto end_free;493
- my_snake.position = tmp;529
+ my_snake.position[my_snake.length].coords.y = -1;530
+ my_snake.position[my_snake.length].coords.x = -1;531
+ }494532
495
- my_snake.position[my_snake.length].coords.y = -1;496
- my_snake.position[my_snake.length].coords.x = -1;497
- }533
+ update_field(my_snake, game_size, board, false);498534
499
- update_field(my_snake, game_size, board, false);535
+ draw_board(game_size, board, current_size, false, 0, score);500536
501
- draw_board(game_size, board, current_size, false, 0, score);537
+ switch (update) {538
+ case 0: 539
+ gameloop = false;540
+ break;541
+ case 2:542
+ setting = NEW_GAME;543
+ run = false;544
+ break;545
+ default:546
+ break;547
+ }502548
503
- switch (update) {504
- case 0: 505
- goto end_free;506
- break;507
- case 2:508
- setting = NEW_GAME;509
- draw_board(game_size, board, current_size, false, 2, score);510
- goto end_free;511
- break;512
- default:513
- break;549
+ }514550
}515
-551
+ nanosleep(&milispeed, NULL);516552
}517553
}518
- nanosleep(&milispeed, NULL);519554
}520555
521
-end_free:556
+522557
523558
free(my_snake.position);524559
free(board);525560
free(values);526561
527
- if (setting == NEW_GAME)528
- goto menu_start;529
-530
-end_of_program:531
-532562
tcsetattr(STDIN_FILENO, TCSANOW, &old);533563
printf("\033[?25h\n\n");534564
@@ -99,7 +99,7 @@ bool draw_board(selected game_size, board_state **board,
9999
void draw_pause(struct winsize window_size, 100100
uint8_t field_width,uint8_t field_height, uint8_t game_over);101101
void draw_highscore (int16_t new_score, 102
- score leader_board[SCORE_NUMBER]);102
+ score leader_board[SCORE_NUMBER], struct winsize window_size);103103
104104
bool print_buffer(uint16_t width, char *string);