aboutsummaryrefslogtreecommitdiffstats
path: root/src/game.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game.c')
-rw-r--r--src/game.c317
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;
+}