diff options
Diffstat (limited to 'src/game.c')
-rw-r--r-- | src/game.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/src/game.c b/src/game.c new file mode 100644 index 0000000..1a836d0 --- /dev/null +++ b/src/game.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2019-2020, yzrh <yzrh@noema.org> + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <stdbool.h> + +#include "extern.h" +#include "screen.h" + +static bool +_collision(int *fruit, Snake_Pos **snake) +{ + Snake_Pos *ptr = *snake; + while (ptr != NULL) { + if (collision_block(fruit, (int[]) {ptr->x, ptr->y})) + return 1; + ptr = ptr->next; + } + return 0; +} + +static bool +_bound(Snake_Pos **snake) +{ + if ((*snake)->x + SCREEN_UNIT / 2 > SCREEN_HEIGHT) + return 1; + else if ((*snake)->y + SCREEN_UNIT / 2 > SCREEN_HEIGHT) + return 1; + else if ((*snake)->x - SCREEN_UNIT / 2 < -SCREEN_UNIT) + return 1; + else if ((*snake)->y - SCREEN_UNIT / 2 < -SCREEN_UNIT) + return 1; + return 0; +} + +static int +_overlap(Snake_Pos **snake0, Snake_Pos **snake1) +{ + Snake_Pos *ptr0 = *snake0; + Snake_Pos *ptr1; + + int is_overlap[2] = {0, 0}; + + while (ptr0->next->next != NULL) { + if (collision_block( + (int[]) {(*snake0)->x, (*snake0)->y}, + (int[]) {ptr0->next->x, ptr0->next->y})) { + is_overlap[0] = 1; + break; + } + ptr0 = ptr0->next; + } + + if (snake1 != NULL) { + ptr0 = *snake0; + ptr1 = *snake1; + while (ptr0->next->next != NULL && + ptr1->next->next != NULL && + (is_overlap[0] != 1 || is_overlap[1] != 2)) { + if (collision_block( + (int[]) {(*snake0)->x, (*snake0)->y}, + (int[]) {ptr1->next->x, ptr1->next->y})) + is_overlap[0] = 1; + if (collision_block( + (int[]) {(*snake1)->x, (*snake1)->y}, + (int[]) {ptr0->next->x, ptr0->next->y})) + is_overlap[1] = 2; + if (collision_block( + (int[]) {(*snake1)->x, (*snake1)->y}, + (int[]) {ptr1->next->x, ptr1->next->y})) + is_overlap[1] = 2; + ptr0 = ptr0->next; + ptr1 = ptr1->next; + } + } + + return is_overlap[0] + is_overlap[1]; +} + +void +game_snake_init(Snake_Pos **snake, int dx) +{ + Snake_Pos *ptr; + while ((ptr = *snake) != NULL) { + *snake = (*snake)->next; + free(ptr); + } + + *snake = malloc(sizeof(Snake_Pos)); + (*snake)->next = malloc(sizeof(Snake_Pos)); + + (*snake)->x = (*snake)->next->x = SCREEN_HEIGHT / 2 + dx; + (*snake)->y = SCREEN_HEIGHT / 2; + (*snake)->next->y = SCREEN_HEIGHT / 2 + SCREEN_UNIT; + (*snake)->next->next = NULL; +} + +void +game_snake_move(Snake_Pos **snake0, Snake_Pos **snake1, + Snake_Input *head, bool law, int *legal) +{ + bool bound_snake0; + bool bound_snake1; + int overlap; + + Snake_Pos *ptr0; + Snake_Pos *ptr1; + + ptr0 = malloc(sizeof(Snake_Pos)); + ptr0->x = (*snake0)->x; + ptr0->y = (*snake0)->y; + ptr0->next = *snake0; + + switch (head[0]) { + case SNAKE_LEFT: + ptr0->x -= SCREEN_UNIT; + break; + case SNAKE_UP: + ptr0->y -= SCREEN_UNIT; + break; + case SNAKE_DOWN: + ptr0->y += SCREEN_UNIT; + break; + case SNAKE_RIGHT: + ptr0->x += SCREEN_UNIT; + break; + default: + break; + } + + bound_snake0 = _bound(&ptr0); + + if (snake1 == NULL) { + overlap = _overlap(&ptr0, NULL); + + if (bound_snake0 || overlap == 1) + *legal = 1; + else + *legal = 0; + } else { + ptr1 = malloc(sizeof(Snake_Pos)); + ptr1->x = (*snake1)->x; + ptr1->y = (*snake1)->y; + ptr1->next = *snake1; + + switch (head[1]) { + case SNAKE_LEFT: + ptr1->x -= SCREEN_UNIT; + break; + case SNAKE_UP: + ptr1->y -= SCREEN_UNIT; + break; + case SNAKE_DOWN: + ptr1->y += SCREEN_UNIT; + break; + case SNAKE_RIGHT: + ptr1->x += SCREEN_UNIT; + break; + default: + break; + } + + bound_snake1 = _bound(&ptr1); + overlap = _overlap(&ptr0, &ptr1); + + if ((bound_snake0 && bound_snake1) || overlap == 3) + *legal = 3; + else if (bound_snake1 || overlap == 2) + *legal = 2; + else if (bound_snake0 || overlap == 1) + *legal = 1; + else + *legal = 0; + } + + if (*legal == 0 || !law) { + *snake0 = ptr0; + + while (ptr0->next->next != NULL) + ptr0 = ptr0->next; + free(ptr0->next); + ptr0->next = NULL; + + if (snake1 != NULL) { + *snake1 = ptr1; + + while (ptr1->next->next != NULL) + ptr1 = ptr1->next; + free(ptr1->next); + ptr1->next = NULL; + } + } else { + free(ptr0); + + if (snake1 != NULL) + free(ptr1); + } +} + +void +game_snake_grow(Snake_Pos **snake) +{ + Snake_Pos *ptr = *snake; + while (ptr->next != NULL) + ptr = ptr->next; + ptr->next = malloc(sizeof(Snake_Pos)); + ptr->next->x = ptr->x; + ptr->next->y = ptr->y; + ptr->next->next = NULL; +} + +void +game_fruit(int *fruit, Snake_Pos **snake) +{ + do { + fruit[0] = rand() % SCREEN_SIDE * SCREEN_UNIT; + fruit[1] = rand() % SCREEN_SIDE * SCREEN_UNIT; + } while (_collision(fruit, snake)); +} + +void +game_snake_fall(Snake_Pos **snake, bool norm, int speed) +{ + Snake_Pos *ptr = *snake; + while(ptr != NULL) { + ptr->y += norm ? speed : -speed; + ptr = ptr->next; + } +} + +void +game_pipe_init(Snake_Pos **pipe) +{ + Snake_Pos *ptr; + while ((ptr = *pipe) != NULL) { + *pipe = (*pipe)->next; + free(ptr); + } + + *pipe = malloc(sizeof(Snake_Pos)); + (*pipe)->x = SCREEN_HEIGHT; + (*pipe)->y = (rand() % (SCREEN_SIDE - PIPE_GAP) + PIPE_GAP) * + SCREEN_UNIT; + (*pipe)->next = NULL; +} + +void +game_pipe_move(Snake_Pos **pipe) +{ + Snake_Pos *ptr = *pipe; + while(ptr != NULL) { + ptr->x -= 1; + ptr = ptr->next; + } +} + +void +game_pipe_add(Snake_Pos **pipe) +{ + Snake_Pos *ptr = *pipe; + while(ptr->next != NULL) + ptr = ptr->next; + ptr->next = malloc(sizeof(Snake_Pos)); + ptr->next->x = SCREEN_HEIGHT; + ptr->next->y = (rand() % (SCREEN_SIDE - PIPE_GAP) + PIPE_GAP) * + SCREEN_UNIT; + ptr->next->next = NULL; +} + +void +game_pipe_del(Snake_Pos **pipe) +{ + Snake_Pos *ptr = *pipe; + *pipe = (*pipe)->next; + free(ptr); +} + +void +game_pipe_pos(Snake_Pos **pipe, int *state) +{ + Snake_Pos *ptr = *pipe; + *state = 0; + *state += ptr->x + SCREEN_UNIT < 0 ? 1 : 0; + while(ptr->next != NULL) + ptr = ptr->next; + *state += ptr->x < SCREEN_HEIGHT - PIPE_DISTANCE * SCREEN_UNIT ? 2 : 0; +} + +/* + * This function returns the dimension of pipes + * that snake is currently passing through, + * so that we can avoid checking all pipes for + * collision + * + * Array elements: x, w, y0, h0, y1, h1 + */ +void +game_pipe_bound(Snake_Pos **pipe, int *pos) +{ + Snake_Pos *ptr = *pipe; + while(ptr != NULL) { + if (ptr->x < SCREEN_HEIGHT / 2 && + ptr->x + SCREEN_UNIT > SCREEN_HEIGHT / 2) { + pos[0] = ptr->x; + pos[1] = SCREEN_UNIT; + pos[2] = 0; + pos[3] = ptr->y - PIPE_GAP / 2 * SCREEN_UNIT; + pos[4] = ptr->y + PIPE_GAP / 2 * SCREEN_UNIT; + pos[5] = SCREEN_HEIGHT - ptr->y - SCREEN_UNIT; + return; + } + ptr = ptr->next; + } + pos[0] = 0; +} |