jag

snake_c

public

Small snake game in C

Star0
Watch0
b8f066c16f28051332f4618911cd56b0df80dd4d
2
ssh://git@git.jaglekon.de:30/jag/snake_c.git
drawing.cC628 lines17.3 KB
1
#include "snake.h"
2
3
bool start_animation() {  
4
5
  struct winsize current_size;
6
  ioctl(STDOUT_FILENO, TIOCGWINSZ, &current_size);
7
8
  struct timespec mili10 = {0, 1000000 * 10};
9
10
  char *snake[3][7] = {
11
    {
12
      "           ________  ",
13
      "         _/ _      \\_",
14
      "________/  (_)       ",
15
      "\\       \\            ",
16
      "/_______/   _        ",
17
      "        \\_ (_)      _",
18
      "          \\________/ "
19
    },
20
    {
21
      "        ",
22
      "________",
23
      "\\      /",
24
      " \\    / ",
25
      "  \\  /  ",
26
      "___\\/___",
27
      "        ",
28
    },
29
    {
30
      "         ",
31
      "__        ",
32
      "  \\_____ ",
33
      "        \\",
34
      "   _____/",
35
      "__/      ",
36
      "         "
37
    }
38
  };
39
40
  uint8_t width_snake[3] = {};
41
42
  {
43
    uint8_t i;
44
45
    for (i = 0; i < 3; i++)
46
      width_snake[i] = (uint8_t) strlen(snake[i][0]);
47
  }
48
49
  uint8_t middle;
50
51
  uint8_t height = 7;
52
  uint8_t width = width_snake[0] + width_snake[1] + width_snake[2];
53
54
  for (middle = 1; width < current_size.ws_col; middle++)
55
    width += width_snake[1];
56
57
  int32_t end = current_size.ws_col + width;
58
59
60
61
  while (end >= 0) {
62
63
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &current_size);
64
65
    int32_t start = end - width; 
66
67
    int32_t i, j;
68
 
69
    char string[1000] = {};
70
    ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);
71
72
     if (length_string > 0) {
73
    
74
      string[length_string] = '\0';
75
76
      direction pressed_key = read_direction(string, true);
77
78
      if (pressed_key == Q_KEY || pressed_key == ESCAPE)
79
        return false;
80
81
      if (pressed_key == ENTER)
82
        break;
83
    }
84
85
    printf("\033[2J\033[H");
86
87
    for (j = 0; j < ((height > current_size.ws_row) ? current_size.ws_row : height) ; j++) {
88
89
    for (i = 0; i < current_size.ws_col; i++) {
90
      int32_t index = i - start;
91
92
      if (index >= 0 && index < width) {
93
        if (index < width_snake[0]) {
94
          printf("%c", snake[0][j][index]);
95
        } else if (index < width_snake[0] + width_snake[1] * middle) {
96
          printf("%c", snake[1][j][(index - width_snake[0]) % width_snake[1]]);
97
        } else {
98
          printf("%c", snake[2][j][index - (width_snake[0] + width_snake[1] * middle)]);
99
        }
100
      } else {
101
        printf(" ");
102
      }
103
    }      
104
    
105
      printf("\n");
106
107
    }
108
    fflush(stdout);
109
    
110
    end--;
111
112
    nanosleep(&mili10, NULL);
113
  }
114
  return true;
115
}
116
117
bool draw_menu(main_menu menu, struct winsize window_size) {
118
119
  char *menu_string[] = {"NEW GAME", "SETTINGS", "HIGHSCORE", "EXIT"};
120
121
  const uint8_t width_small = 9;
122
  const uint8_t height_small = 5;
123
124
  char *menu_string_big[][6] = {
125
      {"███╗   ██╗███████╗██╗    ██╗     ██████╗  █████╗ ███╗   ███╗███████╗",
126
       "████╗  ██║██╔════╝██║    ██║    ██╔════╝ ██╔══██╗████╗ ████║██╔════╝",
127
       "██╔██╗ ██║█████╗  ██║ █╗ ██║    ██║  ███╗███████║██╔████╔██║█████╗  ",
128
       "██║╚██╗██║██╔══╝  ██║███╗██║    ██║   ██║██╔══██║██║╚██╔╝██║██╔══╝  ",
129
       "██║ ╚████║███████╗╚███╔███╔╝    ╚██████╔╝██║  ██║██║ ╚═╝ ██║███████╗",
130
       "╚═╝  ╚═══╝╚══════╝ ╚══╝╚══╝      ╚═════╝ ╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝"},
131
      {"███████╗███████╗████████╗████████╗██╗███╗   ██╗ ██████╗ ███████╗",
132
       "██╔════╝██╔════╝╚══██╔══╝╚══██╔══╝██║████╗  ██║██╔════╝ ██╔════╝",
133
       "███████╗█████╗     ██║      ██║   ██║██╔██╗ ██║██║  ███╗███████╗",
134
       "╚════██║██╔══╝     ██║      ██║   ██║██║╚██╗██║██║   ██║╚════██║",
135
       "███████║███████╗   ██║      ██║   ██║██║ ╚████║╚██████╔╝███████║",
136
       "╚══════╝╚══════╝   ╚═╝      ╚═╝   ╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝"},
137
      {"██╗  ██╗██╗ ██████╗ ██╗  ██╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗",
138
       "██║  ██║██║██╔════╝ ██║  ██║██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝",
139
       "███████║██║██║  ███╗███████║███████╗██║     ██║   ██║██████╔╝█████╗  ",
140
       "██╔══██║██║██║   ██║██╔══██║╚════██║██║     ██║   ██║██╔══██╗██╔══╝  ",
141
       "██║  ██║██║╚██████╔╝██║  ██║███████║╚██████╗╚██████╔╝██║  ██║███████╗",
142
       "╚═╝  ╚═╝╚═╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝"},
143
      {"███████╗██╗  ██╗██╗████████╗", 
144
       "██╔════╝╚██╗██╔╝██║╚══██╔══╝",
145
       "█████╗   ╚███╔╝ ██║   ██║   ", 
146
       "██╔══╝   ██╔██╗ ██║   ██║   ",
147
       "███████╗██╔╝ ██╗██║   ██║   ", 
148
       "╚══════╝╚═╝  ╚═╝╚═╝   ╚═╝   "}
149
  };
150
151
  const uint8_t height_line = 6;
152
  const uint8_t height_space = 2;
153
154
  const uint8_t width_text[] = {68, 64, 69, 28};
155
156
  const uint8_t width_big = width_text[2] /*strlen(menu_string_big[0][0])*/;
157
  const uint8_t height_big =
158
      height_line * MAIN_MENU + height_space * (MAIN_MENU - 1);
159
160
  printf("\033[2J\033[H");
161
162
  if (window_size.ws_row < height_small || window_size.ws_col < width_small) {
163
    printf("Too small\n");
164
    return true;
165
  }
166
167
  uint8_t i, j, k;
168
169
  if (window_size.ws_row >= height_big && window_size.ws_col >= width_big) {
170
171
    uint8_t vertical_buffer = (window_size.ws_row - height_big) >> 1;
172
173
    for (i = 0; i < vertical_buffer; i++)
174
      printf("\n");
175
176
    for (i = 0; i < MAIN_MENU; i++) {
177
178
      if (i == menu)
179
        printf("\033[32m");
180
181
      uint8_t horizontal_buffer = (window_size.ws_col - width_text[i]) >> 1;
182
183
      for (j = 0; j < height_line; j++) {
184
185
        for (k = 0; k < horizontal_buffer; k++)
186
          printf(" ");
187
188
        printf("%s", menu_string_big[i][j]);
189
190
        if (j != height_line - 1)
191
          printf("\n");
192
      }
193
194
      printf("\033[0m");
195
196
      if (i != MAIN_MENU - 1)
197
        printf("\n\n");
198
    }
199
200
  } else {
201
202
    uint8_t vertical_buffer = (window_size.ws_row - height_small) >> 1;
203
204
    for (i = 0; i < vertical_buffer; i++)
205
      printf("\n");
206
207
    for (i = 0; i < MAIN_MENU; i++) {
208
      if (i == menu)
209
        printf("\033[32m");
210
211
      uint8_t horizontal_buffer =
212
          (window_size.ws_col - strlen(menu_string[i])) >> 1;
213
214
      for (j = 0; j < horizontal_buffer; j++)
215
        printf(" ");
216
217
      printf("%s\033[0m", menu_string[i]);
218
219
      if (i != MAIN_MENU - 1)
220
        printf("\n\n");
221
    }
222
  }
223
224
  fflush(stdout);
225
  return false;
226
}
227
228
229
void draw_settings(settings selected_setting, speed game_speed, selected game_size, struct winsize window_size) {
230
231
  char *title[] = {
232
    " ___ ___ _____ _____ ___ _  _  ___ ___ ",
233
    "/ __| __|_   _|_   _|_ _| \\| |/ __/ __|",
234
    "\\__ \\ _|  | |   | |  | || .` | (_ \\__ \\",
235
    "|___/___| |_|   |_| |___|_|\\_|\\___|___/",
236
                                        
237
  };
238
239
  char *setting_string[] = {
240
    "HEIGHT",
241
    "WIDTH",
242
    "SPEED",
243
    "BACK"
244
  };
245
246
  char *speed_char[] = {
247
    "VERY FAST",
248
    "FAST",
249
    "AVERAGE",
250
    "SLOW",
251
    "VERY SLOW"
252
  };
253
254
255
  uint8_t title_height = 4;
256
  uint8_t title_width = strlen(title[0]);
257
258
  
259
  uint8_t setting_width;
260
  if (title_width % 2 == 0) {
261
    setting_width = (title_width + 2) >> 1;
262
  } else {
263
    setting_width = (title_width + 1) >> 1;
264
  }
265
266
  uint8_t settings_height = SETTINGS_MENU * 2 + 1;
267
268
  uint16_t full_height = title_height + settings_height + 2;
269
  uint16_t full_width = setting_width * 2 + 3;
270
271
  uint8_t i, j;
272
273
  printf("\033[2J\033[H");
274
275
  if (window_size.ws_col < full_width || window_size.ws_row < full_height) {
276
    printf("Too small!\n");
277
    printf("Min: x: %d y: %d", full_width, full_height);
278
    fflush(stdout);
279
    return;
280
  }
281
282
  uint8_t vertical_buffer = (window_size.ws_row - full_height) >> 1;
283
  uint8_t horizontal_buffer = (window_size.ws_col - full_width) >> 1;
284
285
  for(i = 0; i < vertical_buffer; i++)
286
    printf("\n");
287
288
289
  for(i = 0; i < title_height + 2; i++) {
290
    for (j = 0; j < horizontal_buffer; j++)
291
      printf(" ");
292
    if (!i) {
293
      printf("┏");
294
      for(j = 0; j < full_width - 2; j++)
295
        printf("━");
296
      printf("┓\n");
297
    } else {
298
      printf("┃ ");
299
      if (i == title_height + 1) {
300
        for(j = 0; j < title_width; j++)
301
          printf(" ");
302
      } else {
303
        printf("\033[31;1m%s\033[0m", title[i - 1]);
304
      }
305
      if (title_width % 2 == 0)
306
        printf(" ");
307
      printf(" ┃\n");
308
    }
309
  }
310
   
311
  for (i = 0; i < settings_height; i++) {
312
313
    for (j = 0; j < horizontal_buffer; j++)
314
      printf(" ");
315
316
    if (i % 2 == 0) {
317
318
      if (i == 0) {
319
        printf("┣");
320
        for(j = 0; j < setting_width; j++)
321
          printf("━");
322
        printf("┯");
323
        for(j = 0; j < setting_width; j++)
324
          printf("━");
325
        printf("┫\n");
326
327
      } else if (i == settings_height - 1) {
328
        printf("┗");
329
        for(j = 0; j < setting_width * 2 + 1; j++)
330
          printf("━");
331
        printf("┛");
332
333
      } else {
334
      
335
        printf("┠");
336
        for(j = 0; j < setting_width; j++)
337
          printf("─");
338
        printf("%s", i == settings_height - 3 ? "┴" : "┼");
339
        for(j = 0; j < setting_width; j++)
340
          printf("─");
341
        printf("┨\n");
342
      }
343
344
    } else {
345
346
      settings current_setting = (i - 1) >> 1;
347
348
      printf("┃");
349
350
      if (current_setting == selected_setting)
351
        printf("\033[32m");
352
353
      print_buffer(current_setting != BACK_S ? setting_width : 2 * setting_width + 1, 
354
        setting_string[current_setting]);
355
      
356
      printf("\033[0m");
357
358
      if (current_setting != BACK_S) {
359
360
        printf("│");
361
362
        if (current_setting == selected_setting)
363
          printf("\033[32m");
364
365
        char *pointer;
366
367
        char number[5];
368
369
        switch (current_setting) {
370
          case SPEED_S:
371
            pointer = speed_char[game_speed];
372
            break;
373
          case WIDTH_S:
374
            sprintf(number, "%d", game_size.x);
375
            pointer = number;
376
            break;
377
          case HEIGHT_S:
378
            sprintf(number, "%d", game_size.y);
379
            pointer = number;
380
            break;
381
          default:
382
            break;
383
        }
384
385
        print_buffer(setting_width, pointer);
386
      }
387
388
      printf("\033[0m┃\n");
389
    }
390
  }
391
392
  fflush(stdout);
393
}
394
395
bool draw_board(
396
  selected game_size,
397
  board_state **board,
398
  struct winsize window_size, 
399
  bool redraw, uint8_t paused,
400
  uint16_t score
401
) {
402
403
  uint8_t i, j;
404
405
  uint8_t actual_height = game_size.y + 2 + 2;
406
  uint8_t actual_width = game_size.x * 2 + 1 + 2;
407
408
  if (actual_width > window_size.ws_col || actual_height > window_size.ws_row) {
409
410
    printf("\033[2J\033[HToo small\n");
411
    printf("Min width: %i & Min height: %i\n", actual_height, actual_width);
412
413
    return true;
414
  }
415
416
  uint8_t vertical_buffer = (window_size.ws_row - actual_height) >> 1;
417
  uint8_t horizontal_buffer = (window_size.ws_col - actual_width) >> 1;
418
419
  if (redraw) {
420
    printf("\033[2J\033[H");
421
    for (i = 0; i < vertical_buffer; i++)
422
      printf("\n");
423
  } else {
424
    for (i = 0; i < actual_height - 1; i++)
425
      printf("\033[%c", UP_CODE);
426
    printf("\r");
427
  }
428
  
429
  for (i = 0; i < ((actual_width - 9) >> 1) + horizontal_buffer; i++)
430
    printf(" ");
431
  printf("╭───────╮\n");
432
    for (i = 0; i < ((actual_width - 9) >> 1) + horizontal_buffer; i++)
433
    printf(" ");
434
  printf("│ \033[32m%05d\033[0m │\n", score);
435
436
  for (i = 0; i < horizontal_buffer; i++)
437
    printf(" ");
438
  printf("╭");
439
  for (i = 0; i < game_size.x; i++)
440
    printf("──");
441
  printf("─╮");
442
  printf("\r");
443
  for (i = 0; i < ((actual_width - 9) >> 1) + horizontal_buffer; i++)
444
    printf("\033[%c", RIGHT_CODE);
445
  printf("┴───────┴\n");
446
447
448
449
  for (i = 0; i < game_size.y; i++) {
450
451
    for (j = 0; j < horizontal_buffer; j++)
452
      printf(" ");
453
454
    printf("│");
455
456
    for (j = 0; j < game_size.x; j++)
457
      printf("%s", give_state(board[i][j]));
458
459
    printf("%s", give_state(board[i][0]));
460
461
    printf("\033[%c│\n", LEFT_CODE);
462
  }
463
464
  for (i = 0; i < horizontal_buffer; i++)
465
    printf(" ");
466
  printf("╰");
467
  for (i = 0; i < game_size.x; i++)
468
    printf("──");
469
  printf("─╯");
470
471
  if (paused)
472
    draw_pause(window_size, actual_width, actual_height, paused);
473
474
  fflush(stdout);
475
476
  return false;
477
}
478
479
void draw_pause(struct winsize window_size, uint8_t field_width,
480
  uint8_t field_height, uint8_t game_over) {
481
482
  const uint8_t height = 5;
483
  const uint8_t width = 14;
484
485
  const char *pause_menu[] = {
486
    "+------------+", 
487
    "|            |",
488
    "|   PAUSED   |",
489
    "|            |",
490
    "+------------+"
491
  };
492
493
  const char *game_over_menu = "| GAME OVER  |";
494
495
  const uint8_t going_up = (field_height + height) >> 1;
496
  const uint8_t going_right = (field_width - width) >> 1;
497
498
  const uint8_t horizontal_buffer = (window_size.ws_col - field_width) >> 1;
499
500
  uint8_t i, j;
501
502
  for (i = 0; i < going_up; i++)
503
    printf("\033[%c", UP_CODE);
504
  printf("\r");
505
506
  for (i = 0; i < height; i++) {
507
    for (j = 0; j < horizontal_buffer; j++)
508
      printf("\033[%c", RIGHT_CODE);
509
    for (j = 0; j < going_right; j++)
510
      printf("\033[%c", RIGHT_CODE);
511
512
    if (i == 2 && game_over == 2) {
513
      printf("\033[37m%s\033[0m\033[%c\r", game_over_menu, DOWN_CODE);
514
    } else {
515
      printf("\033[37m%s\033[0m\033[%c\r", pause_menu[i], DOWN_CODE);
516
    }
517
  }
518
519
  for (i = 0; i < going_up - height; i++)
520
    printf("\033[%c", DOWN_CODE);
521
  printf("\r");
522
523
  fflush(stdout);
524
}
525
526
void draw_highscore (int16_t new_score, score leader_board[SCORE_NUMBER]) {
527
  
528
  uint8_t i;
529
530
  printf("\033[2J\033[H");
531
532
  for (i = 0; i < SCORE_NUMBER; i++) {
533
    printf("%-10s %05d\n", leader_board[i].name, leader_board[i].points);
534
  }
535
536
  if (new_score != -1) {
537
    for (i = SCORE_NUMBER - new_score; i > 0; i--)
538
      printf("\033[%c", UP_CODE);
539
    printf("\r_");
540
    fflush(stdout);
541
542
    uint8_t number_characters = 0;
543
544
    while(true) {
545
      char string[STRING_LEN] = {};
546
      ssize_t length_string = read(STDIN_FILENO, string, sizeof(string) - 1);
547
548
      if (length_string > 0) {
549
        
550
        direction pressed_key = read_direction(string, false);
551
552
        if (pressed_key == ENTER) {
553
          leader_board[new_score].name[number_characters] = '\0';
554
          break;        
555
        }
556
         
557
        if (pressed_key == DEL && number_characters > 0) {
558
          printf("\033[%c \033[%c\033[%c_", LEFT_CODE, LEFT_CODE, LEFT_CODE);
559
          leader_board[new_score].name[--number_characters] = '\0';
560
        }
561
562
        if (isalnum(string[0]) && number_characters < SCORE_LEN - 2) {
563
          printf("\033[%c%c_", LEFT_CODE, string[0]);
564
          leader_board[new_score].name[number_characters++] = string[0];
565
        }
566
      }
567
      fflush(stdout);
568
      struct timespec mili100 = {0, 1000000 * 100};
569
      nanosleep(&mili100, NULL);
570
    }
571
  }
572
}
573
574
575
char *give_state(board_state square) {
576
577
  switch (square) {
578
    case FRUIT:
579
      return "\033[32m O\033[0m";
580
      break;
581
    case HEAD_1:
582
      return "\033[33m═\033[31mX\033[0m";
583
      break;
584
    case HEAD_2:
585
      return "\033[31m\33[CX\033[0m";
586
      break;    
587
    case VERTICAL:
588
      return "\033[33m ║\033[0m";
589
      break;
590
    case HORIZONTAL:
591
      return "\033[33m══\033[0m";
592
      break;
593
    case TOP_RIGHT:
594
      return "\033[33m ╚\033[0m";
595
      break;
596
    case TOP_LEFT:
597
      return "\033[33m═╝\033[0m";
598
      break;
599
    case BOTTOM_RIGHT:
600
      return "\033[33m ╔\033[0m";
601
      break;
602
    case BOTTOM_LEFT:
603
      return "\033[33m═╗\033[0m";
604
      break;
605
    default:
606
      return " ·";
607
      break;
608
  }
609
}
610
611
bool print_buffer(uint16_t width, char *string) {
612
  uint16_t len = strlen(string);
613
  uint16_t i;
614
615
  if (width < len)
616
    return false;
617
618
  uint16_t prebuffer = (width - len) >> 1; 
619
  uint16_t postbuffer = width - len - prebuffer; 
620
621
  for (i = 0; i < prebuffer; i++)
622
    printf(" ");
623
  printf("%s", string);
624
  for (i = 0; i < postbuffer; i++)
625
    printf(" ");
626
627
  return true;
628
}