jag

snake_c

public

Small snake game in C

Star0
Watch0
86b7b847c2375a649731e1097b0e9907e6539a79
2
ssh://git@git.jaglekon.de:30/jag/snake_c.git
snake.cC886 lines21.2 KB
1
#define _POSIX_C_SOURCE 199309L
2
3
#include <termios.h>
4
#include <unistd.h>
5
6
#include <stdbool.h>
7
#include <stdint.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10
11
#include <sys/ioctl.h>
12
13
#include <time.h>
14
15
#include <ctype.h>
16
#include <string.h>
17
18
#define RIGHT_CODE 'C'
19
#define LEFT_CODE 'D'
20
#define UP_CODE 'A'
21
#define DOWN_CODE 'B'
22
23
#define WIDTH 20
24
#define HEIGHT 20
25
26
#define STRING_LEN 20
27
28
#define SPEED 100 /* in ms */
29
30
#define MAX_LENGTH 1000
31
#define STARTING_LENGTH 2
32
33
typedef enum { NEW_GAME, SETTINGS, EXIT, MAIN_MENU } main_menu;
34
35
typedef enum {HEIGHT_S, WIDTH_S, SPEED_S, BACK_S, SETTINGS_MENU} settings;
36
37
typedef enum {
38
  NO_DIRECTION = -1,
39
  UP = 0,
40
  LEFT = 1,
41
  DOWN = 2,
42
  RIGHT = 3,
43
  DIRECTIONS = 4
44
} direction;
45
46
typedef struct selected {
47
  int16_t x;
48
  int16_t y;
49
} selected;
50
51
typedef struct snake_part {
52
  selected coords;
53
  direction directions[2];
54
} snake_part;
55
56
typedef struct snake {
57
  snake_part position[MAX_LENGTH];
58
  uint16_t length;
59
} snake;
60
61
62
uint8_t update_snake (snake *my_snake, direction shift);
63
void update_field(snake my_snake, char board[HEIGHT][WIDTH][STRING_LEN],
64
                  selected fruit);
65
selected new_fruit(char board[HEIGHT][WIDTH][STRING_LEN]);
66
67
bool start_animation();
68
bool draw_menu(main_menu menu, struct winsize window_size);
69
bool draw_board(char board[HEIGHT][WIDTH][STRING_LEN],
70
  struct winsize window_size, bool redraw, bool paused);
71
void draw_pause(struct winsize window_size, 
72
  uint8_t field_width,uint8_t field_height);
73
74
direction read_direction(char *string, bool wasd_enabled);
75
76
int main(int argc, char *args[]) {
77
78
  /* command argument handling */
79
80
  if (argc > 1) {
81
    if (argc > 2) {
82
      printf("Too many parameters\n");
83
      goto help_info;
84
    }
85
86
    if (!strcmp(args[1], "-h") || !strcmp(args[1], "--help")) {
87
88
      printf("This is a small TUI snake game.\n\n");
89
      printf("Controls: Arrow keys/WASD to control the snake.\n");
90
      printf("          P to pause.\n");
91
      printf("          Q to quit.\n");
92
93
      return 0;
94
    }
95
96
    printf("Argument \"%s\" not recognized\n", args[1]);
97
98
  help_info:
99
    printf("Try \"-h\" or \"--help\" for more information\n");
100
    return 1;
101
  }
102
103
  /* Setting up terminal with termios */
104
105
  struct termios old, new;
106
107
  tcgetattr(STDIN_FILENO, &old);
108
109
  new = old;
110
111
  new.c_lflag &= ~(ECHO | ICANON);
112
  new.c_cc[VMIN] = 0;
113
  new.c_cc[VTIME] = 0;
114
115
  tcsetattr(STDIN_FILENO, TCSANOW, &new);
116
117
  srand(time(NULL));
118
119
  printf("\033[?25l");
120
121
  struct winsize init_size, current_size;
122
  ioctl(STDOUT_FILENO, TIOCGWINSZ, &init_size);
123
  current_size = init_size;
124
  bool too_small = false;
125
126
127
  struct timespec mili100 = {0, 1000000 * SPEED};
128
129
130
  /* Animation at the start */
131
  if (!start_animation())
132
    goto end_of_program;
133
134
  /* Menu */
135
136
  bool menu = true;
137
  bool setting = false;
138
  bool change_menu = true;
139
140
  main_menu selected_menu = NEW_GAME;
141
  settings selected_setting = HEIGHT_S;
142
143
  while (menu) {
144
145
    bool pressed_enter = false;
146
    bool changed_selected = false;
147
148
    direction arrow = NO_DIRECTION;
149
150
    char string[1000] = {};
151
    ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);
152
153
154
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &current_size);
155
156
    if (current_size.ws_col != init_size.ws_col ||
157
        current_size.ws_row != init_size.ws_row) {
158
      init_size = current_size;
159
      changed_selected = true;
160
    }
161
162
163
    if (length_string > 0) {
164
      string[length_string] = '\0';
165
166
      arrow = read_direction(string, false);
167
168
      if (string[0] == '\n')
169
        pressed_enter = true;
170
      
171
      if (toupper(string[0]) == 'Q')
172
        goto end_of_program;
173
    }
174
175
    if (!setting) {
176
      
177
      if (!too_small) {
178
        switch (arrow) {
179
          case UP:
180
            selected_menu = (selected_menu + (MAIN_MENU - 1)) % MAIN_MENU;
181
            changed_selected = true;
182
            break;
183
          case DOWN:
184
            selected_menu = (selected_menu + 1) % MAIN_MENU;
185
            changed_selected = true;
186
            break;
187
          default:
188
            break;
189
        }
190
      }
191
192
      if (changed_selected || change_menu) {
193
        too_small = draw_menu(selected_menu, init_size);
194
        change_menu = false;
195
      }
196
197
      if (pressed_enter && !too_small) {
198
        switch (selected_menu) {
199
        case NEW_GAME:
200
          menu = false;
201
          break;
202
        case SETTINGS:
203
          setting = true;
204
          change_menu = true;
205
          break;
206
        default:
207
          goto end_of_program;
208
          break;
209
        }
210
      }
211
    } else {
212
213
      char *setting_string[] = {
214
        "HEIGHT",
215
        "WIDTH",
216
        "SPEED",
217
        "BACK"
218
      };
219
220
221
      switch (arrow) {
222
        case UP:
223
          selected_setting = (selected_setting + (SETTINGS_MENU - 1)) % SETTINGS_MENU;
224
          changed_selected = true;
225
          break;
226
        case DOWN:
227
          selected_setting = (selected_setting + 1) % SETTINGS_MENU;
228
          changed_selected = true;
229
          break;
230
        default:
231
          break;
232
      }
233
234
      if (changed_selected || change_menu) {
235
              
236
        uint8_t i;
237
238
        printf("\033[2J\033[H");
239
      
240
        for (i = 0; i < SETTINGS_MENU; i++) {
241
      
242
          if (i == selected_setting)
243
            printf("\033[32m");
244
245
          printf("%s\033[0m", setting_string[i]);
246
247
          if (i < SETTINGS_MENU - 1)
248
            printf("\n\n");
249
        }
250
        fflush(stdout);
251
252
        change_menu = false;
253
      }
254
255
      
256
      if (pressed_enter) {
257
        switch (selected_setting) {
258
        case BACK_S:
259
          setting = false;
260
          change_menu = true;
261
          break;
262
        default:
263
          break;
264
        }
265
        pressed_enter = false;
266
      }
267
268
    }
269
270
    nanosleep(&mili100, NULL);
271
  }
272
273
  /* initialisation of the game */
274
275
  snake my_snake = {};
276
  my_snake.length = STARTING_LENGTH;
277
278
  direction shift = RIGHT;
279
  direction tmp_direction = shift;
280
281
  {
282
    uint16_t i;
283
284
    my_snake.position[0].coords.y = HEIGHT >> 1;
285
    my_snake.position[0].coords.x = WIDTH >> 1;
286
    my_snake.position[0].directions[0] = shift;
287
    my_snake.position[0].directions[1] = shift;
288
    for (i = 1; i < my_snake.length; i++) {
289
      my_snake.position[i].coords.y = -1;
290
      my_snake.position[i].coords.x = -1;
291
    }
292
  }
293
294
  selected fruit = {-1, -1};
295
  char board[HEIGHT][WIDTH][STRING_LEN] = {};
296
297
  update_field(my_snake, board, fruit);
298
299
  fruit = new_fruit(board);
300
  update_field(my_snake, board, fruit);
301
302
  bool paused = false;
303
304
  if ((too_small = draw_board(board, current_size, true, false)))
305
    paused = true;
306
307
308
  bool run = true;
309
310
  /* start of the actual game loop */
311
312
  while (run) {
313
314
    /* input handling  */
315
316
    
317
      char string[1000] = {};
318
      ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);
319
320
      if (length_string > 0) {
321
        string[length_string] = '\0';
322
323
        if (!too_small) {
324
          if (toupper(string[0]) == 'P' || string[0] == '\n') {
325
            paused = !paused;
326
            if (paused)
327
              draw_board(board, current_size, true, paused);
328
          }
329
330
          if (!paused)
331
            tmp_direction = read_direction(string, true);
332
        }
333
334
        if (toupper(string[0]) == 'Q')
335
          run = false;
336
      }
337
    
338
339
    /* game logic */
340
341
    /*
342
    struct timeval current;
343
    gettimeofday(&current, NULL);*/
344
345
    if (/*time_diff >= SPEED * 1000*/ true) {
346
347
      ioctl(STDOUT_FILENO, TIOCGWINSZ, &current_size);
348
349
      if (current_size.ws_col != init_size.ws_col ||
350
          current_size.ws_row != init_size.ws_row) {
351
        init_size = current_size;
352
353
        paused = true;
354
        too_small = draw_board(board, current_size, true, paused);
355
      }
356
357
      if (!paused) {
358
359
        if (tmp_direction != NO_DIRECTION &&
360
            ((shift + (DIRECTIONS >> 1)) % DIRECTIONS) != tmp_direction) {
361
          shift = tmp_direction;
362
        }
363
364
        uint8_t update = update_snake(&my_snake, shift);
365
366
        switch (update) {
367
            case 0: 
368
              printf("\nERROR\n");
369
              goto end_of_program;
370
              break;
371
            case 2:
372
              printf("\nHAHA LOST, LOSER");
373
              goto end_of_program;
374
              break;
375
            default:
376
              break;
377
        }
378
379
        update_field(my_snake, board, fruit);
380
381
        
382
        uint8_t head_y = my_snake.position[0].coords.y;
383
        uint8_t head_x = my_snake.position[0].coords.x;
384
385
        if (head_y == fruit.y && head_x == fruit.x) {
386
          my_snake.length++;
387
          fruit = new_fruit(board);
388
        }
389
390
        update_field(my_snake, board, fruit);
391
        draw_board(board, current_size, false, false);
392
      }
393
    }
394
    nanosleep(&mili100, NULL);
395
  }
396
397
end_of_program:
398
399
  tcsetattr(STDIN_FILENO, TCSANOW, &old);
400
  printf("\033[?25h\n\n");
401
402
403
  printf("\033[32m");
404
  return 0;
405
}
406
407
408
uint8_t update_snake (snake *my_snake, direction shift) {
409
  
410
  my_snake->position[0].directions[1] = my_snake->position[0].directions[0];
411
  my_snake->position[0].directions[0] = shift;
412
413
  uint16_t i;
414
  for (i = my_snake->length; i > 0; i--)
415
    my_snake->position[i] = my_snake->position[i - 1];
416
417
  switch (shift) {
418
  case UP:
419
    my_snake->position[0].coords.y =
420
        ((my_snake->position[0].coords.y + HEIGHT - 1) % HEIGHT);
421
    break;
422
  case DOWN:
423
    my_snake->position[0].coords.y = ((my_snake->position[0].coords.y + 1) % HEIGHT);
424
    break;
425
  case LEFT:
426
    my_snake->position[0].coords.x =((my_snake->position[0].coords.x + WIDTH - 1) % WIDTH);
427
    break;
428
  case RIGHT:
429
    my_snake->position[0].coords.x = ((my_snake->position[0].coords.x + 1) % WIDTH);
430
    break;
431
  default:
432
    return 0;
433
    break;
434
  }
435
436
  uint8_t head_y = my_snake->position[0].coords.y;
437
  uint8_t head_x = my_snake->position[0].coords.x;
438
439
  for (i = 1; i < my_snake->length; i++) {
440
    int16_t x = my_snake->position[i].coords.x;
441
    int16_t y = my_snake->position[i].coords.y;
442
443
    if (x == head_x && y == head_y)
444
      return 2;
445
  }
446
447
448
  return 1;
449
}
450
451
void update_field(snake my_snake, char board[HEIGHT][WIDTH][STRING_LEN],
452
                  selected fruit) {
453
454
  uint8_t i, j;
455
456
  for (i = 0; i < HEIGHT; i++) {
457
    for (j = 0; j < WIDTH; j++) {
458
      strcpy(board[i][j], "  ");
459
    }
460
  }
461
462
  for (i = 0; i < my_snake.length; i++) {
463
    int16_t x = my_snake.position[i].coords.x;
464
    int16_t y = my_snake.position[i].coords.y;
465
    if (x >= 0 && y >= 0) {
466
      if (!i) {
467
        if (my_snake.position[i].directions[0] == RIGHT) {
468
          strcpy(board[y][x], "\033[33m═\033[31mX\033[0m");
469
        } else {
470
          strcpy(board[y][x], "\033[31m X\033[0m");
471
        }
472
      } else {
473
474
        char *snake_bit[DIRECTIONS][DIRECTIONS] = {
475
          [UP][UP] = " ║",
476
          [DOWN][DOWN] = " ║",
477
          
478
          [RIGHT][RIGHT] = "══",
479
          [LEFT][LEFT] = "══",
480
          
481
          [DOWN][RIGHT] = "═╗",
482
          [LEFT][UP] = "═╗",
483
          
484
          [UP][RIGHT] = "═╝",
485
          [LEFT][DOWN] = "═╝",
486
          
487
          [DOWN][LEFT] = " ╔",
488
          [RIGHT][UP] = " ╔",
489
          
490
          [UP][LEFT] = " ╚",
491
          [RIGHT][DOWN] = " ╚"
492
        };
493
494
        direction first = my_snake.position[i].directions[0];
495
        direction second = my_snake.position[i].directions[1];
496
497
        snprintf(board[y][x], sizeof(board[y][x]),"\033[33m%s\033[0m",snake_bit[first][second]);
498
      }
499
    }
500
  }
501
502
  if (fruit.x >= 0 && fruit.y >= 0)
503
    strcpy(board[fruit.y][fruit.x], "\033[32m O\033[0m");
504
}
505
506
selected new_fruit(char board[HEIGHT][WIDTH][STRING_LEN]) {
507
  bool found_space = false;
508
509
  uint8_t x;
510
  uint8_t y;
511
512
  while (!found_space) {
513
    x = rand() % WIDTH;
514
    y = rand() % HEIGHT;
515
516
    if (!strcmp(board[y][x], "  "))
517
      found_space = true;
518
  }
519
520
  selected fruit = {x, y};
521
522
  return fruit;
523
}
524
525
bool start_animation() {  
526
527
  struct winsize current_size;
528
  ioctl(STDOUT_FILENO, TIOCGWINSZ, &current_size);
529
530
  struct timespec mili10 = {0, 100000 * SPEED};
531
532
  char *snake[3][7] = {
533
    {
534
      "           ________  ",
535
      "         _/ _      \\_",
536
      "________/  (_)       ",
537
      "\\       \\            ",
538
      "/_______/   _        ",
539
      "        \\_ (_)      _",
540
      "          \\________/ "
541
    },
542
    {
543
      "        ",
544
      "________",
545
      "\\      /",
546
      " \\    / ",
547
      "  \\  /  ",
548
      "___\\/___",
549
      "        ",
550
    },
551
    {
552
      "         ",
553
      "__        ",
554
      "  \\_____ ",
555
      "        \\",
556
      "   _____/",
557
      "__/      ",
558
      "         "
559
    }
560
  };
561
562
  uint8_t width_snake[3] = {};
563
564
  {
565
    uint8_t i;
566
567
    for (i = 0; i < 3; i++)
568
      width_snake[i] = (uint8_t) strlen(snake[i][0]);
569
  }
570
571
  uint8_t middle;
572
573
  uint8_t height = 7;
574
  uint8_t width = width_snake[0] + width_snake[1] + width_snake[2];
575
576
  for (middle = 1; width < current_size.ws_col; middle++)
577
    width += width_snake[1];
578
579
  int32_t end = current_size.ws_col + width;
580
581
582
583
  while (end >= 0) {
584
585
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &current_size);
586
587
    int32_t start = end - width; 
588
589
    int32_t i, j;
590
 
591
    char string[1000] = {};
592
    ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);
593
594
     if (length_string > 0) {
595
    
596
      string[length_string] = '\0';
597
598
599
    if (toupper(string[0]) == 'Q')
600
      return false;
601
602
    if (string[0] == '\n')
603
      break;
604
    }
605
606
    printf("\033[2J\033[H");
607
608
    for (j = 0; j < ((height > current_size.ws_row) ? current_size.ws_row : height) ; j++) {
609
610
    for (i = 0; i < current_size.ws_col; i++) {
611
      int32_t index = i - start;
612
613
      if (index >= 0 && index < width) {
614
        if (index < width_snake[0]) {
615
          printf("%c", snake[0][j][index]);
616
        } else if (index < width_snake[0] + width_snake[1] * middle) {
617
          printf("%c", snake[1][j][(index - width_snake[0]) % width_snake[1]]);
618
        } else {
619
          printf("%c", snake[2][j][index - (width_snake[0] + width_snake[1] * middle)]);
620
        }
621
      } else {
622
        printf(" ");
623
      }
624
    }      
625
    
626
      printf("\n");
627
628
    }
629
    fflush(stdout);
630
    
631
    end--;
632
633
    nanosleep(&mili10, NULL);
634
  }
635
  return true;
636
}
637
638
bool draw_menu(main_menu menu, struct winsize window_size) {
639
640
  char *menu_string[] = {"NEW GAME", "SETTINGS", "EXIT"};
641
642
  const uint8_t width_small = 8;
643
  const uint8_t height_small = 5;
644
645
  char *menu_string_big[][6] = {
646
      {"███╗   ██╗███████╗██╗    ██╗     ██████╗  █████╗ ███╗   ███╗███████╗",
647
       "████╗  ██║██╔════╝██║    ██║    ██╔════╝ ██╔══██╗████╗ ████║██╔════╝",
648
       "██╔██╗ ██║█████╗  ██║ █╗ ██║    ██║  ███╗███████║██╔████╔██║█████╗  ",
649
       "██║╚██╗██║██╔══╝  ██║███╗██║    ██║   ██║██╔══██║██║╚██╔╝██║██╔══╝  ",
650
       "██║ ╚████║███████╗╚███╔███╔╝    ╚██████╔╝██║  ██║██║ ╚═╝ ██║███████╗",
651
       "╚═╝  ╚═══╝╚══════╝ ╚══╝╚══╝      ╚═════╝ ╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝"},
652
      {"███████╗███████╗████████╗████████╗██╗███╗   ██╗ ██████╗ ███████╗",
653
       "██╔════╝██╔════╝╚══██╔══╝╚══██╔══╝██║████╗  ██║██╔════╝ ██╔════╝",
654
       "███████╗█████╗     ██║      ██║   ██║██╔██╗ ██║██║  ███╗███████╗",
655
       "╚════██║██╔══╝     ██║      ██║   ██║██║╚██╗██║██║   ██║╚════██║",
656
       "███████║███████╗   ██║      ██║   ██║██║ ╚████║╚██████╔╝███████║",
657
       "╚══════╝╚══════╝   ╚═╝      ╚═╝   ╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝"},
658
      {"███████╗██╗  ██╗██╗████████╗", "██╔════╝╚██╗██╔╝██║╚══██╔══╝",
659
       "█████╗   ╚███╔╝ ██║   ██║   ", "██╔══╝   ██╔██╗ ██║   ██║   ",
660
       "███████╗██╔╝ ██╗██║   ██║   ", "╚══════╝╚═╝  ╚═╝╚═╝   ╚═╝   "}};
661
662
  const uint8_t height_line = 6;
663
  const uint8_t height_space = 2;
664
665
  const uint8_t width_text[] = {68, 64, 28};
666
667
  const uint8_t width_big = width_text[0] /*strlen(menu_string_big[0][0])*/;
668
  const uint8_t height_big =
669
      height_line * MAIN_MENU + height_space * (MAIN_MENU - 1);
670
671
  printf("\033[2J\033[H");
672
673
  if (window_size.ws_row < height_small || window_size.ws_col < width_small) {
674
    printf("Too small\n");
675
    return true;
676
  }
677
678
  uint8_t i, j, k;
679
680
  if (window_size.ws_row >= height_big && window_size.ws_col >= width_big) {
681
682
    uint8_t vertical_buffer = (window_size.ws_row - height_big) >> 1;
683
684
    for (i = 0; i < vertical_buffer; i++)
685
      printf("\n");
686
687
    for (i = 0; i < MAIN_MENU; i++) {
688
689
      if (i == menu)
690
        printf("\033[32m");
691
692
      uint8_t horizontal_buffer = (window_size.ws_col - width_text[i]) >> 1;
693
694
      for (j = 0; j < height_line; j++) {
695
696
        for (k = 0; k < horizontal_buffer; k++)
697
          printf(" ");
698
699
        printf("%s", menu_string_big[i][j]);
700
701
        if (j != height_line - 1)
702
          printf("\n");
703
      }
704
705
      printf("\033[0m");
706
707
      if (i != MAIN_MENU - 1)
708
        printf("\n\n");
709
    }
710
711
  } else {
712
713
    uint8_t vertical_buffer = (window_size.ws_row - height_small) >> 1;
714
715
    for (i = 0; i < vertical_buffer; i++)
716
      printf("\n");
717
718
    for (i = 0; i < MAIN_MENU; i++) {
719
      if (i == menu)
720
        printf("\033[32m");
721
722
      uint8_t horizontal_buffer =
723
          (window_size.ws_col - strlen(menu_string[i])) >> 1;
724
725
      for (j = 0; j < horizontal_buffer; j++)
726
        printf(" ");
727
728
      printf("%s\033[0m", menu_string[i]);
729
730
      if (i != MAIN_MENU - 1)
731
        printf("\n\n");
732
    }
733
  }
734
735
  fflush(stdout);
736
  return false;
737
}
738
739
bool draw_board(char board[HEIGHT][WIDTH][STRING_LEN],
740
                struct winsize window_size, bool redraw, bool paused) {
741
742
  uint8_t i, j;
743
744
  uint8_t actual_height = HEIGHT + 2;
745
  uint8_t actual_width = WIDTH * 2 + 2;
746
747
  if (actual_width > window_size.ws_col || actual_height > window_size.ws_row) {
748
749
    printf("\033[2J\033[HToo small\n");
750
    printf("Min width: %i & Min height: %i\n", actual_height, actual_width);
751
752
    return true;
753
  }
754
755
  uint8_t vertical_buffer = (window_size.ws_row - actual_height) >> 1;
756
  uint8_t horizontal_buffer = (window_size.ws_col - actual_width) >> 1;
757
758
  if (redraw) {
759
    printf("\033[2J\033[H");
760
    for (i = 0; i < vertical_buffer; i++)
761
      printf("\n");
762
  } else {
763
    for (i = 0; i < actual_height - 1; i++)
764
      printf("\033[%c", UP_CODE);
765
    printf("\r");
766
  }
767
768
  for (i = 0; i < horizontal_buffer; i++)
769
    printf(" ");
770
  printf("+");
771
  for (i = 0; i < WIDTH; i++)
772
    printf("--");
773
  printf("+\n");
774
775
  for (i = 0; i < HEIGHT; i++) {
776
777
    for (j = 0; j < horizontal_buffer; j++)
778
      printf(" ");
779
780
    printf("|");
781
782
    for (j = 0; j < WIDTH; j++)
783
      printf("%s", board[i][j]);
784
785
    printf("|\n");
786
  }
787
788
  for (i = 0; i < horizontal_buffer; i++)
789
    printf(" ");
790
  printf("+");
791
  for (i = 0; i < WIDTH; i++)
792
    printf("--");
793
  printf("+");
794
795
  if (paused)
796
    draw_pause(window_size, actual_width, actual_height);
797
798
  fflush(stdout);
799
800
  return false;
801
}
802
803
void draw_pause(struct winsize window_size, uint8_t field_width,
804
                uint8_t field_height) {
805
806
  const uint8_t height = 5;
807
  const uint8_t width = 14;
808
809
  const char *pause_menu[] = {
810
    "+------------+", 
811
    "|            |",
812
    "|   PAUSED   |",
813
    "|            |",
814
    "+------------+"
815
  };
816
817
  const uint8_t going_up = (field_height + height) >> 1;
818
  const uint8_t going_right = (field_width - width) >> 1;
819
820
  const uint8_t horizontal_buffer = (window_size.ws_col - field_width) >> 1;
821
822
  uint8_t i, j;
823
824
  for (i = 0; i < going_up; i++)
825
    printf("\033[%c", UP_CODE);
826
  printf("\r");
827
828
  for (i = 0; i < height; i++) {
829
    for (j = 0; j < horizontal_buffer; j++)
830
      printf("\033[%c", RIGHT_CODE);
831
    for (j = 0; j < going_right; j++)
832
      printf("\033[%c", RIGHT_CODE);
833
834
    printf("\033[37m%s\033[0m\033[%c\r", pause_menu[i], DOWN_CODE);
835
  }
836
837
  for (i = 0; i < going_up - height; i++)
838
    printf("\033[%c", DOWN_CODE);
839
  printf("\r");
840
841
  fflush(stdout);
842
}
843
844
direction read_direction(char *string, bool wasd_enabled) {
845
846
  if (strlen(string) >= 3) {
847
    if (string[0] == '\033') {
848
      if (string[1] == '[') {
849
850
        switch (string[2]) {
851
        case RIGHT_CODE:
852
          return RIGHT;
853
          break;
854
        case LEFT_CODE:
855
          return LEFT;
856
          break;
857
        case UP_CODE:
858
          return UP;
859
          break;
860
        case DOWN_CODE:
861
          return DOWN;
862
          break;
863
        }
864
      }
865
    }
866
  }
867
868
  if (wasd_enabled) {
869
    switch (toupper(string[0])) {
870
    case 'A':
871
      return LEFT;
872
      break;
873
    case 'D':
874
      return RIGHT;
875
      break;
876
    case 'W':
877
      return UP;
878
      break;
879
    case 'S':
880
      return DOWN;
881
      break;
882
    }
883
  }
884
885
  return NO_DIRECTION;
886
}