From c100e56944590985ed8ecbdcbc5f0d27b6542767 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sun, 19 Oct 2025 14:52:49 -0300 Subject: feat:the game Kinda forgot commit. --- Makefile | 4 +- game.c | 104 +++++++++++++++++++++++++++++++++++++++ main.c | 6 --- map.h | 17 +++++++ snake.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ snake.h | 54 +++++++++++++++++++++ 6 files changed, 344 insertions(+), 8 deletions(-) create mode 100644 game.c delete mode 100644 main.c create mode 100644 map.h diff --git a/Makefile b/Makefile index 027c0c6..149cb8f 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,8 @@ OBJ = $(patsubst %.c, %.o, $(SRC)) CC := gcc -CFLAGS := -Wall -Wextra -Werror -pedantic -std=c99 -g -LDFLAGS := +CFLAGS := -Wall -Wextra -Werror -g +LDFLAGS := -lncurses $(TARGET): $(OBJ) $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ diff --git a/game.c b/game.c new file mode 100644 index 0000000..7a213c3 --- /dev/null +++ b/game.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include "snake.h" + +#define DEFAULT_WIDTH 30 +#define DEFAULT_HEIGHT 25 + +/* draws the game map. Excepts a window large enough to print the map */ +static void draw(WINDOW *display, Map *map) { + werase(display); + + box(display, 0, 0); + + if (!map->fruit_eaten) { + mvwaddch(display, map->fruit.y, map->fruit.x, '*'); + } + + for (PointList *i = map->snake->tail; i != NULL; i = i->next) { + mvwaddch(display, i->point.y, i->point.x, '#'); + } + + wrefresh(display); +} + +int main(int argc, char **argv) { + setlocale(LC_ALL, ""); + + initscr(); + cbreak(); + noecho(); + nodelay(stdscr, true); + curs_set(0); + + const unsigned short target_fps = 5; + bool quit = false; + + Map *map; + if (argc == 3) { + unsigned int width = (unsigned int)strtol(argv[1], NULL, 10); + unsigned int height = (unsigned int)strtol(argv[2], NULL, 10); + map = create_map(width, height); + } else { + map = create_map(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + if (map == NULL) { + fprintf(stderr, "ERROR: Failed to allocate map"); + endwin(); + exit(1); + } + + WINDOW *map_window = newwin(map->height, map->width, (LINES/2) - (map->height/2), (COLS/2) - (map->width/2)); + + draw(map_window, map); + + while (!quit) { + int key; + + /* Get Input */ + key = getch(); + + switch(key) { + case 'w': + map->snake->moving_direction = NORTH; + break; + case 'a': + map->snake->moving_direction = WEST; + break; + case 's': + map->snake->moving_direction = SOUTH; + break; + case 'd': + map->snake->moving_direction = EAST; + break; + case 'q': + quit = true; + break; + } + + /* Process game logic */ + if (!move_snake(map)) { + nodelay(stdscr, false); + /* TODO: Proper game over logic */ + clear(); + mvprintw(0, 0, "Game Over"); + getch(); + quit = true; + } + + /* Draw frame */ + if (!quit) draw(map_window, map); + + /* TODO: calculate a proper wait time */ + napms((1.0f/(float)target_fps) * 1000); + } + + free_map(map); + + delwin(map_window); + endwin(); + return 0; +} diff --git a/main.c b/main.c deleted file mode 100644 index 6cc468f..0000000 --- a/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("Hello, world!\n"); - return 0; -} diff --git a/map.h b/map.h new file mode 100644 index 0000000..018376f --- /dev/null +++ b/map.h @@ -0,0 +1,17 @@ +#ifndef MAP_H +#define MAP_H + +typedef struct Point { + int x; + int y; +} Point; + +typedef struct Map { + Point fruit; + unsigned int height; + unsigned int width; +} Map; + +Map createMap(unsigned int width, unsigned int height); + +#endif diff --git a/snake.c b/snake.c index 8b13789..0cd6915 100644 --- a/snake.c +++ b/snake.c @@ -1 +1,168 @@ +#include "snake.h" +#include +#include +#include +static bool position_in_snake(Point point, const Snake *snake) { + for (PointList *i = snake->tail; i != NULL; i = i->next) { + if (point.x == i->point.x && point.y == i->point.y) { + return true; + } + } + return false; +} + +static bool point_out_of_bounds(Point point, const Map* map) { + if (point.x >= map->width || point.y >= map->height) + return true; + return false; +} + +static void spawn_fruit(Map *map) { + if (map->snake->length >= map->width * map->height) return; + + Point point; + do { + point.x = rand() % map->width; + point.y = rand() % map->height; + } while(position_in_snake(point, map->snake)); + + map->fruit.x = point.x; + map->fruit.y = point.y; + map->fruit_eaten = false; +} + +void free_snake(Snake *snake) { + while(snake->tail != NULL) { + PointList *tmp = snake->tail; + snake->tail = snake->tail->next; + free(tmp); + } + free(snake); +} + +/*⠀⠀⠀⢘⠀⡂⢠⠆⠀⡰⠀⡀⢀⣠⣶⣦⣶⣶⣶⣶⣾⣿⣿⡿⢀⠈⢐⠈⠀⠀ + *⠀⠀⠀⡃⠀⡀⣞⡇⢰⠃⣼⣇⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⣰⣻⡀⢸⠀⠀⠀ + *⠀⠀⢐⢀⠀⣛⣽⣇⠘⢸⣿⣿⣷⣾⣿⣿⣿⣿⣿⣿⠟⢡⣾⣿⢿⡇⠀⡃⠀⠀ + *⠀⠀⢐⠀⠀⢳⣿⡯⡞⣾⣿⣿⣿⣿⣿⣿⢿⣿⠟⢁⣴⣿⣿⣿⡜⢷⠀⢘⠄⠀ + *⠀⠀⠂⡂⠸⡆⠙⠛⡵⣿⣿⣿⣿⣿⡿⠤⠛⣠⣴⣿⣿⠿⣟⣟⠟⢿⡆⢳⠀⠀ + *⠀⠀⠸⠁⠀⡾⠁⠀⠀⠀⠀⠉⠉⠉⠈⣠⡌⢁⠄⡛⠡⠉⠍⠙⢳⢾⠁⢸⠀⠀ + *⠀⠀⢈⠀⢀⠌⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣷⡎⠙⢬⣳⣪⡯⢜⣷⢸⠂⡈⠄⠀ + *⠀⠀⠐⡀⠀⢣⠀⠀⠀⠀⠀⠀⠀⣴⣿⣾⣷⢿⢻⣅⣌⡯⢛⣿⣿⡞⠠⡁⠂⠀ + *⠀⠀⠀⠄⠀⢉⡀⠀⠀⢀⡠⠤⠼⣇⣳⣿⣿⣟⡜⣿⣿⣿⣿⣿⣿⡇⠸⠡⠀⠀ + *⠀⠀⡀⠅⠀⠃⢀⡀⣿⡹⠗⢀⠛⠥⣺⣿⣿⡝⢹⣸⣿⣿⣿⣿⡏⠠⠰⠈⠐⠀ + *⠠⠈⠀⠄⣀⠀⠀⠸⠻⠦⠀⠀⠀⠀⠀⠉⠐⠀⠘⠻⢹⣿⡿⠃⠀⡀⠕⣈⠡⡄ + *⠀⠀⣴⡀⣬⠁⠀⠀⡁⠂⠀⣀⣀⠔⠌⠤⣀⡀⠀⠀⡈⢸⠪⠀⠀⡌⠤⠈⡀⣠ + *⠀⠀⣿⣿⣾⡇⠀⠀⠀⣴⢫⣾⠃⠠⢰⣶⣴⠶⣿⣦⠀⠀⠀⢄⣂⠀⠀⠰⠀⠙ + *⠀⠀⠉⠛⠛⠀⢀⣴⣿⢗⡟⠡⣄⣀⡀⠀⢀⣤⠞⡅⠀⠁⠀⡾⠀⠀⠠⡗⠀⢀ + *⠀⠀⠀⠀⠀⣴⡿⢋⠔⠃⠀⠀⠍⠙⠉⠈⠑⠁⠂⠀⠀⠀⡡⡁⣠⡼⣸⠅⠀⠘ + *⠀⠀⠀⣼⠛⢡⠔⠁⠐⣆⠀⠀⠀⠀⠀⠀⠀⠀⠁⢀⡔⡞⢛⣿⡿⠃⠏⠀⠀⢠ + *⠀⠀⠀⠈⠗⠀⠀⠀⠀⠘⣷⣀⢀⣀⣀⠀⡀⢀⣌⡧⠂⠀⡞⠛⡟⠀⠀⠀⡠⠜ + *⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠓⠈⠙⠙⠋⠉⠁⠀⠀⠀⠀⠀⠀⠀⡂⠠⠤⢶ + */ +Snake *create_snake(unsigned int x, unsigned int y, Direction direction) { + Snake *snake = malloc(sizeof(Snake)); + if (snake == NULL) return NULL; + snake->head = malloc(sizeof(PointList)); + if (snake->head == NULL) { + free(snake); + return NULL; + } + snake->length = 1; + snake->tail = snake->head; + + snake->head->point.x = x; + snake->head->point.y = y; + + snake->moving_direction = direction; + + return snake; +} + +Map *create_map(unsigned int width, unsigned int height) { + srand(time(NULL)); + + Map *map = malloc(sizeof(Map)); + if (map == NULL) return NULL; + + map->width = width; + map->height = height; + + unsigned int snake_x = rand() % width; + unsigned int snake_y = rand() % height; + + Direction snake_dir; + if (rand() % 2 == 0) { + if (snake_x > width / 2) { + snake_dir = WEST; + } else { + snake_dir = EAST; + } + } else { + if (snake_y > height / 2) { + snake_dir = NORTH; + } else { + snake_dir = SOUTH; + } + } + + Snake *snake = create_snake(snake_x, snake_y, snake_dir); + if (snake == NULL) { + free_snake(snake); + return NULL; + } + map->snake = snake; + + spawn_fruit(map); + + return map; +} + +bool move_snake(Map *map) { + PointList *neohead = malloc(sizeof(PointList)); + if (neohead == NULL) { + exit(1); + } + neohead->point = map->snake->head->point; + neohead->next = NULL; + + switch(map->snake->moving_direction) { + case NORTH: + neohead->point.y--; + break; + case WEST: + neohead->point.x--; + break; + case EAST: + neohead->point.x++; + break; + case SOUTH: + neohead->point.y++; + break; + break; + } + + if (point_out_of_bounds(neohead->point, map)) return false; + + if (position_in_snake(neohead->point, map->snake)) return false; + + map->snake->head->next = neohead; + map->snake->head = neohead; + + if (neohead->point.x == map->fruit.x && neohead->point.y == map->fruit.y && !map->fruit_eaten) { + map->fruit_eaten = true; + map->snake->length++; + spawn_fruit(map); + } else { + PointList *tmp = map->snake->tail; + map->snake->tail = map->snake->tail->next; + free(tmp); + } + + return true; +} + +void free_map(Map *map) { + free_snake(map->snake); + free(map); +} diff --git a/snake.h b/snake.h index e69de29..a7439bb 100644 --- a/snake.h +++ b/snake.h @@ -0,0 +1,54 @@ +#ifndef SNAKE_H +#define SNAKE_H + +#include +#include + +typedef enum Direction { + NORTH, + WEST, + EAST, + SOUTH +} Direction; + +typedef struct Point { + unsigned int x; + unsigned int y; +} Point; + +typedef struct PointList { + Point point; + struct PointList *next; +} PointList; + +typedef struct Snake { + PointList *head; + PointList *tail; + size_t length; + Direction moving_direction; +} Snake; + +typedef struct Map { + Point fruit; + Snake *snake; + bool fruit_eaten; + unsigned int height; + unsigned int width; +} Map; + +Snake *create_snake(unsigned int x, unsigned int y, Direction direction); + +Map *create_map(unsigned int width, unsigned int height); + +/* Attempts to move the snake. + * Returns true if the snake sucessfully moved, + * false for game over. + */ +bool move_snake(Map *map); + +/* Frees the snake */ +void free_snake(Snake *snake); + +void free_map(Map *map); + +#endif /* SNAKE_H */ -- cgit v1.2.3