jag

snake_c

public

Small snake game in C

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