jag

snake_c

public

Small snake game in C

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