/* * Copyright (c) 2019-2021, yzrh * * SPDX-License-Identifier: Apache-2.0 */ #include #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; }