jag

snake_c

public

Small snake game in C

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