Compare commits
	
		
			17 Commits
		
	
	
		
			cfd4ccad64
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 93a2c37a6c | |||
| fb7856b69e | |||
| 299612634b | |||
| 665b8135a3 | |||
| ae65999622 | |||
| f5ea2867b8 | |||
| 9a6d15f269 | |||
| 40a3668049 | |||
| 4f6bbdd775 | |||
| e124e3071e | |||
| 6b0e858064 | |||
| 103f85d07e | |||
| a2d4290076 | |||
| f0e9d5c751 | |||
| 0e133aff32 | |||
| d09742ba79 | |||
| 027dbb8882 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,9 @@ | |||||||
| # Clion files | # Clion files | ||||||
| .idea | .idea | ||||||
|  |  | ||||||
|  | # Cmake files | ||||||
|  | cmake-build-debug | ||||||
|  |  | ||||||
| # Prerequisites | # Prerequisites | ||||||
| *.d | *.d | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,34 +0,0 @@ | |||||||
| cmake_minimum_required() |  | ||||||
|  |  | ||||||
| # ------------------------------------------------------------------ |  | ||||||
| #  Define a custom target to run the default 'make' command |  | ||||||
| # ------------------------------------------------------------------ |  | ||||||
| add_custom_target( |  | ||||||
|         MinigameMenu |  | ||||||
|         COMMAND ${MAKE_EXECUTABLE} |  | ||||||
|         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |  | ||||||
|         COMMENT "Running make in the project directory..." |  | ||||||
|         VERBATIM |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # ------------------------------------------------------------------ |  | ||||||
| #  Define a custom target to run 'make clean' |  | ||||||
| # ------------------------------------------------------------------ |  | ||||||
| add_custom_target( |  | ||||||
|         Clean |  | ||||||
|         COMMAND ${MAKE_EXECUTABLE} clean |  | ||||||
|         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |  | ||||||
|         COMMENT "Running make clean in the project directory..." |  | ||||||
|         VERBATIM |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # ------------------------------------------------------------------ |  | ||||||
| #  Define a custom target to run 'make clean' |  | ||||||
| # ------------------------------------------------------------------ |  | ||||||
| add_custom_target( |  | ||||||
|         Tarball |  | ||||||
|         COMMAND ${MAKE_EXECUTABLE} tarball2 |  | ||||||
|         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |  | ||||||
|         COMMENT "Running make tarball in the project directory..." |  | ||||||
|         VERBATIM |  | ||||||
| ) |  | ||||||
							
								
								
									
										55
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,27 +1,40 @@ | |||||||
| CC = gcc | CFLAGS = -std=gnu11 -Wextra -pedantic -Wall -O0 -g3 -fsanitize=address | ||||||
| CFLAGS = -std=c11 -Wextra -Wpedantic -g3 -fsanitize=address | LDFLAGS = -lncurses -fsanitize=address | ||||||
| LDFLAGS = -lncursesw -fsanitize=address | BUILD_DIR = build | ||||||
| SRC = $(filter-out voorbeeld.c,$(wildcard *.c)) | SRC_DIR = src | ||||||
| HEADERS = $(wildcard *.h) | GAMES_DIR = games | ||||||
|  | ENGINE_DIR = engine | ||||||
|  |  | ||||||
| .PHONY: tarball1 tarball2 clean | MAIN_OBJECTS = $(BUILD_DIR)/main.o \ | ||||||
|  | 	$(BUILD_DIR)/minigame_menu.o \ | ||||||
|  | 	$(BUILD_DIR)/snake.o \ | ||||||
|  | 	$(BUILD_DIR)/maze_runner.o \ | ||||||
|  | 	$(BUILD_DIR)/minesweeper.o \ | ||||||
|  | 	$(BUILD_DIR)/manual.o \ | ||||||
|  | 	$(BUILD_DIR)/grid.o \ | ||||||
|  | 	$(BUILD_DIR)/grid_game_engine.o | ||||||
|  |  | ||||||
| all: spel | .PHONY: clean | ||||||
|  |  | ||||||
| spel: $(SRC) | main: $(MAIN_OBJECTS) | ||||||
| 	$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) | 	cc $(LDFLAGS) -o main $^ | ||||||
|  |  | ||||||
| voorbeeld: | $(BUILD_DIR)/main.o: src/main.c | ||||||
| 	$(CC) -o voorbeeld voorbeeld.c $(CFLAGS) $(LDFLAGS) | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
|  | $(BUILD_DIR)/minigame_menu.o: src/games/minigame-menu/minigame_menu.c | ||||||
| tarball1: deel1.tar.gz | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
| tarball2: deel2.tar.gz | $(BUILD_DIR)/snake.o: src/games/snake/snake.c | ||||||
|  | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
| deel1.tar.gz: spel.c rooster.h rooster.c Makefile | $(BUILD_DIR)/maze_runner.o: src/games/maze-runner/maze_runner.c | ||||||
| 	tar czf $@ $^ | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
|  | $(BUILD_DIR)/minesweeper.o: src/games/minesweeper/minesweeper.c | ||||||
| deel2.tar.gz: $(SRC) $(HEADERS) Makefile | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
| 	tar czf $@ $^ assets | $(BUILD_DIR)/manual.o: src/games/manual/manual.c | ||||||
|  | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
|  | $(BUILD_DIR)/grid.o: src/engine/grid/grid.c | ||||||
|  | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
|  | $(BUILD_DIR)/grid_game_engine.o: src/engine/engine/grid_game_engine.c | ||||||
|  | 	cc $(CFLAGS) -o $@ -c $^ | ||||||
|  |  | ||||||
| clean: | clean: | ||||||
| 	rm -f *~ *.o voorbeeld spel deel?.tar.gz | 	rm -f build/*.o main | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								Makefile.trial
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Makefile.trial
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | CC = gcc | ||||||
|  | CFLAGS = -std=gnu11 -Wextra -pedantic -Wall -O0 -g3 -fsanitize=address | ||||||
|  | LDFLAGS = -lncursesw -fsanitize=address | ||||||
|  | OBJ_DIR = ./build | ||||||
|  | OBJECTS = $(wildcard $(OBJ_DIR)/*.o) | ||||||
|  | BUILD_COMMAND = $(CC) -c $^ -o $(OBJ_DIR)/$@ $(CFLAGS) $(LDFLAGS) | ||||||
|  |  | ||||||
|  | main: build | ||||||
|  |  | ||||||
|  | build: main.o | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	rm -f *~ $(OBJECTS) main | ||||||
|  |  | ||||||
|  | grid: engine/grid/grid.c | ||||||
|  | 	$(CC) -c $^ -o $(OBJ_DIR)/$@.o $(CFLAGS) $(LDFLAGS) | ||||||
							
								
								
									
										45
									
								
								Makefile.yeet
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Makefile.yeet
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | CC = gcc | ||||||
|  | CFLAGS = -std=gnu11 -Wextra -pedantic -Wall -O0 -g3 -fsanitize=address | ||||||
|  | LDFLAGS = -lncurses -fsanitize=address | ||||||
|  | OBJ_DIR = build/ | ||||||
|  |  | ||||||
|  | OBJECTS = $(wildcard $(OBJ_DIR)/*.o) | ||||||
|  | BUILD_COMMAND = $(CC) -c $^ -o $(OBJ_DIR)/$@ $(CFLAGS) $(LDFLAGS) | ||||||
|  |  | ||||||
|  | SRC = src/ | ||||||
|  | GAMES_DIR = games/ | ||||||
|  | ENGINE_DIR = engine/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .PHONY: clean | ||||||
|  |  | ||||||
|  | build: $(OBJECTS) | ||||||
|  | 	$(CC) -o minigame-menu $(CFLAGS) $(LDFLAGS) | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	rm -f *~ $(OBJECTS) main | ||||||
|  |  | ||||||
|  | main.o: src/main.c | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | minigame-menu.o: src/games | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | manual.o: src/games | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | maze-runner.o: src/games | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | snake.o: src/games | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | minesweeper.o: src/games | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | engine.o: src/engine | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
|  |  | ||||||
|  | grid.o: src/engine | ||||||
|  | 	$(BUILD_COMMAND) | ||||||
							
								
								
									
										87
									
								
								assets/manual.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								assets/manual.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | *--------------------------------------------* | ||||||
|  | |                                            | | ||||||
|  | |           !!! HOWTO MINIGAME !!!           | | ||||||
|  | |                                            | | ||||||
|  | |        Make sure that your terminal        | | ||||||
|  | |        has enough space to display         | | ||||||
|  | |        all the output of the game.         | | ||||||
|  | |                                            | | ||||||
|  | |        This can be achieved by             | | ||||||
|  | |        going fullscreen and/or             | | ||||||
|  | |        zooming out.                        | | ||||||
|  | |                                            | | ||||||
|  | |             *________________*             | | ||||||
|  | |             |    GENERAL     |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |        Exit current screen:        |   | | ||||||
|  | |   |         Escape, backspace          |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Reset zoom:            |   | | ||||||
|  | |   |           "'ctrl' + '0'"           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Zoom out:             |   | | ||||||
|  | |   |           "'ctrl' + '-'"           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Zoom in:              |   | | ||||||
|  | |   |           "'ctrl' + '+'"           |   | | ||||||
|  | |   |      "'ctrl' + 'shift' + '='"      |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |                                            | | ||||||
|  | |        "'ctrl' + '-'"                      | | ||||||
|  | |                                            | | ||||||
|  | |        You can reset the zoom with:        | | ||||||
|  | |        "'ctrl' + '0'"                      | | ||||||
|  | |                                            | | ||||||
|  | |             *________________*             | | ||||||
|  | |             |      MENU      |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Move down:             |   | | ||||||
|  | |   |          's', arrow_down           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Move up:              |   | | ||||||
|  | |   |           'w', arrow_up            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Select:               |   | | ||||||
|  | |   |        'f', enter, space bar       |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |                                            | | ||||||
|  | |            *-----------------*             | | ||||||
|  | |            |   MAZE RUNNER   |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Move up:               |   | | ||||||
|  | |   |          'w', arrow_up             |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Move down:              |   | | ||||||
|  | |   |         's', arrow_down            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Move right:             |   | | ||||||
|  | |   |         'd', arrow_right           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Move left:              |   | | ||||||
|  | |   |         'a', arrow_left            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |                                            | | ||||||
|  | |            *-----------------*             | | ||||||
|  | |            |      SNAKE      |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Turn up:               |   | | ||||||
|  | |   |          'w', arrow_up             |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Turn down:              |   | | ||||||
|  | |   |         's', arrow_down            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Turn right:             |   | | ||||||
|  | |   |         'd', arrow_right           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Turn left:              |   | | ||||||
|  | |   |         'a', arrow_left            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | *--------------------------------------------* | ||||||
| @@ -1,153 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Created by snapshot112 on 10/15/25. |  | ||||||
|  * |  | ||||||
|  * A game engine that can run and display games in square grids. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "grid_game_engine.h" |  | ||||||
|  |  | ||||||
| #include <locale.h> |  | ||||||
| #include <ncurses.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
|  |  | ||||||
| #include "rooster.h" |  | ||||||
|  |  | ||||||
| int modulo(const int number, const int mod) { |  | ||||||
|     int result = number % mod; |  | ||||||
|     if (result < 0) { |  | ||||||
|         result += mod;    //This is not how math is supposed to work C, damnit. |  | ||||||
|     } |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void show_grid_on_offset(const rooster *gp, const int starting_x, const int starting_y) { |  | ||||||
|     const int height = rooster_hoogte(gp); |  | ||||||
|  |  | ||||||
|     for (int y = 0; y < height; y++) { |  | ||||||
|         char *rij = rooster_vraag_rij(gp, y); |  | ||||||
|         mvprintw(starting_y + y, starting_x, "%s", rij); |  | ||||||
|         free(rij); |  | ||||||
|     } |  | ||||||
|     refresh(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void show_grid(const rooster *rp) { |  | ||||||
|     show_grid_on_offset(rp, 0, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void update_grid(rooster *rp, char c, int x, int y) { |  | ||||||
|     if (rooster_plaats(rp, x, y, c) == 1) { |  | ||||||
|         mvaddch(y, x, c); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Shows the victory screen. |  | ||||||
|  * |  | ||||||
|  * Side Effect: |  | ||||||
|  * Clears the console and prints the victory message. |  | ||||||
|  */ |  | ||||||
| static void display_victory(void) { |  | ||||||
|     clear(); |  | ||||||
|     mvprintw(2,5, "YOU WON!!!!!"); |  | ||||||
|     refresh(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Shows the GAME OVER screen. |  | ||||||
|  * |  | ||||||
|  * Side Effect: |  | ||||||
|  * Clears the console and prints the GAME OVER message. |  | ||||||
|  */ |  | ||||||
| static void display_loss(void) { |  | ||||||
|     clear(); |  | ||||||
|     mvprintw(2,5, "GAME OVER"); |  | ||||||
|     refresh(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Shows the quit screen |  | ||||||
|  * |  | ||||||
|  * Side Effect: |  | ||||||
|  * Clears the console and prints the quit message. |  | ||||||
|  */ |  | ||||||
| static void display_quit(void) { |  | ||||||
|     clear(); |  | ||||||
|     mvprintw(2,5, "You quit the game"); |  | ||||||
|     refresh(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Shows the hacker man screen |  | ||||||
|  * |  | ||||||
|  * Side Effect: |  | ||||||
|  * Clears the console and prints the hacker man message. |  | ||||||
|  */ |  | ||||||
| static void display_hackerman(void) { |  | ||||||
|     clear(); |  | ||||||
|     mvprintw(2,5, "The hacker man strikes again..."); |  | ||||||
|     refresh(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void graceful_exit(void) { |  | ||||||
|     mvprintw(5, 5, "Press 'q' to exit."); |  | ||||||
|     while (1) { |  | ||||||
|         switch (getch()) { |  | ||||||
|             case 'q': |  | ||||||
|             case 'Q': |  | ||||||
|                 return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void game_exit_screen(rooster *gp) { |  | ||||||
|     toestand current_state = rooster_vraag_toestand(gp); |  | ||||||
|     switch (current_state) { |  | ||||||
|         case STATE_GEWONNEN: |  | ||||||
|             display_victory(); |  | ||||||
|             break; |  | ||||||
|         case STATE_VERLOREN: |  | ||||||
|             display_loss(); |  | ||||||
|             break; |  | ||||||
|         case STATE_QUIT: |  | ||||||
|             display_quit(); |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             display_hackerman(); |  | ||||||
|     } |  | ||||||
|     graceful_exit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void init_ncurses() { |  | ||||||
|     setlocale(LC_ALL, ""); |  | ||||||
|     initscr(); |  | ||||||
|     cbreak();             // So you can cancel the game with ctrl + c. |  | ||||||
|     keypad(stdscr, TRUE); // Enable extra keys like the arrow keys. |  | ||||||
|     noecho();             // Don't write the keyboard input to the console. |  | ||||||
|     curs_set(0);          // Hides the cursor. |  | ||||||
|  |  | ||||||
|     // mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); // Don't mask any mouse events |  | ||||||
|     // printf("\033[?1003h\n"); // Makes the terminal report mouse movement events |  | ||||||
|  |  | ||||||
|     start_color(); |  | ||||||
|     init_pair(BLACK, COLOR_BLACK, COLOR_BLACK); |  | ||||||
|     init_pair(WHITE, COLOR_BLACK, COLOR_WHITE); |  | ||||||
|     init_pair(BLUE, COLOR_BLACK, COLOR_BLUE); |  | ||||||
|     init_pair(GREEN, COLOR_BLACK, COLOR_GREEN); |  | ||||||
|     init_pair(CYAN, COLOR_BLACK, COLOR_CYAN); |  | ||||||
|     init_pair(MAGENTA, COLOR_BLACK, COLOR_MAGENTA); |  | ||||||
|     init_pair(YELLOW, COLOR_BLACK, COLOR_YELLOW); |  | ||||||
|     init_pair(RED, COLOR_BLACK, COLOR_RED); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void cleanup_ncurses() { |  | ||||||
|     endwin(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void init_engine(void) { |  | ||||||
|     init_ncurses(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void cleanup_engine(void) { |  | ||||||
|     cleanup_ncurses(); |  | ||||||
| } |  | ||||||
| @@ -1,103 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Created by snapshot112 on 10/15/25. |  | ||||||
|  * |  | ||||||
|  * A game engine that uses the can run and display games in rectangular grids. |  | ||||||
|  * The graphics are made using ncursesw. |  | ||||||
|  * |  | ||||||
|  * Please make sure to initialize the game engine before running any games. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #ifndef MINIGAME_MENU_GRID_GAME_ENGINE_H |  | ||||||
| #define MINIGAME_MENU_GRID_GAME_ENGINE_H |  | ||||||
| #include "rooster.h" |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     BLACK = 1, |  | ||||||
|     WHITE = 2, |  | ||||||
|     BLUE = 3, |  | ||||||
|     GREEN = 4, |  | ||||||
|     CYAN = 5, |  | ||||||
|     MAGENTA = 6, |  | ||||||
|     YELLOW = 7, |  | ||||||
|     RED = 8 |  | ||||||
| } game_colors; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|     char name[100]; |  | ||||||
|     rooster *game_map; |  | ||||||
| } game_maps; |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * A proper modulo function. |  | ||||||
|  * The one provided by c: '%' doesn't work according to the mathematical definition. |  | ||||||
|  */ |  | ||||||
| int modulo(int number, int mod); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Displays the given grid with the given offset using ncurses. |  | ||||||
|  * |  | ||||||
|  * Input: |  | ||||||
|  * gp: A pointer to the grid. |  | ||||||
|  * |  | ||||||
|  * Side effect: |  | ||||||
|  * The console is cleared and the grid is printed. |  | ||||||
|  */ |  | ||||||
| void show_grid_on_offset(const rooster *gp, int starting_x, int starting_y); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Displays the given grid with ncurses. |  | ||||||
|  * |  | ||||||
|  * Input: |  | ||||||
|  * gp: A pointer to the grid. |  | ||||||
|  * |  | ||||||
|  * Side effect: |  | ||||||
|  * The console is cleared and the grid is printed. |  | ||||||
|  */ |  | ||||||
| void show_grid(const rooster *gp); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Updates a single location in the grid. |  | ||||||
|  * |  | ||||||
|  * Input: |  | ||||||
|  * gp: A pointer to the grid. |  | ||||||
|  * c: The character to update the location with. |  | ||||||
|  * x: The x-coordinate of the spot you want to update. |  | ||||||
|  * y: The y-coordinate of the spot you want to update. |  | ||||||
|  * |  | ||||||
|  * Side effect: |  | ||||||
|  * The update gets applied both on the grid and on the screen. |  | ||||||
|  */ |  | ||||||
| void update_grid(rooster *gp, char c, int x, int y); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Display the ending screen that matches the end state of the grid. |  | ||||||
|  * |  | ||||||
|  * Input: |  | ||||||
|  * gp: A pointer to the grid. |  | ||||||
|  * |  | ||||||
|  * Side Effects: |  | ||||||
|  * The end of game screen gets displayed with a graceful exit. |  | ||||||
|  */ |  | ||||||
| void game_exit_screen(rooster *gp); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Waits for you to press 'q' before exiting the game. |  | ||||||
|  * |  | ||||||
|  * Side effect: Prints "Press 'q' to exit." game to the console. |  | ||||||
|  */ |  | ||||||
| void graceful_exit(void); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Initialize ncurses. |  | ||||||
|  * |  | ||||||
|  * This enables cbreak, noecho, hides the cursor and enables the extra keys. |  | ||||||
|  * This also creates the color pairs needed for game_colors, |  | ||||||
|  */ |  | ||||||
| void init_engine(void); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Cleanup ncurses. |  | ||||||
|  */ |  | ||||||
| void cleanup_engine(void); |  | ||||||
|  |  | ||||||
| #endif //MINIGAME_MENU_GRID_GAME_ENGINE_H |  | ||||||
							
								
								
									
										128
									
								
								maze_runner.c
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								maze_runner.c
									
									
									
									
									
								
							| @@ -1,128 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by snapshot112 on 10/15/25. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "maze_runner.h" |  | ||||||
|  |  | ||||||
| #include <ncurses.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
|  |  | ||||||
| #include "grid_game_engine.h" |  | ||||||
| #include "rooster.h" |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Reads in the maze from the assets file. |  | ||||||
|  */ |  | ||||||
| static rooster *get_maze(void) { |  | ||||||
|     // TODO: echt opties aanbieden in plaats van hardcoded 1 maze. |  | ||||||
|     // Alternatief is om random een maze te genereren. dit is miss beter. |  | ||||||
|  |  | ||||||
|     // 2. Open het doolhof bestand en lees het rooster. |  | ||||||
|     FILE *fh = fopen("assets/maze.txt", "r"); |  | ||||||
|     if (fh == NULL) { |  | ||||||
|         perror("loading maze"); |  | ||||||
|         exit(EXIT_FAILURE); |  | ||||||
|     } |  | ||||||
|     rooster *rp = rooster_lees(fh); |  | ||||||
|     fclose(fh); |  | ||||||
|  |  | ||||||
|     // 3. Bepaal of het lezen van het rooster is gelukt. |  | ||||||
|     if (rp == NULL) { |  | ||||||
|         fprintf(stderr, "Kan rooster niet maken.\n"); |  | ||||||
|         exit(EXIT_FAILURE); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return rp; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Voert de benodigde veranderingen in het rooster door als de speler in een |  | ||||||
|  * bepaalde richting probeert te bewegen. |  | ||||||
|  * Input: |  | ||||||
|  * rp   : een pointer naar het rooster |  | ||||||
|  * dx,dy: de richting waarin de speler probeert te bewegen. De vier mogelijk- |  | ||||||
|  *        heden voor (dx,dy) zijn (-1,0), (1,0), (0,-1), (0,1) voor resp. |  | ||||||
|  *        links, rechts, omhoog en omlaag. |  | ||||||
|  * |  | ||||||
|  * Side effect: het rooster wordt aangepast op basis van de handeling van |  | ||||||
|  *              de speler. |  | ||||||
|  */ |  | ||||||
| static void maze_runner_beweeg(rooster *rp, int dx, int dy) { |  | ||||||
|     int playerx; |  | ||||||
|     int playery; |  | ||||||
|     rooster_zoek(rp, '*', &playerx, &playery); |  | ||||||
|  |  | ||||||
|     if (playerx == -1 || playery == -1) { |  | ||||||
|         printf("Player not found!"); |  | ||||||
|         exit(1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (rooster_bevat(rp, playerx + dx, playery + dy) == 1) { |  | ||||||
|         char new_location = rooster_kijk(rp, playerx + dx, playery + dy); |  | ||||||
|         switch (new_location) { |  | ||||||
|             case '#': |  | ||||||
|                 break; |  | ||||||
|             case 'X': |  | ||||||
|                 update_grid(rp, ' ', playerx, playery); |  | ||||||
|                 rooster_zet_toestand(rp, STATE_VERLOREN); |  | ||||||
|                 break; |  | ||||||
|             case ' ': |  | ||||||
|                 update_grid(rp, ' ', playerx, playery); |  | ||||||
|                 update_grid(rp, '*', playerx + dx, playery + dy); |  | ||||||
|                 break; |  | ||||||
|             case '$': |  | ||||||
|                 update_grid(rp, ' ', playerx, playery); |  | ||||||
|                 rooster_zet_toestand(rp, STATE_GEWONNEN); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|         refresh(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Speelt het spel met een gegeven rooster tot de toestand niet langer |  | ||||||
|  * AAN_HET_SPELEN is. |  | ||||||
|  */ |  | ||||||
| static void speel_maze(rooster *rp) { |  | ||||||
|     while (rooster_vraag_toestand(rp) == STATE_AAN_HET_SPELEN) |  | ||||||
|     { |  | ||||||
|         switch (getch()) { |  | ||||||
|             case KEY_UP: // fallthrough |  | ||||||
|             case 'w': |  | ||||||
|             case 'W': |  | ||||||
|                 maze_runner_beweeg(rp, 0, -1); |  | ||||||
|                 break; |  | ||||||
|             case KEY_DOWN: // fallthrough |  | ||||||
|             case 's': |  | ||||||
|             case 'S': |  | ||||||
|                 maze_runner_beweeg(rp, 0, 1); |  | ||||||
|                 break; |  | ||||||
|             case KEY_LEFT: // fallthrough |  | ||||||
|             case 'a': |  | ||||||
|             case 'A': |  | ||||||
|                 maze_runner_beweeg(rp, -1, 0); |  | ||||||
|                 break; |  | ||||||
|             case KEY_RIGHT: // fallthrough |  | ||||||
|             case 'd': |  | ||||||
|             case 'D': |  | ||||||
|                 maze_runner_beweeg(rp, 1, 0); |  | ||||||
|                 break; |  | ||||||
|             case KEY_BACKSPACE: |  | ||||||
|                 rooster_zet_toestand(rp, STATE_QUIT); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void maze_runner(void) { |  | ||||||
|     // Voorbereiding. |  | ||||||
|     rooster *rp = get_maze(); |  | ||||||
|     show_grid(rp); |  | ||||||
|     rooster_zet_toestand(rp, STATE_AAN_HET_SPELEN); |  | ||||||
|  |  | ||||||
|     // Game zelf. |  | ||||||
|     speel_maze(rp); |  | ||||||
|  |  | ||||||
|     // Exit game. |  | ||||||
|     game_exit_screen(rp); |  | ||||||
|     rooster_klaar(rp); |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Created by snapshot112 on 10/15/25. |  | ||||||
|  * |  | ||||||
|  * A minigame menu for games configured to run on the grid game engine. |  | ||||||
|  * |  | ||||||
|  * Please make sure to include and initialize the game engine before calling menu(); |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #ifndef MINIGAME_MENU_MINIGAME_MENU_H |  | ||||||
| #define MINIGAME_MENU_MINIGAME_MENU_H |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     GAME_MAZE_RUNNER = 0, |  | ||||||
|     GAME_SNAKE = 1, |  | ||||||
|     GAME_MINESWEEPER = 2, |  | ||||||
|     GAME_QUIT = 3, |  | ||||||
| } game; |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * A minigame menu for games configured to run on the grid game engine. |  | ||||||
|  * |  | ||||||
|  * Please make sure to include and initialize the game engine before calling menu(); |  | ||||||
|  * |  | ||||||
|  * Side Effects: |  | ||||||
|  * Clears the console and uses it to display a minigame menu. |  | ||||||
|  * |  | ||||||
|  * Controls: |  | ||||||
|  * 'w'/'arr_up:     Next menu item. |  | ||||||
|  * 's'/'arr_down':  Previous menu item. |  | ||||||
|  * 'f':             Select current menu item. |  | ||||||
|  * 'BACKSPACE':     Exit the menu. |  | ||||||
|  */ |  | ||||||
| void minigame_menu(void); |  | ||||||
|  |  | ||||||
| #endif //MINIGAME_MENU_MINIGAME_MENU_H |  | ||||||
							
								
								
									
										295
									
								
								rooster.c
									
									
									
									
									
								
							
							
						
						
									
										295
									
								
								rooster.c
									
									
									
									
									
								
							| @@ -1,295 +0,0 @@ | |||||||
| #include "rooster.h" |  | ||||||
|  |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * The rooster type this program is build around. |  | ||||||
|  */ |  | ||||||
| typedef struct rooster_data { |  | ||||||
|     char *rost; |  | ||||||
|     int height; |  | ||||||
|     int width; |  | ||||||
|     toestand state; |  | ||||||
| } rooster; |  | ||||||
|  |  | ||||||
| rooster *rooster_maak(const char* input) { |  | ||||||
|     int width = 0; |  | ||||||
|     int height = 0; |  | ||||||
|     const size_t len = strlen(input) / sizeof(char); |  | ||||||
|     if (input == NULL || len == 0) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     for (int i = 0; input[i] != '\n'; i++) { |  | ||||||
|         width++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     height = (int)len / (width + 1); |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < height; i = i + width + 1) { |  | ||||||
|         if ((int)strcspn(&input[i], "\n") != width) { |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const int grid_size = (width + 1) * height + 1; |  | ||||||
|  |  | ||||||
|     rooster *rp = malloc(sizeof(rooster)); |  | ||||||
|  |  | ||||||
|     if (rp == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     rp->rost = malloc(grid_size * sizeof(char)); |  | ||||||
|     rp->height = height; |  | ||||||
|     rp->width = width; |  | ||||||
|     rp->state = STATE_BEGIN; |  | ||||||
|  |  | ||||||
|     strcpy(rp->rost, input); |  | ||||||
|  |  | ||||||
|     return rp; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Sets a grids width and height |  | ||||||
|  * |  | ||||||
|  * Input: |  | ||||||
|  * fh: the stream to read the grid from. |  | ||||||
|  * rost: a rooster file to store the width and height in. |  | ||||||
|  * |  | ||||||
|  * Side effects: |  | ||||||
|  * the rooster gets its width and height set |  | ||||||
|  * |  | ||||||
|  * Output: |  | ||||||
|  * 1 if the file width and height seem to match with its size |  | ||||||
|  * 0 otherwise |  | ||||||
|  */ |  | ||||||
| static int get_grid_sizes(FILE *fh, rooster *rost) { |  | ||||||
|     while (getc(fh) != '\n') { |  | ||||||
|         if (feof(fh)) { |  | ||||||
|             return 0; |  | ||||||
|         } |  | ||||||
|         rost->width++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (rost->width == 0) { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fseek(fh, 0, SEEK_END); |  | ||||||
|  |  | ||||||
|     // Get file size (- 1 for the blank newline and EOF at the end) |  | ||||||
|     if (ftell(fh) % (rost->width + 1) != 0) { |  | ||||||
|         // Not all lines are the same width |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     rost->height = (int)ftell(fh) / (int)sizeof(char) / rost->width; |  | ||||||
|     fseek(fh, 0, SEEK_SET); |  | ||||||
|  |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| rooster *rooster_lees(FILE *fh) { |  | ||||||
|     if (fh == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     rooster rost = { |  | ||||||
|         NULL, |  | ||||||
|         0, |  | ||||||
|         0, |  | ||||||
|         STATE_BEGIN |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     // Sets the width and height of the rooster. |  | ||||||
|     if (get_grid_sizes(fh, &rost) != 1) { |  | ||||||
|         // Unlogical file structure. |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const int grid_size = (rost.width + 1) * rost.height + 1; |  | ||||||
|  |  | ||||||
|     rost.rost = malloc(grid_size * sizeof(char)); |  | ||||||
|     if (rost.rost == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // This makes the strncat() work. |  | ||||||
|     rost.rost[0] = '\0'; |  | ||||||
|  |  | ||||||
|     char *line = malloc((rost.width + 2) * sizeof(char)); |  | ||||||
|     if (line == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < rost.height; i++) { |  | ||||||
|         if (fgets(line, rost.width + 2, fh) == NULL) { |  | ||||||
|             free(rost.rost); |  | ||||||
|             free(line); |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Validate that the line length is correct |  | ||||||
|         if ((int)strcspn(line, "\n") != rost.width) { |  | ||||||
|             free(rost.rost); |  | ||||||
|             free(line); |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Width is without the newline at the end. |  | ||||||
|         strncat(rost.rost, line, rost.width + 1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     free(line); |  | ||||||
|  |  | ||||||
|     rooster *return_rooster = malloc(sizeof(rost)); |  | ||||||
|     if (return_rooster == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     memcpy(return_rooster, &rost, sizeof(rost)); |  | ||||||
|  |  | ||||||
|     return return_rooster; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| toestand rooster_vraag_toestand(const rooster *rp) { |  | ||||||
|     if (rp != NULL) { |  | ||||||
|         return rp->state; |  | ||||||
|     } |  | ||||||
|     return STATE_VERLOREN; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void rooster_zet_toestand(rooster *rp, toestand t) { |  | ||||||
|     if (rp != NULL) { |  | ||||||
|         switch (t) { |  | ||||||
|             case STATE_BEGIN: |  | ||||||
|                 rp->state = STATE_BEGIN; |  | ||||||
|                 break; |  | ||||||
|             case STATE_AAN_HET_SPELEN: |  | ||||||
|                 rp->state = STATE_AAN_HET_SPELEN; |  | ||||||
|                 break; |  | ||||||
|             case STATE_GEWONNEN: |  | ||||||
|                 rp->state = STATE_GEWONNEN; |  | ||||||
|                 break; |  | ||||||
|             case STATE_VERLOREN: |  | ||||||
|                 rp->state = STATE_VERLOREN; |  | ||||||
|                 break; |  | ||||||
|             case STATE_QUIT: |  | ||||||
|                 rp->state = STATE_QUIT; |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void rooster_klaar(rooster *rp) { |  | ||||||
|     if (rp != NULL) { |  | ||||||
|         if (rp->rost != NULL) |  | ||||||
|         { |  | ||||||
|             free(rp->rost); |  | ||||||
|         } |  | ||||||
|         free(rp); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int rooster_breedte(const rooster *rp) { |  | ||||||
|     if (rp == NULL) { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|     return rp->width; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int rooster_hoogte(const rooster *rp) { |  | ||||||
|     if (rp == NULL) { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|     return rp->height; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int internal_location(const rooster *rp, const int x, const int y) { |  | ||||||
|     return y * (rp->width + 1) + x; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int rooster_bevat(const rooster *rp, int x, int y) { |  | ||||||
|     if (rp != NULL && rp->rost != NULL) { |  | ||||||
|         if (x >= 0 && y >= 0 && x < rp->width && y < rp->height) |  | ||||||
|         { |  | ||||||
|             return 1; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| char rooster_kijk(const rooster *rp, int x, int y) { |  | ||||||
|     if (rp != NULL && rp->rost != NULL && rooster_bevat(rp, x, y) == 1) { |  | ||||||
|         return rp->rost[internal_location(rp, x, y)]; |  | ||||||
|     } |  | ||||||
|     return '\0'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int rooster_plaats(rooster *rp, int x, int y, char c) { |  | ||||||
|     if (rp != NULL && rp->rost != NULL && rooster_bevat(rp, x, y) == 1) { |  | ||||||
|         rp->rost[internal_location(rp, x, y)] = c; |  | ||||||
|         return 1; |  | ||||||
|     } |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| char *rooster_vraag_rij(const rooster *rp, int y) { |  | ||||||
| 	if (rp != NULL && rp->rost != NULL && rooster_bevat(rp, 0, y) == 1) { |  | ||||||
| 	    // we're going to remove the newline so this is long enough |  | ||||||
| 		char *row = malloc((rp->width + 1) * sizeof(char)); |  | ||||||
| 		memcpy(row, &rp->rost[internal_location(rp, 0, y)], rp->width * sizeof(char)); |  | ||||||
| 	    row[rp->width] = '\0'; |  | ||||||
| 		return row; |  | ||||||
| 	} |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| rooster *rooster_kopieer(const rooster *rp) { |  | ||||||
| 	if (rp != NULL && rp->rost != NULL) { |  | ||||||
| 	    const size_t grid_memory = ((rp->width + 1) * rp->height + 1) * sizeof(char); |  | ||||||
|  |  | ||||||
|         char *grid = malloc(grid_memory); |  | ||||||
|         if (grid == NULL) { |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         rooster *new_rooster = malloc(sizeof(*rp)); |  | ||||||
|         if (new_rooster == NULL) { |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
| 	    memcpy(grid, rp->rost, grid_memory); |  | ||||||
|  |  | ||||||
|         memcpy(new_rooster, rp, sizeof(*rp)); |  | ||||||
|  |  | ||||||
|         new_rooster->rost = grid; |  | ||||||
|         return new_rooster; |  | ||||||
|     } |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void rooster_zoek(const rooster *rp, char c, int *x, int *y) { |  | ||||||
|     if (rp == NULL || rp->rost == NULL) { |  | ||||||
|         *x = -1; |  | ||||||
|         *y = -1; |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const char search[2] = {c}; |  | ||||||
|  |  | ||||||
|     int strpos = strcspn(rp->rost, search); |  | ||||||
|  |  | ||||||
|     if (rp->rost[strpos] == '\0') |  | ||||||
|     { |  | ||||||
|         *x = -1; |  | ||||||
|         *y = -1; |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     *x = strpos % (rp->width + 1); |  | ||||||
|     *y = strpos / (rp->width + 1); |  | ||||||
| } |  | ||||||
							
								
								
									
										177
									
								
								rooster.h
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								rooster.h
									
									
									
									
									
								
							| @@ -1,177 +0,0 @@ | |||||||
| /* rooster.h |  | ||||||
|  |  | ||||||
|    Deze module verzorgt het datatype "rooster". Een rooster representeert een |  | ||||||
|    rechthoekig grid van objecten. Elk object is in dit rooster een char. |  | ||||||
|  |  | ||||||
|    Deze header file beschrijft het interface voor "rooster". |  | ||||||
|    De implementatie, in "rooster.c", moet je grotendeels zelf schrijven. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #ifndef _ROOSTER_H |  | ||||||
| #define _ROOSTER_H |  | ||||||
|  |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
|  // Dankzij de typedef hoef je niet telkens "struct rooster_data" te schrijven. |  | ||||||
|  // Definieer struct rooster_data in rooster.c. |  | ||||||
| struct rooster_data; |  | ||||||
| typedef struct rooster_data rooster; |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     STATE_BEGIN, |  | ||||||
|     STATE_AAN_HET_SPELEN, |  | ||||||
|     STATE_GEWONNEN, |  | ||||||
|     STATE_VERLOREN, |  | ||||||
|     STATE_QUIT |  | ||||||
| } toestand; |  | ||||||
|  |  | ||||||
| /* Maak een rooster op basis van de data in de gegeven stream. |  | ||||||
|  |  | ||||||
|    fh: de stream waaruit het doolhof gelezen moet worden. |  | ||||||
|  |  | ||||||
|    Uitvoer: als alles goed gaat, een pointer naar een rooster (die op de heap is |  | ||||||
|             gealloceerd), dat overeenkomt met de gegeven beschrijving. |  | ||||||
|             De begintoestand is BEGIN. |  | ||||||
|  |  | ||||||
|             Als de beschrijving niet consistent is (bijvoorbeeld |  | ||||||
|             niet alle rijen zijn even lang, of er klopt iets anders niet), of |  | ||||||
|             als niet voldoende geheugen kan worden gereserveerd, dan wordt |  | ||||||
|             NULL teruggegeven. (In dat geval blijft geen gereserveerd geheugen |  | ||||||
|             achter.) |  | ||||||
| */ |  | ||||||
| rooster *rooster_lees(FILE *fh); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Maak een rooster op basis van een gegeven string. |  | ||||||
|  * |  | ||||||
|  * Uitvoer: als alles goed gaat, een pointer naar een rooster (die op de heap is |  | ||||||
|  *         gealloceerd), dat overeenkomt met de gegeven beschrijving. |  | ||||||
|  *         De begintoestand is BEGIN. |  | ||||||
|  * |  | ||||||
|  *         Als de beschrijving niet consistent is (bijvoorbeeld |  | ||||||
|  *         niet alle rijen zijn even lang, of er klopt iets anders niet), of |  | ||||||
|  *         als niet voldoende geheugen kan worden gereserveerd, dan wordt |  | ||||||
|  *         NULL teruggegeven. (In dat geval blijft geen gereserveerd geheugen |  | ||||||
|  *         achter.) |  | ||||||
|  */ |  | ||||||
| rooster *rooster_maak(const char* input); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Haal een rij uit het rooster op. |  | ||||||
|  * |  | ||||||
|  * Input: |  | ||||||
|  * rp: een pointer naar het rooster |  | ||||||
|  * y: de y-coordinaat van de rij die je wilt hebben. |  | ||||||
|  * |  | ||||||
|  * Output: |  | ||||||
|  * Een pointer naar een nieuwe string met daarin alle karakters in die rij. |  | ||||||
|  */ |  | ||||||
| char *rooster_vraag_rij(const rooster *rp, int y); |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Maak een kopie van een rooster |  | ||||||
|  * |  | ||||||
|  * Input: |  | ||||||
|  * rp: Een pointer naar het rooster. |  | ||||||
|  * |  | ||||||
|  * Output: |  | ||||||
|  * Een pointer naar het kopie. |  | ||||||
|  */ |  | ||||||
| rooster *rooster_kopieer(const rooster *rp); |  | ||||||
|  |  | ||||||
| /* Vraag de huidige toestand van het spel op. |  | ||||||
|  |  | ||||||
|    Input: |  | ||||||
|    rp: een pointer naar het rooster. |  | ||||||
|  |  | ||||||
|    Uitvoer: de toestand. |  | ||||||
| */ |  | ||||||
| toestand rooster_vraag_toestand(const rooster *rp); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Verander de huidige toestand van het spel. |  | ||||||
|  |  | ||||||
|    rp: een pointer naar het rooster. |  | ||||||
|    t:  de nieuwe toestand. |  | ||||||
| */ |  | ||||||
| void rooster_zet_toestand(rooster *rp, toestand t); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Geef alle resources vrij die zijn gealloceerd voor een rooster. |  | ||||||
|    De rooster pointer is na aanroep van deze functie niet meer bruikbaar. |  | ||||||
|  |  | ||||||
|    rp: een pointer naar het rooster. |  | ||||||
| */ |  | ||||||
| void rooster_klaar(rooster *rp); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Vraag de breedte van het rooster op, dat wil zeggen, het aantal kolommen. |  | ||||||
|  |  | ||||||
|    rp: een pointer naar het rooster. |  | ||||||
|  |  | ||||||
|    Uitvoer: de breedte. |  | ||||||
| */ |  | ||||||
| int rooster_breedte(const rooster *rp); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Vraag de hoogte van het rooster op, dat wil zeggen, het aantal rijen. |  | ||||||
|  |  | ||||||
|    rp: een pointer naar het rooster. |  | ||||||
|  |  | ||||||
|    Uitvoer: de hoogte. |  | ||||||
| */ |  | ||||||
| int rooster_hoogte(const rooster *rp); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Kijk of de gegeven positie binnen het rooster valt. |  | ||||||
|  |  | ||||||
|    rp:  een pointer naar het rooster. |  | ||||||
|    x,y: de positie. |  | ||||||
|  |  | ||||||
|    Uitvoer: 1 als de positie binnen het rooster valt, anders 0. |  | ||||||
| */ |  | ||||||
| int rooster_bevat(const rooster *rp, int x, int y); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Kijk welk object er staat op een bepaalde positie in het rooster. |  | ||||||
|  |  | ||||||
|    rp : een pointer naar het rooster |  | ||||||
|    x,y: de betreffende positie. |  | ||||||
|  |  | ||||||
|    Uitvoer: het object op die positie, of '\0' als de positie buiten het |  | ||||||
|             rooster valt. |  | ||||||
| */ |  | ||||||
| char rooster_kijk(const rooster *rp, int x, int y); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Schrijf een bepaald object op een bepaalde positie in het rooster. |  | ||||||
|  |  | ||||||
|    rp : een pointer naar het rooster |  | ||||||
|    x,y: de betreffende positie. |  | ||||||
|    c  : het object. |  | ||||||
|  |  | ||||||
|    Effect: als (x,y) binnen het rooster ligt, wordt het object op |  | ||||||
|            de opgegeven positie geplaatst, anders verandert er niets. |  | ||||||
|  |  | ||||||
|    Uitvoer: 1 als het object is geplaatst, of 0 als het buiten de grenzen lag. |  | ||||||
| */ |  | ||||||
| int rooster_plaats(rooster *rp, int x, int y, char c); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Zoek een bepaald object in het rooster, en geef de coordinaten van het |  | ||||||
|    object terug via de gegeven pointers. Let op: als er meerdere objecten van |  | ||||||
|    het gezochte soort in het rooster voorkomen, is niet gedefinieerd van welke |  | ||||||
|    de positie wordt gevonden. |  | ||||||
|  |  | ||||||
|    rp : een pointer naar het rooster |  | ||||||
|    c  : het object dat moet worden gezocht |  | ||||||
|    x,y: pointers naar de geheugenlocaties waar de gevonden positie moet worden |  | ||||||
|         geschreven. |  | ||||||
|  |  | ||||||
|    Uitvoer: via de pointers x en y. Als het object niet wordt gevonden worden |  | ||||||
|             *x en *y op -1 gezet. |  | ||||||
| */ |  | ||||||
| void rooster_zoek(const rooster *rp, char c, int *x, int *y); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										16
									
								
								snake.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								snake.c
									
									
									
									
									
								
							| @@ -1,16 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by snapshot112 on 10/15/25. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "snake.h" |  | ||||||
|  |  | ||||||
| #include <ncurses.h> |  | ||||||
|  |  | ||||||
| #include "grid_game_engine.h" |  | ||||||
|  |  | ||||||
| void snake(void) { |  | ||||||
|     clear(); |  | ||||||
|     mvprintw(0,0, "Snake has not yet been created"); |  | ||||||
|     graceful_exit(); |  | ||||||
|     refresh(); |  | ||||||
| } |  | ||||||
							
								
								
									
										24
									
								
								spel.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								spel.c
									
									
									
									
									
								
							| @@ -1,24 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Naam: Jeroen Boxhoorn |  | ||||||
|  * UvAnetID: 16333969 |  | ||||||
|  * Studie: BSc Informatica |  | ||||||
|  * |  | ||||||
|  * A minigame menu that lets you play games on the grid game engine. |  | ||||||
|  * |  | ||||||
|  * Currently the following games are included: |  | ||||||
|  * - maze runner |  | ||||||
|  * - snake |  | ||||||
|  * - minesweeper |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "grid_game_engine.h" |  | ||||||
| #include "minigame_menu.h" |  | ||||||
|  |  | ||||||
| int main(void) { |  | ||||||
|     init_engine(); |  | ||||||
|  |  | ||||||
|     // 5. Speel het spel. |  | ||||||
|     minigame_menu(); |  | ||||||
|  |  | ||||||
|     cleanup_engine(); |  | ||||||
| } |  | ||||||
							
								
								
									
										160
									
								
								src/engine/engine/grid_game_engine.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								src/engine/engine/grid_game_engine.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 8/10/2025 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "grid_game_engine.h" | ||||||
|  |  | ||||||
|  | #include <locale.h> | ||||||
|  | #include <ncurses.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | int same_coordinate(const coordinate a, const coordinate b) { | ||||||
|  |     return a.x == b.x && a.y == b.y; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int modulo(const int number, const int mod) { | ||||||
|  |     int result = number % mod; | ||||||
|  |     if (result < 0) { | ||||||
|  |         result += mod;    //This is not how math is supposed to work C, damnit. | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void show_grid_on_offset(const grid *gp, const coordinate offset) { | ||||||
|  |     const int height = grid_height(gp); | ||||||
|  |  | ||||||
|  |     for (int y = 0; y < height; y++) { | ||||||
|  |         char *rij = grid_fetch_row(gp, y); | ||||||
|  |         mvprintw(offset.y + y, offset.x, "%s", rij); | ||||||
|  |         free(rij); | ||||||
|  |     } | ||||||
|  |     refresh(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void show_grid(const grid *gp) { | ||||||
|  |     show_grid_on_offset(gp, (coordinate){.x = 0, .y = 0}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void update_grid(grid *gp, const char ch, coordinate c) { | ||||||
|  |     if (grid_put(gp, ch, c) == 1) { | ||||||
|  |         mvaddch(c.y, c.x, ch); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Shows the victory screen. | ||||||
|  |  * | ||||||
|  |  * Side Effect: | ||||||
|  |  * Clears the console and prints the victory message. | ||||||
|  |  */ | ||||||
|  | static void display_victory(const coordinate location) { | ||||||
|  |     mvaddstr(location.y, location.x, "YOU WON!!!!!"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Shows the GAME OVER screen. | ||||||
|  |  * | ||||||
|  |  * Side Effect: | ||||||
|  |  * Clears the console and prints the GAME OVER message. | ||||||
|  |  */ | ||||||
|  | static void display_loss(const coordinate location) { | ||||||
|  |     mvaddstr(location.y, location.x, "GAME OVER"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Shows the quit screen | ||||||
|  |  * | ||||||
|  |  * Side Effect: | ||||||
|  |  * Clears the console and prints the quit message. | ||||||
|  |  */ | ||||||
|  | static void display_quit(const coordinate location) { | ||||||
|  |     mvaddstr(location.y, location.x, "You quit the game"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Shows the hacker man screen | ||||||
|  |  * | ||||||
|  |  * Side Effect: | ||||||
|  |  * Clears the console and prints the hacker man message. | ||||||
|  |  */ | ||||||
|  | static void display_hackerman(const coordinate location) { | ||||||
|  |     mvaddstr(location.y, location.x, "The hacker man strikes again..."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void graceful_exit(const coordinate message_location) { | ||||||
|  |     mvaddstr(message_location.y, message_location.x, "Press ENTER to exit."); | ||||||
|  |     while (1) { | ||||||
|  |         switch (getch()) { | ||||||
|  |             case KEY_BACKSPACE: | ||||||
|  |             case KEY_ESCAPE: | ||||||
|  |             case KEY_ENTER: | ||||||
|  |             case '\n': | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void game_exit_message(const grid *gp, coordinate location) { | ||||||
|  |     const state current_state = grid_fetch_state(gp); | ||||||
|  |     switch (current_state) { | ||||||
|  |         case STATE_GEWONNEN: | ||||||
|  |             display_victory(location); | ||||||
|  |             break; | ||||||
|  |         case STATE_VERLOREN: | ||||||
|  |             display_loss(location); | ||||||
|  |             break; | ||||||
|  |         case STATE_QUIT: | ||||||
|  |             display_quit(location); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             display_hackerman(location); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     location.y += 2; | ||||||
|  |     graceful_exit(location); | ||||||
|  |     refresh(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void enable_highlight(const game_colors color) { | ||||||
|  |     attron(COLOR_PAIR(color)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void disable_highlight(const game_colors color) { | ||||||
|  |     attroff(COLOR_PAIR(color)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Initialize ncurses. | ||||||
|  |  * | ||||||
|  |  * This enables cbreak, noecho, hides the cursor and enables the extra keys. | ||||||
|  |  * This also creates the color pairs needed for game_colors and sets ESCDELAY to 0. | ||||||
|  |  */ | ||||||
|  | static void init_ncurses(void) { | ||||||
|  |     ESCDELAY = 0; | ||||||
|  |     setlocale(LC_ALL, ""); | ||||||
|  |     initscr(); | ||||||
|  |     cbreak();             // So you can cancel the game with ctrl + c. | ||||||
|  |     keypad(stdscr, TRUE); // Enable extra keys like the arrow keys. | ||||||
|  |     noecho();             // Don't write the keyboard input to the console. | ||||||
|  |     curs_set(0);          // Hides the cursor. | ||||||
|  |  | ||||||
|  |     start_color(); | ||||||
|  |     init_pair(BLACK, COLOR_BLACK, COLOR_BLACK); | ||||||
|  |     init_pair(WHITE, COLOR_BLACK, COLOR_WHITE); | ||||||
|  |     init_pair(BLUE, COLOR_BLACK, COLOR_BLUE); | ||||||
|  |     init_pair(GREEN, COLOR_BLACK, COLOR_GREEN); | ||||||
|  |     init_pair(CYAN, COLOR_BLACK, COLOR_CYAN); | ||||||
|  |     init_pair(MAGENTA, COLOR_BLACK, COLOR_MAGENTA); | ||||||
|  |     init_pair(YELLOW, COLOR_BLACK, COLOR_YELLOW); | ||||||
|  |     init_pair(RED, COLOR_BLACK, COLOR_RED); | ||||||
|  |  | ||||||
|  |     clear(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void init_engine(void) { | ||||||
|  |     init_ncurses(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cleanup_engine(void) { | ||||||
|  |     endwin(); | ||||||
|  | } | ||||||
							
								
								
									
										152
									
								
								src/engine/engine/grid_game_engine.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/engine/engine/grid_game_engine.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 15/10/2025. | ||||||
|  |  * | ||||||
|  |  * A game engine build on top of a grid api to run and display games using ncurses. | ||||||
|  |  * | ||||||
|  |  * Please make sure to initialize the game engine before running any games. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef MINIGAME_MENU_GRID_GAME_ENGINE_H | ||||||
|  | #define MINIGAME_MENU_GRID_GAME_ENGINE_H | ||||||
|  | #include "../grid/grid.h" | ||||||
|  |  | ||||||
|  | #define KEY_ESCAPE 27 | ||||||
|  |  | ||||||
|  | // Start at 1 since the color 0 is reserved for no_color. | ||||||
|  | typedef enum { | ||||||
|  |     BLACK = 1, | ||||||
|  |     WHITE = 2, | ||||||
|  |     BLUE = 3, | ||||||
|  |     GREEN = 4, | ||||||
|  |     CYAN = 5, | ||||||
|  |     MAGENTA = 6, | ||||||
|  |     YELLOW = 7, | ||||||
|  |     RED = 8 | ||||||
|  | } game_colors; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     char name[100]; | ||||||
|  |     grid *game_map; | ||||||
|  | } game_maps; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Checks if 2 coordinates are the same. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * a: coordinate 1 | ||||||
|  |  * b: coordinate 2 | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * If they point to the same location:  1 | ||||||
|  |  * Otherwise:                           0 | ||||||
|  |  */ | ||||||
|  | int same_coordinate(coordinate a, coordinate b); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * A proper modulo function. | ||||||
|  |  * The one provided by c: '%' doesn't work according to the mathematical definition. | ||||||
|  |  */ | ||||||
|  | int modulo(int number, int mod); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Displays the given grid with the given offset using ncurses. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp: A pointer to the grid. | ||||||
|  |  * c: The location you want to show the grid at. | ||||||
|  |  * | ||||||
|  |  * Side effect: | ||||||
|  |  * The console is cleared and the grid is printed. | ||||||
|  |  */ | ||||||
|  | void show_grid_on_offset(const grid *gp, coordinate c); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Displays the given grid with ncurses. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp: A pointer to the grid. | ||||||
|  |  * | ||||||
|  |  * Side effect: | ||||||
|  |  * The console is cleared and the grid is printed. | ||||||
|  |  */ | ||||||
|  | void show_grid(const grid *gp); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Turn on color highlighting for ncurses | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * color: The color you want the highlight to be. | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * Enables color highlighting in ncurses. | ||||||
|  |  * | ||||||
|  |  * Note: | ||||||
|  |  * This should always be disabled with disable_highlights before being called again. | ||||||
|  |  * Not disabling the current highlight before enabling another one is undefined behaviour. | ||||||
|  |  */ | ||||||
|  | void enable_highlight(game_colors color); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Turn off color highlighting for ncurses | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * color: The color highlighting you want to turn off. | ||||||
|  | * | ||||||
|  |  * Side Effects: | ||||||
|  |  * Enables color highlighting in ncurses. | ||||||
|  |  * | ||||||
|  |  * Note: | ||||||
|  |  * This should always be enabled with enable_highlights before being called. | ||||||
|  |  * Disabling the highlight before enabling it is undefined behaviour. | ||||||
|  |  */ | ||||||
|  | void disable_highlight(game_colors color); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Updates a single location in the grid. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp: A pointer to the grid. | ||||||
|  |  * ch: The character to update the location with. | ||||||
|  |  * c: The spot you want to update. | ||||||
|  |  * | ||||||
|  |  * Side effect: | ||||||
|  |  * The update gets applied both on the grid and on the screen. | ||||||
|  |  */ | ||||||
|  | void update_grid(grid *gp, char ch, coordinate c); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Display the ending screen that matches the end state of the grid. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp:          A pointer to the grid. | ||||||
|  |  * coordinate:  The location to show the ending screen. | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * The end of game screen gets displayed with a graceful exit. | ||||||
|  |  */ | ||||||
|  | void game_exit_message(const grid *gp, coordinate location); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Waits for you to press ENTER before exiting the game. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * coordinate: The location to show the message. | ||||||
|  |  * | ||||||
|  |  * Side effect: Prints "Press ENTER to exit." game to the console. | ||||||
|  |  */ | ||||||
|  | void graceful_exit(coordinate message_location); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Initialize ncurses. | ||||||
|  |  * | ||||||
|  |  * This enables cbreak, noecho, hides the cursor and enables the extra keys. | ||||||
|  |  * This also creates the color pairs needed for game_colors and sets ESCDELAY to 0. | ||||||
|  |  */ | ||||||
|  | void init_engine(void); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Cleanup ncurses. | ||||||
|  |  */ | ||||||
|  | void cleanup_engine(void); | ||||||
|  |  | ||||||
|  | #endif //MINIGAME_MENU_GRID_GAME_ENGINE_H | ||||||
							
								
								
									
										302
									
								
								src/engine/grid/grid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								src/engine/grid/grid.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,302 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 2/10/2025 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "grid.h" | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * The grid type this program is build around. | ||||||
|  |  */ | ||||||
|  | typedef struct grid_data { | ||||||
|  |     char *locations; | ||||||
|  |     int height; | ||||||
|  |     int width; | ||||||
|  |     state state; | ||||||
|  | } grid; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Translate x and y coordinates to a location index on the grid. | ||||||
|  |  */ | ||||||
|  | static int internal_location(const grid *gp, const coordinate c) { | ||||||
|  |     return c.y * (gp->width + 1) + c.x; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | grid *grid_create_from_string(const char* input) { | ||||||
|  |     int width = 0; | ||||||
|  |     int height = 0; | ||||||
|  |     const size_t len = strlen(input) / sizeof(char); | ||||||
|  |     if (input == NULL || len == 0) { | ||||||
|  |         printf("invalid input\n"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; input[i] != '\n'; i++) { | ||||||
|  |         width++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     height = (int)len / (width + 1); | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < height; i = i + width + 1) { | ||||||
|  |         if ((int)strcspn(&input[i], "\n") != width) { | ||||||
|  |             printf("line %d was not %d wide\n", i, width); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const int grid_size = (width + 1) * height + 1; | ||||||
|  |  | ||||||
|  |     grid *gp = malloc(sizeof(grid)); | ||||||
|  |  | ||||||
|  |     if (gp == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     gp->locations = malloc(grid_size * sizeof(char)); | ||||||
|  |     gp->height = height; | ||||||
|  |     gp->width = width; | ||||||
|  |     gp->state = STATE_BEGIN; | ||||||
|  |  | ||||||
|  |     strcpy(gp->locations, input); | ||||||
|  |  | ||||||
|  |     return gp; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Sets a grids width and height | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * fh: The stream to read the grid from. | ||||||
|  |  * gp: A pointer to the grid whose width and height you want to set. | ||||||
|  |  * | ||||||
|  |  * Side effects: | ||||||
|  |  * the grid gets its width and height set | ||||||
|  |  * | ||||||
|  |  * Output: | ||||||
|  |  * 1 if the file width and height seem to match with its size | ||||||
|  |  * 0 otherwise | ||||||
|  |  */ | ||||||
|  | static int get_grid_sizes(FILE *fh, grid *gp) { | ||||||
|  |     while (getc(fh) != '\n') { | ||||||
|  |         if (feof(fh)) { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         gp->width++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (gp->width == 0) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fseek(fh, 0, SEEK_END); | ||||||
|  |  | ||||||
|  |     // Get file size (- 1 for the blank newline and EOF at the end) | ||||||
|  |     if (ftell(fh) % (gp->width + 1) != 0) { | ||||||
|  |         // Not all lines are the same width | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     gp->height = (int)ftell(fh) / (int)sizeof(char) / (gp->width + 1); | ||||||
|  |     fseek(fh, 0, SEEK_SET); | ||||||
|  |  | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | grid *grid_create_from_file(FILE *fh) { | ||||||
|  |     if (fh == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     grid temp_grid = { | ||||||
|  |         NULL, | ||||||
|  |         0, | ||||||
|  |         0, | ||||||
|  |         STATE_BEGIN | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // Sets the width and height of the grid. | ||||||
|  |     if (get_grid_sizes(fh, &temp_grid) != 1) { | ||||||
|  |         // Unlogical file structure. | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const int grid_size = (temp_grid.width + 1) * temp_grid.height + 1; | ||||||
|  |  | ||||||
|  |     temp_grid.locations = malloc(grid_size * sizeof(char)); | ||||||
|  |     if (temp_grid.locations == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // This makes the strncat() work. | ||||||
|  |     temp_grid.locations[0] = '\0'; | ||||||
|  |  | ||||||
|  |     char *line = malloc((temp_grid.width + 2) * sizeof(char)); | ||||||
|  |     if (line == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < temp_grid.height; i++) { | ||||||
|  |         if (fgets(line, temp_grid.width + 2, fh) == NULL) { | ||||||
|  |             free(temp_grid.locations); | ||||||
|  |             free(line); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Validate that the line length is correct | ||||||
|  |         if ((int)strcspn(line, "\n") != temp_grid.width) { | ||||||
|  |             free(temp_grid.locations); | ||||||
|  |             free(line); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Width is without the newline at the end. | ||||||
|  |         strncat(temp_grid.locations, line, temp_grid.width + 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     free(line); | ||||||
|  |  | ||||||
|  |     grid *return_grid = malloc(sizeof(temp_grid)); | ||||||
|  |     if (return_grid == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     memcpy(return_grid, &temp_grid, sizeof(temp_grid)); | ||||||
|  |  | ||||||
|  |     return return_grid; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | state grid_fetch_state(const grid *gp) { | ||||||
|  |     if (gp != NULL) { | ||||||
|  |         return gp->state; | ||||||
|  |     } | ||||||
|  |     return STATE_VERLOREN; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void grid_put_state(grid *gp, const state t) { | ||||||
|  |     if (gp != NULL) { | ||||||
|  |         switch (t) { | ||||||
|  |             case STATE_BEGIN: | ||||||
|  |                 gp->state = STATE_BEGIN; | ||||||
|  |                 break; | ||||||
|  |             case STATE_AAN_HET_SPELEN: | ||||||
|  |                 gp->state = STATE_AAN_HET_SPELEN; | ||||||
|  |                 break; | ||||||
|  |             case STATE_GEWONNEN: | ||||||
|  |                 gp->state = STATE_GEWONNEN; | ||||||
|  |                 break; | ||||||
|  |             case STATE_VERLOREN: | ||||||
|  |                 gp->state = STATE_VERLOREN; | ||||||
|  |                 break; | ||||||
|  |             case STATE_QUIT: | ||||||
|  |                 gp->state = STATE_QUIT; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void grid_cleanup(grid *gp) { | ||||||
|  |     if (gp != NULL) { | ||||||
|  |         if (gp->locations != NULL) | ||||||
|  |         { | ||||||
|  |             free(gp->locations); | ||||||
|  |         } | ||||||
|  |         free(gp); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int grid_width(const grid *gp) { | ||||||
|  |     if (gp == NULL) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     return gp->width; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int grid_height(const grid *gp) { | ||||||
|  |     if (gp == NULL) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     return gp->height; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int grid_contains(const grid *gp, const coordinate c) { | ||||||
|  |     if (gp != NULL && gp->locations != NULL) { | ||||||
|  |         if (c.x >= 0 && c.y >= 0 && c.x < gp->width && c.y < gp->height) | ||||||
|  |         { | ||||||
|  |             return 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char grid_fetch(const grid *gp, const coordinate c) { | ||||||
|  |     if (gp != NULL && gp->locations != NULL && grid_contains(gp, c) == 1) { | ||||||
|  |         return gp->locations[internal_location(gp, c)]; | ||||||
|  |     } | ||||||
|  |     return '\0'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int grid_put(grid *gp, const char ch, const coordinate c) { | ||||||
|  |     if (gp != NULL && gp->locations != NULL && grid_contains(gp, c) == 1) { | ||||||
|  |         gp->locations[internal_location(gp, c)] = ch; | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *grid_fetch_row(const grid *gp, const int y) { | ||||||
|  |     const coordinate row_start = {.x = 0, .y = y}; | ||||||
|  | 	if (gp != NULL && gp->locations != NULL && grid_contains(gp, row_start) == 1) { | ||||||
|  | 	    // we're going to remove the newline so this is long enough | ||||||
|  | 		char *row = malloc((gp->width + 1) * sizeof(char)); | ||||||
|  | 		memcpy(row, &gp->locations[internal_location(gp, row_start)], gp->width * sizeof(char)); | ||||||
|  | 	    row[gp->width] = '\0'; | ||||||
|  | 		return row; | ||||||
|  | 	} | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | grid *grid_copy(const grid *gp) { | ||||||
|  | 	if (gp != NULL && gp->locations != NULL) { | ||||||
|  | 	    const size_t grid_memory = ((gp->width + 1) * gp->height + 1) * sizeof(char); | ||||||
|  |  | ||||||
|  |         char *locations = malloc(grid_memory); | ||||||
|  |         if (locations == NULL) { | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  | 	    grid *new_grid = malloc(sizeof(*gp)); | ||||||
|  | 	    if (new_grid == NULL) { | ||||||
|  | 	        return NULL; | ||||||
|  | 	    } | ||||||
|  |  | ||||||
|  | 	    memcpy(locations, gp->locations, grid_memory); | ||||||
|  |  | ||||||
|  | 	    memcpy(new_grid, gp, sizeof(*gp)); | ||||||
|  |  | ||||||
|  | 	    new_grid->locations = locations; | ||||||
|  | 	    return new_grid; | ||||||
|  |     } | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | coordinate grid_find(const grid *gp, const char c) { | ||||||
|  |     const coordinate not_found = {.x = -1, .y = -1}; | ||||||
|  |     if (gp == NULL || gp->locations == NULL) { | ||||||
|  |         return not_found; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const char search[2] = {c}; | ||||||
|  |  | ||||||
|  |     const int char_index = (int)strcspn(gp->locations, search); | ||||||
|  |  | ||||||
|  |     if (gp->locations[char_index] == '\0') | ||||||
|  |     { | ||||||
|  |         return not_found; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return (coordinate){.x = char_index % (gp->width + 1), .y = char_index / (gp->width + 1)}; | ||||||
|  | } | ||||||
							
								
								
									
										176
									
								
								src/engine/grid/grid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								src/engine/grid/grid.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,176 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 2/10/2025 | ||||||
|  |  * | ||||||
|  |  * This module provides a grid api. | ||||||
|  |  * | ||||||
|  |  * A grid is a rectangular grid of objects. Every object in this grid is a char. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef _GRID_H | ||||||
|  | #define _GRID_H | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct grid_data; | ||||||
|  | typedef struct grid_data grid; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     int x; | ||||||
|  |     int y; | ||||||
|  | } coordinate; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     STATE_BEGIN, | ||||||
|  |     STATE_AAN_HET_SPELEN, | ||||||
|  |     STATE_GEWONNEN, | ||||||
|  |     STATE_VERLOREN, | ||||||
|  |     STATE_QUIT | ||||||
|  | } state; | ||||||
|  |  | ||||||
|  | /* Maak een rooster op basis van de data in de gegeven stream. | ||||||
|  |  * | ||||||
|  |  * fh: de stream waaruit het doolhof gelezen moet worden. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: als alles goed gaat, een pointer naar een rooster (die op de heap is | ||||||
|  |  *          gealloceerd), dat overeenkomt met de gegeven beschrijving. | ||||||
|  |  *          De begintoestand is BEGIN. | ||||||
|  |  * | ||||||
|  |  *          Als de beschrijving niet consistent is (bijvoorbeeld | ||||||
|  |  *          niet alle rijen zijn even lang, of er klopt iets anders niet), of | ||||||
|  |  *          als niet voldoende geheugen kan worden gereserveerd, dan wordt | ||||||
|  |  *          NULL teruggegeven. (In dat geval blijft geen gereserveerd geheugen | ||||||
|  |  *          achter.) | ||||||
|  |  */ | ||||||
|  | grid *grid_create_from_file(FILE *fh); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Maak een rooster op basis van een gegeven string. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: als alles goed gaat, een pointer naar een rooster (die op de heap is | ||||||
|  |  *         gealloceerd), dat overeenkomt met de gegeven beschrijving. | ||||||
|  |  *         De begintoestand is BEGIN. | ||||||
|  |  * | ||||||
|  |  *         Als de beschrijving niet consistent is (bijvoorbeeld | ||||||
|  |  *         niet alle rijen zijn even lang, of er klopt iets anders niet), of | ||||||
|  |  *         als niet voldoende geheugen kan worden gereserveerd, dan wordt | ||||||
|  |  *         NULL teruggegeven. (In dat geval blijft geen gereserveerd geheugen | ||||||
|  |  *         achter.) | ||||||
|  |  */ | ||||||
|  | grid *grid_create_from_string(const char* input); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Haal een rij uit het rooster op. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp: een pointer naar het rooster | ||||||
|  |  * y: de y-coordinaat van de rij die je wilt hebben. | ||||||
|  |  * | ||||||
|  |  * Output: | ||||||
|  |  * Een pointer naar een nieuwe string met daarin alle karakters in die rij. | ||||||
|  |  */ | ||||||
|  | char *grid_fetch_row(const grid *gp, int y); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Maak een kopie van een rooster | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp: Een pointer naar het rooster. | ||||||
|  |  * | ||||||
|  |  * Output: | ||||||
|  |  * Een pointer naar het kopie. | ||||||
|  |  */ | ||||||
|  | grid *grid_copy(const grid *gp); | ||||||
|  |  | ||||||
|  | /* Vraag de huidige toestand van het spel op. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp: een pointer naar het rooster. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: de toestand. | ||||||
|  |  */ | ||||||
|  | state grid_fetch_state(const grid *gp); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Verander de huidige toestand van het spel. | ||||||
|  |  * | ||||||
|  |  * gp: een pointer naar het rooster. | ||||||
|  |  * t:  de nieuwe toestand. | ||||||
|  |  */ | ||||||
|  | void grid_put_state(grid *gp, state t); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Geef alle resources vrij die zijn gealloceerd voor een rooster. | ||||||
|  |  * De rooster pointer is na aanroep van deze functie niet meer bruikbaar. | ||||||
|  |  * | ||||||
|  |  * gp: een pointer naar het rooster. | ||||||
|  |  */ | ||||||
|  | void grid_cleanup(grid *gp); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Vraag de breedte van het rooster op, dat wil zeggen, het aantal kolommen. | ||||||
|  |  * | ||||||
|  |  * gp: een pointer naar het rooster. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: de breedte. | ||||||
|  |  */ | ||||||
|  | int grid_width(const grid *gp); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Vraag de hoogte van het rooster op, dat wil zeggen, het aantal rijen. | ||||||
|  |  * | ||||||
|  |  * gp: een pointer naar het rooster. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: de hoogte. | ||||||
|  |  */ | ||||||
|  | int grid_height(const grid *gp); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Kijk of de gegeven positie binnen het rooster valt. | ||||||
|  |  * | ||||||
|  |  * gp:  een pointer naar het rooster. | ||||||
|  |  * c: de positie. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: 1 als de positie binnen het rooster valt, anders 0. | ||||||
|  |  */ | ||||||
|  | int grid_contains(const grid *gp, coordinate c); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Kijk welk object er staat op een bepaalde positie in het rooster. | ||||||
|  |  * | ||||||
|  |  * gp: een pointer naar het rooster | ||||||
|  |  * c: de betreffende positie. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: het object op die positie, of '\0' als de positie buiten het | ||||||
|  |  *          rooster valt. | ||||||
|  |  */ | ||||||
|  | char grid_fetch(const grid *gp, coordinate c); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Schrijf een bepaald object op een bepaalde positie in het rooster. | ||||||
|  |  * | ||||||
|  |  * gp: een pointer naar het rooster | ||||||
|  |  * ch: het object. | ||||||
|  |  * c: de locatie. | ||||||
|  |  * | ||||||
|  |  * Effect: als c binnen het rooster ligt, wordt het object op | ||||||
|  |  *         de opgegeven positie geplaatst, anders verandert er niets. | ||||||
|  |  * | ||||||
|  |  * Uitvoer: 1 als het object is geplaatst, of 0 als het buiten de grenzen lag. | ||||||
|  |  */ | ||||||
|  | int grid_put(grid *gp, char ch, coordinate c); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* Zoek een bepaald object in het rooster, en geef de coordinaten van het | ||||||
|  |  * object terug via de gegeven pointers. Let op: als er meerdere objecten van | ||||||
|  |  * het gezochte soort in het rooster voorkomen, is niet gedefinieerd van welke | ||||||
|  |  * de positie wordt gevonden. | ||||||
|  |  * | ||||||
|  |  * gp: een pointer naar het rooster | ||||||
|  |  * c: het object dat moet worden gezocht | ||||||
|  |  * | ||||||
|  |  * Uitvoer: de locatie van het object. (x and y zijn -1 als het niet gevonden is.) | ||||||
|  |  */ | ||||||
|  | coordinate grid_find(const grid *gp, char c); | ||||||
|  |  | ||||||
|  | #endif //_GRID_H | ||||||
							
								
								
									
										87
									
								
								src/games/manual/assets/manual.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/games/manual/assets/manual.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | *--------------------------------------------* | ||||||
|  | |                                            | | ||||||
|  | |           !!! HOWTO MINIGAME !!!           | | ||||||
|  | |                                            | | ||||||
|  | |        Make sure that your terminal        | | ||||||
|  | |        has enough space to display         | | ||||||
|  | |        all the output of the game.         | | ||||||
|  | |                                            | | ||||||
|  | |        This can be achieved by             | | ||||||
|  | |        going fullscreen and/or             | | ||||||
|  | |        zooming out.                        | | ||||||
|  | |                                            | | ||||||
|  | |             *________________*             | | ||||||
|  | |             |    GENERAL     |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |        Exit current screen:        |   | | ||||||
|  | |   |         Escape, backspace          |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Reset zoom:            |   | | ||||||
|  | |   |           "'ctrl' + '0'"           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Zoom out:             |   | | ||||||
|  | |   |           "'ctrl' + '-'"           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Zoom in:              |   | | ||||||
|  | |   |           "'ctrl' + '+'"           |   | | ||||||
|  | |   |      "'ctrl' + 'shift' + '='"      |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |                                            | | ||||||
|  | |        "'ctrl' + '-'"                      | | ||||||
|  | |                                            | | ||||||
|  | |        You can reset the zoom with:        | | ||||||
|  | |        "'ctrl' + '0'"                      | | ||||||
|  | |                                            | | ||||||
|  | |             *________________*             | | ||||||
|  | |             |      MENU      |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Move down:             |   | | ||||||
|  | |   |          's', arrow_down           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Move up:              |   | | ||||||
|  | |   |           'w', arrow_up            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |              Select:               |   | | ||||||
|  | |   |        'f', enter, space bar       |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |                                            | | ||||||
|  | |            *-----------------*             | | ||||||
|  | |            |   MAZE RUNNER   |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Move up:               |   | | ||||||
|  | |   |          'w', arrow_up             |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Move down:              |   | | ||||||
|  | |   |         's', arrow_down            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Move right:             |   | | ||||||
|  | |   |         'd', arrow_right           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Move left:              |   | | ||||||
|  | |   |         'a', arrow_left            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |                                            | | ||||||
|  | |            *-----------------*             | | ||||||
|  | |            |      SNAKE      |             | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |             Turn up:               |   | | ||||||
|  | |   |          'w', arrow_up             |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Turn down:              |   | | ||||||
|  | |   |         's', arrow_down            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Turn right:             |   | | ||||||
|  | |   |         'd', arrow_right           |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   |            Turn left:              |   | | ||||||
|  | |   |         'a', arrow_left            |   | | ||||||
|  | |   |                                    |   | | ||||||
|  | |   *------------------------------------*   | | ||||||
|  | *--------------------------------------------* | ||||||
							
								
								
									
										36
									
								
								src/games/manual/manual.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/games/manual/manual.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 10/17/2025 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "manual.h" | ||||||
|  |  | ||||||
|  | #include <ncurses.h> | ||||||
|  | #include "../../engine/engine/grid_game_engine.h" | ||||||
|  |  | ||||||
|  | void manual(const coordinate display_location) { | ||||||
|  |     erase(); | ||||||
|  |     FILE *fp = fopen("assets/manual.txt", "r"); | ||||||
|  |     if (fp == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     grid *grid = grid_create_from_file(fp); | ||||||
|  |     if (grid == NULL) { | ||||||
|  |         mvaddstr(display_location.y, display_location.x, "Error loading grid"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fclose(fp); | ||||||
|  |  | ||||||
|  |     show_grid_on_offset(grid, display_location); | ||||||
|  |  | ||||||
|  |     // Wait until ESCAPE or BACKSPACE is pressed. | ||||||
|  |     timeout(200); | ||||||
|  |     for (int ch = getch(); ch != KEY_ESCAPE && ch != KEY_BACKSPACE; ch = getch()) { | ||||||
|  |         // Update the screen in the meantime to accommodate windows resizes. | ||||||
|  |         show_grid_on_offset(grid, display_location); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     grid_cleanup(grid); | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								src/games/manual/manual.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/games/manual/manual.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 10/17/2025 | ||||||
|  |  * | ||||||
|  |  * Provides a way to display the minigame manual in the assets in game. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef MINIGAME_MENU_MANUAL_H | ||||||
|  | #define MINIGAME_MENU_MANUAL_H | ||||||
|  | #include "../../engine/engine/grid_game_engine.h" | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * An in game manual for the minigames menu. | ||||||
|  |  * | ||||||
|  |  * Please make sure to include and initialize the game engine before opening the manual | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * display_location: The location to display the manual. | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * Clears the console and uses it to display the manual. | ||||||
|  |  * | ||||||
|  |  * Controls: | ||||||
|  |  * Press ESCAPE or BACKSPACE to exit the manual. | ||||||
|  |  */ | ||||||
|  | void manual(coordinate display_location); | ||||||
|  |  | ||||||
|  | #endif //MINIGAME_MENU_MANUAL_H | ||||||
							
								
								
									
										153
									
								
								src/games/maze-runner/maze_runner.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/games/maze-runner/maze_runner.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 6/10/2025 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "maze_runner.h" | ||||||
|  |  | ||||||
|  | #include <ncurses.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | #include "../../engine/engine/grid_game_engine.h" | ||||||
|  |  | ||||||
|  | #define EMPTY ' ' | ||||||
|  | #define WALL '#' | ||||||
|  | #define LIVING_PLAYER '*' | ||||||
|  | #define DEAD_PLAYER '@' | ||||||
|  | #define MAZE_EXIT '$' | ||||||
|  | #define TRAP 'X' | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Reads in the maze from the assets file. | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * Memory is allocated to store the grid in. | ||||||
|  |  */ | ||||||
|  | static grid *get_maze(void) { | ||||||
|  |     // Open het doolhof bestand en lees het rooster. | ||||||
|  |     FILE *fh = fopen("assets/maze.txt", "r"); | ||||||
|  |     if (fh == NULL) { | ||||||
|  |         perror("loading maze"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     grid *gp = grid_create_from_file(fh); | ||||||
|  |     fclose(fh); | ||||||
|  |  | ||||||
|  |     // Bepaal of het lezen van het rooster is gelukt. | ||||||
|  |     if (gp == NULL) { | ||||||
|  |         fprintf(stderr, "Kan rooster niet maken.\n"); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return gp; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Voert de benodigde veranderingen in het rooster door als de speler in een | ||||||
|  |  * bepaalde richting probeert te bewegen. | ||||||
|  |  * Input: | ||||||
|  |  * gp: een pointer naar het rooster | ||||||
|  |  * offset_vector: de richting waarin de speler probeert te bewegen. De vier mogelijk- | ||||||
|  |  *                heden voor (dx,dy) zijn (-1,0), (1,0), (0,-1), (0,1) voor resp. | ||||||
|  |  *                links, rechts, omhoog en omlaag. | ||||||
|  |  * | ||||||
|  |  * Side effect: het rooster wordt aangepast op basis van de handeling van | ||||||
|  |  *              de speler. | ||||||
|  |  */ | ||||||
|  | static void maze_runner_move(grid *gp, const coordinate offset_vector) { | ||||||
|  |     const coordinate player_position = grid_find(gp, LIVING_PLAYER); | ||||||
|  |  | ||||||
|  |     if (player_position.y == -1) { | ||||||
|  |         printf("Player not found!"); | ||||||
|  |         // State begin for the hackerman ending screen. | ||||||
|  |         grid_put_state(gp, STATE_BEGIN); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     coordinate new_player_position = player_position; | ||||||
|  |     new_player_position.x += offset_vector.x; | ||||||
|  |     new_player_position.y += offset_vector.y; | ||||||
|  |  | ||||||
|  |     if (grid_contains(gp, new_player_position) == 1) { | ||||||
|  |         const char new_location = grid_fetch(gp, new_player_position); | ||||||
|  |         switch (new_location) { | ||||||
|  |             case WALL: | ||||||
|  |                 break; | ||||||
|  |             case TRAP: | ||||||
|  |                 grid_put_state(gp, STATE_VERLOREN); | ||||||
|  |  | ||||||
|  |                 enable_highlight(RED); | ||||||
|  |                 update_grid(gp, DEAD_PLAYER, player_position); | ||||||
|  |                 disable_highlight(RED); | ||||||
|  |                 break; | ||||||
|  |             case EMPTY: | ||||||
|  |                 update_grid(gp, EMPTY, player_position); | ||||||
|  |                 update_grid(gp, LIVING_PLAYER, new_player_position); | ||||||
|  |                 break; | ||||||
|  |             case MAZE_EXIT: | ||||||
|  |                 update_grid(gp, EMPTY, player_position); | ||||||
|  |                 grid_put_state(gp, STATE_GEWONNEN); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |         refresh(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Speelt het spel met een gegeven rooster tot de toestand niet langer | ||||||
|  |  * AAN_HET_SPELEN is. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * gp: Een pointer naar het rooster. | ||||||
|  |  * | ||||||
|  |  * Side effects: | ||||||
|  |  * Het rooster wordt ge-updated afhankelijk van de user input. | ||||||
|  |  */ | ||||||
|  | static void speel_maze(grid *gp) { | ||||||
|  |     coordinate offset_vector = {.x = 0, .y = 0}; | ||||||
|  |     switch (getch()) { | ||||||
|  |         case KEY_UP: // fallthrough | ||||||
|  |         case 'w': | ||||||
|  |         case 'W': | ||||||
|  |             offset_vector.y--; | ||||||
|  |             break; | ||||||
|  |         case KEY_DOWN: // fallthrough | ||||||
|  |         case 's': | ||||||
|  |         case 'S': | ||||||
|  |             offset_vector.y++; | ||||||
|  |             break; | ||||||
|  |         case KEY_LEFT: // fallthrough | ||||||
|  |         case 'a': | ||||||
|  |         case 'A': | ||||||
|  |             offset_vector.x--; | ||||||
|  |             break; | ||||||
|  |         case KEY_RIGHT: // fallthrough | ||||||
|  |         case 'd': | ||||||
|  |         case 'D': | ||||||
|  |             offset_vector.x++; | ||||||
|  |             break; | ||||||
|  |         case 'p': | ||||||
|  |         case KEY_BACKSPACE: | ||||||
|  |         case KEY_ESCAPE: | ||||||
|  |             grid_put_state(gp, STATE_QUIT); | ||||||
|  |             return; | ||||||
|  |     } | ||||||
|  |     maze_runner_move(gp, offset_vector); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void maze_runner(void) { | ||||||
|  |     // Voorbereiding. | ||||||
|  |     grid *gp = get_maze(); | ||||||
|  |     if (gp == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     show_grid(gp); | ||||||
|  |     grid_put_state(gp, STATE_AAN_HET_SPELEN); | ||||||
|  |  | ||||||
|  |     // Game zelf. | ||||||
|  |     while (grid_fetch_state(gp) == STATE_AAN_HET_SPELEN) { | ||||||
|  |         speel_maze(gp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Exit game. | ||||||
|  |     game_exit_message(gp, (coordinate){0, grid_height(gp) + 2}); | ||||||
|  |     grid_cleanup(gp); | ||||||
|  | } | ||||||
| @@ -1,9 +1,11 @@ | |||||||
| /*
 | /*
 | ||||||
|  |  * Created by snapshot112 on 6/10/2025 | ||||||
|  |  * | ||||||
|  * Naam: Jeroen Boxhoorn |  * Naam: Jeroen Boxhoorn | ||||||
|  * UvAnetID: 16333969 |  * UvAnetID: 16333969 | ||||||
|  * Studie: BSc Informatica |  * Studie: BSC Informatica | ||||||
|  * |  * | ||||||
|  * A game of maze runner configured to run on the grid game engine. |  * A game of maze runner build on the grid game engine. | ||||||
|  * |  * | ||||||
|  * Please make sure to include and initialize the game engine before calling maze_runner(); |  * Please make sure to include and initialize the game engine before calling maze_runner(); | ||||||
|  * |  * | ||||||
| @@ -23,7 +25,7 @@ | |||||||
| #define MINIGAME_MENU_MAZE_RUNNER_H | #define MINIGAME_MENU_MAZE_RUNNER_H | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * A game of maze runner configured to run on the grid game engine. |  * A game of maze runner build on the grid game engine. | ||||||
|  * |  * | ||||||
|  * Please make sure to include and initialize the game engine before calling maze_runner(); |  * Please make sure to include and initialize the game engine before calling maze_runner(); | ||||||
|  * |  * | ||||||
| @@ -32,7 +34,7 @@ | |||||||
|  * |  * | ||||||
|  * Controls: |  * Controls: | ||||||
|  * use WSAD or arrow keys to move through the maze. |  * use WSAD or arrow keys to move through the maze. | ||||||
|  * Use BACKSPACE to exit the game early. |  * Use BACKSPACE or ESCAPE to exit the game early. | ||||||
|  */ |  */ | ||||||
| void maze_runner(void); | void maze_runner(void); | ||||||
| 
 | 
 | ||||||
| @@ -1,16 +1,16 @@ | |||||||
| //
 | /*
 | ||||||
| // Created by snapshot112 on 10/15/25.
 |  * Created by snapshot112 on 15/10/2025 | ||||||
| //
 |  */ | ||||||
| 
 | 
 | ||||||
| #include "minesweeper.h" | #include "minesweeper.h" | ||||||
| 
 | 
 | ||||||
| #include <ncurses.h> | #include <ncurses.h> | ||||||
| 
 | 
 | ||||||
| #include "grid_game_engine.h" | #include "../../engine/engine/grid_game_engine.h" | ||||||
| 
 | 
 | ||||||
| void minesweeper() { | void minesweeper() { | ||||||
|     clear(); |     clear(); | ||||||
|     mvprintw(0,0, "Minesweeper has not yet been created"); |     mvprintw(0,0, "Minesweeper has not yet been created"); | ||||||
|     graceful_exit(); |     graceful_exit((coordinate){0, 3}); | ||||||
|     refresh(); |     refresh(); | ||||||
| } | } | ||||||
| @@ -1,18 +1,18 @@ | |||||||
| /*
 | /*
 | ||||||
|  * Created by snapshot112 on 10/15/25. |  * Created by snapshot112 on 15/10/2025 | ||||||
|  * |  * | ||||||
|  * A game of minesweeper runner configured to run on the grid game engine. |  * A game of minesweeper build on the grid game engine. | ||||||
|  * |  * | ||||||
|  * Please make sure to include and initialize the game engine before calling snake(); |  * Please make sure to include and initialize the game engine before calling minesweeper(); | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef MINIGAME_MENU_MINESWEEPER_H | #ifndef MINIGAME_MENU_MINESWEEPER_H | ||||||
| #define MINIGAME_MENU_MINESWEEPER_H | #define MINIGAME_MENU_MINESWEEPER_H | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * A game of minesweeper configured to run on the grid game engine. |  * A game of minesweeper build on the grid game engine. | ||||||
|  * |  * | ||||||
|  * Please make sure to include and initialize the game engine before calling snake(); |  * Please make sure to include and initialize the game engine before calling minesweeper(); | ||||||
|  * |  * | ||||||
|  * Side Effects: |  * Side Effects: | ||||||
|  * Clears the console and uses it to play a game of minesweeper. |  * Clears the console and uses it to play a game of minesweeper. | ||||||
| @@ -1,23 +1,31 @@ | |||||||
| //
 | /*
 | ||||||
| // Created by snapshot112 on 10/15/25.
 |  * Created by snapshot112 on 15/10/2025 | ||||||
| //
 |  */ | ||||||
| 
 | 
 | ||||||
| #include "minigame_menu.h" | #include "minigame_menu.h" | ||||||
| 
 | 
 | ||||||
| #include <ncurses.h> | #include <ncurses.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| 
 | 
 | ||||||
| #include "grid_game_engine.h" | #include "../../engine/engine/grid_game_engine.h" | ||||||
| #include "maze_runner.h" | #include "../manual/manual.h" | ||||||
| #include "minesweeper.h" | #include "../maze-runner/maze_runner.h" | ||||||
| #include "rooster.h" | #include "../minesweeper/minesweeper.h" | ||||||
| #include "snake.h" | #include "../snake/snake.h" | ||||||
| 
 | 
 | ||||||
| #define AMOUNT_OF_MENU_OPTIONS 4 | #define AMOUNT_OF_MENU_OPTIONS 5 | ||||||
| 
 | 
 | ||||||
| static game SELECTED_GAME = GAME_MAZE_RUNNER; | typedef enum { | ||||||
| static int OFFSET_Y = 5; |     GAME_MANUAL = 0, | ||||||
| static int OFFSET_X = 5; |     GAME_MAZE_RUNNER = 1, | ||||||
|  |     GAME_SNAKE = 2, | ||||||
|  |     GAME_MINESWEEPER = 3, | ||||||
|  |     GAME_QUIT = 4, | ||||||
|  | } game; | ||||||
|  | 
 | ||||||
|  | static grid *MENU; | ||||||
|  | static game SELECTED_GAME = GAME_MANUAL; | ||||||
|  | static coordinate OFFSET = {.x = 5, .y = 5}; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Launch a game from the menu. |  * Launch a game from the menu. | ||||||
| @@ -26,8 +34,12 @@ static int OFFSET_X = 5; | |||||||
|  * menu: A pointer to the menu grid. |  * menu: A pointer to the menu grid. | ||||||
|  * game: The game you want to launch. |  * game: The game you want to launch. | ||||||
|  */ |  */ | ||||||
| static void launch_game(rooster *menu, const game game) { | static void launch_game(const game game) { | ||||||
|  |     clear(); | ||||||
|     switch (game) { |     switch (game) { | ||||||
|  |         case GAME_MANUAL: | ||||||
|  |             manual((coordinate){0,0}); | ||||||
|  |             break; | ||||||
|         case GAME_MAZE_RUNNER: |         case GAME_MAZE_RUNNER: | ||||||
|             maze_runner(); |             maze_runner(); | ||||||
|             break; |             break; | ||||||
| @@ -46,23 +58,22 @@ static void launch_game(rooster *menu, const game game) { | |||||||
|  * Input: |  * Input: | ||||||
|  * menu:        A pointer to the menu grid. |  * menu:        A pointer to the menu grid. | ||||||
|  * target:      The menu option to highlight. |  * target:      The menu option to highlight. | ||||||
|  * offset_x:    The x offset of the menu. |  | ||||||
|  * offset_y:    The y offset of the menu. |  | ||||||
|  * |  * | ||||||
|  * Side effects: |  * Side effects: | ||||||
|  * If a valid menu option is provided:      It will be highlighted in green. |  * If a valid menu option is provided:      It will be highlighted in green. | ||||||
|  * If an invalid menu option is provided:   Nothing happens |  * If an invalid menu option is provided:   Nothing happens | ||||||
|  */ |  */ | ||||||
| static void menu_highlight(const rooster *menu) { | static void menu_highlight(const grid *menu) { | ||||||
|     switch (SELECTED_GAME) { |     switch (SELECTED_GAME) { | ||||||
|  |         case GAME_MANUAL: | ||||||
|         case GAME_MAZE_RUNNER: |         case GAME_MAZE_RUNNER: | ||||||
|         case GAME_SNAKE: |         case GAME_SNAKE: | ||||||
|         case GAME_MINESWEEPER: |         case GAME_MINESWEEPER: | ||||||
|         case GAME_QUIT: |         case GAME_QUIT: | ||||||
|             attron(COLOR_PAIR(GREEN)); |             attron(COLOR_PAIR(GREEN)); | ||||||
| 
 | 
 | ||||||
|             char* row = rooster_vraag_rij(menu, SELECTED_GAME); |             char* row = grid_fetch_row(menu, SELECTED_GAME); | ||||||
|             mvprintw(OFFSET_Y + (int)SELECTED_GAME, OFFSET_X,  "%s", row); |             mvprintw(OFFSET.y + (int)SELECTED_GAME, OFFSET.x,  "%s", row); | ||||||
|             free(row); |             free(row); | ||||||
| 
 | 
 | ||||||
|             attroff(COLOR_PAIR(GREEN)); |             attroff(COLOR_PAIR(GREEN)); | ||||||
| @@ -75,16 +86,14 @@ static void menu_highlight(const rooster *menu) { | |||||||
|  * Input: |  * Input: | ||||||
|  * menu:                A pointer to the menu grid. |  * menu:                A pointer to the menu grid. | ||||||
|  * default_selection:   The starting selection in the menu. |  * default_selection:   The starting selection in the menu. | ||||||
|  * offset_x:            The x offset of the menu. |  | ||||||
|  * offset_y:            The y offset of the menu. |  | ||||||
|  * |  * | ||||||
|  * Side Effects: |  * Side Effects: | ||||||
|  * Displays the menu |  * Displays the menu | ||||||
|  */ |  */ | ||||||
| static void show_menu(const rooster *menu) { | static void show_menu() { | ||||||
|     clear(); |     erase(); | ||||||
|     show_grid_on_offset(menu, OFFSET_X, OFFSET_Y); |     show_grid_on_offset(MENU, OFFSET); | ||||||
|     menu_highlight(menu); |     menu_highlight(MENU); | ||||||
|     refresh(); |     refresh(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -114,11 +123,10 @@ static void menu_move(const int offset) { | |||||||
|  * 0: Continue running. |  * 0: Continue running. | ||||||
|  * 1: Exit the menu. |  * 1: Exit the menu. | ||||||
|  * |  * | ||||||
|  * |  | ||||||
|  * Side Effect: |  * Side Effect: | ||||||
|  * Changes the SELECTED_GAME as needed and launches selected games on select. |  * Changes the SELECTED_GAME as needed and launches selected games on select. | ||||||
|  */ |  */ | ||||||
| static int navigate_menu(rooster *menu) { | static int navigate_menu(void) { | ||||||
|     switch (getch()) { |     switch (getch()) { | ||||||
|         case KEY_UP: |         case KEY_UP: | ||||||
|         case 'w': |         case 'w': | ||||||
| @@ -131,14 +139,17 @@ static int navigate_menu(rooster *menu) { | |||||||
|             menu_move(1); |             menu_move(1); | ||||||
|             break; |             break; | ||||||
|         case KEY_ENTER: |         case KEY_ENTER: | ||||||
|  |         case '\n': | ||||||
|         case 'f': |         case 'f': | ||||||
|         case 'F': |         case 'F': | ||||||
|  |         case ' ': | ||||||
|             if (SELECTED_GAME == GAME_QUIT) { |             if (SELECTED_GAME == GAME_QUIT) { | ||||||
|                 return 1; |                 return 1; | ||||||
|             } |             } | ||||||
|             launch_game(menu, SELECTED_GAME); |             launch_game(SELECTED_GAME); | ||||||
|             break; |             break; | ||||||
|         case KEY_BACKSPACE: |         case KEY_BACKSPACE: | ||||||
|  |         case KEY_ESCAPE: | ||||||
|             return 1; |             return 1; | ||||||
|     } |     } | ||||||
|     return 0; |     return 0; | ||||||
| @@ -146,28 +157,25 @@ static int navigate_menu(rooster *menu) { | |||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Create the menu grid. |  * Create the menu grid. | ||||||
|  * |  | ||||||
|  * Output: |  | ||||||
|  * A pointer to the menu grid. |  | ||||||
|  */ |  */ | ||||||
| static rooster *initialize_menu(void) { | static void initialize_menu(void) { | ||||||
|     char menu[] = "Maze Runner\n" |     const char menu[] = "How to play\n" | ||||||
|  |                         "Maze Runner\n" | ||||||
|                         "   Snake   \n" |                         "   Snake   \n" | ||||||
|                         "Minesweeper\n" |                         "Minesweeper\n" | ||||||
|                         "   Leave   \n"; |                         "   Leave   \n"; | ||||||
|     rooster *rp = rooster_maak(menu); |     MENU = grid_create_from_string(menu); | ||||||
|     return rp; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void minigame_menu(void) { | void minigame_menu(void) { | ||||||
|     rooster *menu = initialize_menu(); |     initialize_menu(); | ||||||
| 
 | 
 | ||||||
|     while (true) { |     while (true) { | ||||||
|         show_menu(menu); |         show_menu(); | ||||||
|         if (navigate_menu(menu) == 1) { |         if (navigate_menu() == 1) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     rooster_klaar(menu); |     grid_cleanup(MENU); | ||||||
| } | } | ||||||
							
								
								
									
										28
									
								
								src/games/minigame-menu/minigame_menu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/games/minigame-menu/minigame_menu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 15/10/2025 | ||||||
|  |  * | ||||||
|  |  * A minigame menu for games build on the grid game engine. | ||||||
|  |  * | ||||||
|  |  * Please make sure to include and initialize the game engine before calling menu(); | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef MINIGAME_MENU_MINIGAME_MENU_H | ||||||
|  | #define MINIGAME_MENU_MINIGAME_MENU_H | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * A minigame menu for games build on the grid game engine. | ||||||
|  |  * | ||||||
|  |  * Please make sure to include and initialize the game engine before calling menu(); | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * Clears the console and uses it to display a minigame menu. | ||||||
|  |  * | ||||||
|  |  * Controls: | ||||||
|  |  * 'w'/'arr_up':        Next menu item. | ||||||
|  |  * 's'/'arr_down':      Previous menu item. | ||||||
|  |  * 'f'/'ENTER':         Select current menu item. | ||||||
|  |  * 'BACKSPACE'/'ESC':   Exit the menu. | ||||||
|  |  */ | ||||||
|  | void minigame_menu(void); | ||||||
|  |  | ||||||
|  | #endif //MINIGAME_MENU_MINIGAME_MENU_H | ||||||
							
								
								
									
										449
									
								
								src/games/snake/snake.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										449
									
								
								src/games/snake/snake.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,449 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 15/10/2025 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #define _POSIX_C_SOURCE 199309 | ||||||
|  |  | ||||||
|  | #include "snake.h" | ||||||
|  |  | ||||||
|  | #include <ncurses.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <time.h> | ||||||
|  | #include <pthread.h> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
|  | #include "../../engine/engine/grid_game_engine.h" | ||||||
|  |  | ||||||
|  | #define CELL_EMPTY ' ' | ||||||
|  | #define CELL_FOOD '$' | ||||||
|  | #define CELL_WALL '#' | ||||||
|  | #define DIRECTION_COUNT 4 | ||||||
|  | #define OFFSET_X 6 | ||||||
|  | #define OFFSET_Y 3 | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     SNAKE_MOVE = 0, | ||||||
|  |     SNAKE_EAT = 1, | ||||||
|  |     SNAKE_DIE = 2 | ||||||
|  | } snake_action; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     DIRECTION_UP = 0, | ||||||
|  |     DIRECTION_RIGHT = 1, | ||||||
|  |     DIRECTION_DOWN = 2, | ||||||
|  |     DIRECTION_LEFT = 3 | ||||||
|  | } direction; | ||||||
|  |  | ||||||
|  | // Snake globals | ||||||
|  | static direction PREVIOUS_DIRECTION; | ||||||
|  | static direction CURRENT_DIRECTION; | ||||||
|  | static coordinate SNAKE_HEAD; | ||||||
|  | static coordinate SNAKE_TAIL; | ||||||
|  |  | ||||||
|  | // Map globals | ||||||
|  | static coordinate RENDER_AT; | ||||||
|  | static coordinate MESSAGE_LOCATION = {0,0}; | ||||||
|  | static int MAP_HEIGHT = 20; | ||||||
|  | static int MAP_WIDTH = 20; | ||||||
|  | static grid *GRID; | ||||||
|  | static pthread_mutex_t SNAKE_MUTEX; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Create a snake body part. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * dir: the direction the body part should point to. | ||||||
|  |  * | ||||||
|  |  * Output: | ||||||
|  |  * a character representing that body part. | ||||||
|  |  */ | ||||||
|  | static char get_body_part(const direction dir) { | ||||||
|  |     return (char)(dir + '0'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Gets the direction of a body part. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * body_part: A part of the snake's body. | ||||||
|  |  * | ||||||
|  |  * Output: | ||||||
|  |  * The direction the next body part is pointing to. | ||||||
|  |  */ | ||||||
|  | static direction get_body_part_direction(const char body_part) { | ||||||
|  |     return (direction)(body_part - '0'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Create a grid for snake with a given height and width. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * height: The height of the map. | ||||||
|  |  * width:  The width of the map. | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * A pointer to the grid. | ||||||
|  |  */ | ||||||
|  | static void create_grid(void) { | ||||||
|  |     const int grid_size = (MAP_WIDTH + 1) * MAP_HEIGHT + 1; | ||||||
|  |     char *map = malloc(grid_size * sizeof(char)); | ||||||
|  |     if (map == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 1; i <= (MAP_WIDTH + 1) * MAP_HEIGHT; i++) { | ||||||
|  |         // Also subtract the null terminator | ||||||
|  |         const int bottom_line = i > grid_size - (MAP_WIDTH + 2); | ||||||
|  |         const int top_line = i < MAP_WIDTH + 1; | ||||||
|  |  | ||||||
|  |         const int line_position = modulo(i, MAP_WIDTH + 1); | ||||||
|  |  | ||||||
|  |         const int line_start = line_position == 1; | ||||||
|  |         const int line_end = line_position == MAP_WIDTH; | ||||||
|  |  | ||||||
|  |         const int newline = line_position == 0; | ||||||
|  |  | ||||||
|  |         if (newline) { | ||||||
|  |             map[i - 1] = '\n'; | ||||||
|  |         } else if (top_line || bottom_line || line_start || line_end) { | ||||||
|  |             map[i - 1] = CELL_WALL; | ||||||
|  |         } else { | ||||||
|  |             map[i - 1] = CELL_EMPTY; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     map[grid_size - 1] = '\0'; | ||||||
|  |  | ||||||
|  |     GRID = grid_create_from_string(map); | ||||||
|  |  | ||||||
|  |     free(map); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Spawn a piece of food at an empty grid location. | ||||||
|  |  * | ||||||
|  |  * Side Effect: | ||||||
|  |  * One of the empty grid spaces gets replaced with a piece of food. | ||||||
|  |  */ | ||||||
|  | static void generate_food(void) { | ||||||
|  |     coordinate empty_spots[MAP_HEIGHT * MAP_WIDTH]; | ||||||
|  |  | ||||||
|  |     int available_spots = 0; | ||||||
|  |  | ||||||
|  |     for (int x = 0; x < MAP_WIDTH; x++) { | ||||||
|  |         for (int y = 0; y < MAP_HEIGHT; y++) { | ||||||
|  |             const coordinate location = {x, y}; | ||||||
|  |             if (grid_fetch(GRID, location) == CELL_EMPTY) { | ||||||
|  |                 empty_spots[available_spots] = location; | ||||||
|  |                 available_spots++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const coordinate food_location = empty_spots[modulo(rand(), available_spots)]; | ||||||
|  |  | ||||||
|  |     grid_put(GRID, CELL_FOOD, food_location); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Setup the game(map) | ||||||
|  |  * | ||||||
|  |  * Output: | ||||||
|  |  * A pointer to the game grid. | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * Seed random with the current time. | ||||||
|  |  * (Re)set the global variables. | ||||||
|  |  * initialize the mutex | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | static void initialize(void) { | ||||||
|  |     // Seed random. | ||||||
|  |     srand(time(NULL)); | ||||||
|  |  | ||||||
|  |     // Create the grid. | ||||||
|  |     create_grid(); | ||||||
|  |     if (GRID == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Set globals. | ||||||
|  |     CURRENT_DIRECTION = DIRECTION_DOWN; | ||||||
|  |     PREVIOUS_DIRECTION = DIRECTION_DOWN; | ||||||
|  |     SNAKE_HEAD = (coordinate){.x = grid_width(GRID) / 2, .y = grid_height(GRID) / 2}; | ||||||
|  |     SNAKE_TAIL = SNAKE_HEAD; | ||||||
|  |     RENDER_AT = (coordinate){.x = OFFSET_X, .y = OFFSET_Y}; | ||||||
|  |     MESSAGE_LOCATION = (coordinate){.x = RENDER_AT.x, .y = RENDER_AT.y + grid_height(GRID) + 2}; | ||||||
|  |  | ||||||
|  |     // Create the first body part and spawn the first piece of food. | ||||||
|  |     grid_put(GRID, get_body_part(CURRENT_DIRECTION), SNAKE_HEAD); | ||||||
|  |     generate_food(); | ||||||
|  |  | ||||||
|  |     pthread_mutex_init(&SNAKE_MUTEX, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Checks what happens when the snake moves over a given char. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * c: The char to check. | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * The snake will move forward: SNAKE_MOVE | ||||||
|  |  * The snake will eat an apple: SNAKE_EAT | ||||||
|  |  * The snake will die:          SNAKE_DIE | ||||||
|  |  */ | ||||||
|  | static snake_action collision_check(const char c) { | ||||||
|  |     if (c == CELL_EMPTY) { | ||||||
|  |         return SNAKE_MOVE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (c == CELL_FOOD) { | ||||||
|  |         return SNAKE_EAT; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return SNAKE_DIE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Move the snake to a given location | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * new_location: The location the snake should move to. | ||||||
|  |  * | ||||||
|  |  * Side effects: | ||||||
|  |  * In case nothing is encountered: The snake moves to the new location. | ||||||
|  |  * In case an obstacle is encountered (wall or part of the snake): The snake dies. | ||||||
|  |  * In case a piece of food is encountered: The snake eats the food and grows by 1. | ||||||
|  |  * | ||||||
|  |  * Note: | ||||||
|  |  * Moving to a location the snake can't reach is undefined behaviour. | ||||||
|  |  */ | ||||||
|  | static void update_snake(const coordinate new_location) { | ||||||
|  |     const snake_action action = collision_check(grid_fetch(GRID, new_location)); | ||||||
|  |  | ||||||
|  |     if (action == SNAKE_DIE) { | ||||||
|  |         grid_put_state(GRID, STATE_VERLOREN); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (action == SNAKE_MOVE) { | ||||||
|  |         coordinate new_tail = SNAKE_TAIL; | ||||||
|  |  | ||||||
|  |         switch (get_body_part_direction(grid_fetch(GRID, SNAKE_TAIL))) { | ||||||
|  |             case DIRECTION_UP: | ||||||
|  |                 new_tail.y--; | ||||||
|  |                 break; | ||||||
|  |             case DIRECTION_RIGHT: | ||||||
|  |                 new_tail.x++; | ||||||
|  |                 break; | ||||||
|  |             case DIRECTION_DOWN: | ||||||
|  |                 new_tail.y++; | ||||||
|  |                 break; | ||||||
|  |             case DIRECTION_LEFT: | ||||||
|  |                 new_tail.x--; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         grid_put(GRID, CELL_EMPTY, SNAKE_TAIL); | ||||||
|  |         SNAKE_TAIL = new_tail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // New head placed after tail moves. It can occupy the empty space created by the tail moving. | ||||||
|  |     grid_put(GRID, get_body_part(CURRENT_DIRECTION), new_location); | ||||||
|  |     SNAKE_HEAD = new_location; | ||||||
|  |     PREVIOUS_DIRECTION = CURRENT_DIRECTION; | ||||||
|  |  | ||||||
|  |     if (action == SNAKE_EAT) { | ||||||
|  |         generate_food(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Handle snake movement. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * NULL, this signature is so it can be run as a thread. | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * NULL when finished | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * While the game is running, it moves the snake forward every 0.25 seconds and updates the game | ||||||
|  |  * state accordingly. | ||||||
|  |  * | ||||||
|  |  * In case an obstacle is encountered (wall or part of the snake): It dies. | ||||||
|  |  * In case a piece of food is encountered: It eats the apple and grows by 1. | ||||||
|  |  */ | ||||||
|  | static void *snake_move(void *arg) { | ||||||
|  |     struct timespec timer; | ||||||
|  |     timer.tv_sec = 0; | ||||||
|  |     timer.tv_nsec = 250000000L; // Snake moves every 0.25 seconds. | ||||||
|  |  | ||||||
|  |     while (grid_fetch_state(GRID) == STATE_AAN_HET_SPELEN) { | ||||||
|  |         nanosleep(&timer, NULL); | ||||||
|  |         pthread_mutex_lock(&SNAKE_MUTEX); | ||||||
|  |         coordinate new_location = SNAKE_HEAD; | ||||||
|  |         switch (CURRENT_DIRECTION) { | ||||||
|  |             case DIRECTION_UP: | ||||||
|  |                 new_location.y--; | ||||||
|  |                 break; | ||||||
|  |             case DIRECTION_RIGHT: | ||||||
|  |                 new_location.x++; | ||||||
|  |                 break; | ||||||
|  |             case DIRECTION_DOWN: | ||||||
|  |                 new_location.y++; | ||||||
|  |                 break; | ||||||
|  |             case DIRECTION_LEFT: | ||||||
|  |                 new_location.x--; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         update_snake(new_location); | ||||||
|  |         show_grid_on_offset(GRID, RENDER_AT); | ||||||
|  |         pthread_mutex_unlock(&SNAKE_MUTEX); | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Turn the snake in the given direction. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * direction: The direction the snake should turn to. | ||||||
|  |  * | ||||||
|  |  * Side effects: | ||||||
|  |  * If the snake is able to turn in the given direction: | ||||||
|  |  *          The snake's direction gets updated with the new value. | ||||||
|  |  * If the snake is unable to turn in the given direction: | ||||||
|  |  *          The snake's direction remains unchanged. | ||||||
|  |  */ | ||||||
|  | static void turn_snake(const direction dir) { | ||||||
|  |     // If the snake has a length of 1, it is able to turn around on the spot. | ||||||
|  |     if ((direction)modulo((int)dir + 2, DIRECTION_COUNT) == PREVIOUS_DIRECTION | ||||||
|  |         && !same_coordinate(SNAKE_HEAD, SNAKE_TAIL)) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     grid_put(GRID, get_body_part(dir), SNAKE_HEAD); | ||||||
|  |     CURRENT_DIRECTION = dir; | ||||||
|  |     show_grid_on_offset(GRID, RENDER_AT); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Handle user input. | ||||||
|  |  * | ||||||
|  |  * Input: | ||||||
|  |  * NULL, this signature is so it can be run as a thread. | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * NULL when finished | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * While the game is running, it constantly updates the direction the snake is pointing to | ||||||
|  |  * based on user input. | ||||||
|  |  * | ||||||
|  |  * In case ESCAPE or BACKSPACE is pressed it quits the game. | ||||||
|  |  */ | ||||||
|  | static void *user_input(void *arg) { | ||||||
|  |     while (grid_fetch_state(GRID) == STATE_AAN_HET_SPELEN) { | ||||||
|  |         timeout(1); | ||||||
|  |         const int c = getch(); | ||||||
|  |         pthread_mutex_lock(&SNAKE_MUTEX); | ||||||
|  |         switch (c) { | ||||||
|  |             case KEY_UP: // fallthrough | ||||||
|  |             case 'w': | ||||||
|  |             case 'W': | ||||||
|  |                 turn_snake(DIRECTION_UP); | ||||||
|  |                 break; | ||||||
|  |             case KEY_DOWN: // fallthrough | ||||||
|  |             case 's': | ||||||
|  |             case 'S': | ||||||
|  |                 turn_snake(DIRECTION_DOWN); | ||||||
|  |                 break; | ||||||
|  |             case KEY_LEFT: // fallthrough | ||||||
|  |             case 'a': | ||||||
|  |             case 'A': | ||||||
|  |                 turn_snake(DIRECTION_LEFT); | ||||||
|  |                 break; | ||||||
|  |             case KEY_RIGHT: // fallthrough | ||||||
|  |             case 'd': | ||||||
|  |             case 'D': | ||||||
|  |                 turn_snake(DIRECTION_RIGHT); | ||||||
|  |                 break; | ||||||
|  |             case KEY_BACKSPACE: | ||||||
|  |             case KEY_ESCAPE: | ||||||
|  |                 grid_put_state(GRID, STATE_QUIT); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |         pthread_mutex_unlock(&SNAKE_MUTEX); | ||||||
|  |     } | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Waits for the user to press their SPACEBAR before starting the game. | ||||||
|  |  * | ||||||
|  |  * Side Effects: | ||||||
|  |  * If the user presses backspace or escape, the whole game quits. | ||||||
|  |  */ | ||||||
|  | static void wait_for_start(void) { | ||||||
|  |     const char start_message[] = "Press SPACEBAR to start playing."; | ||||||
|  |     const char empty_message[] = "                                "; | ||||||
|  |     mvaddstr(MESSAGE_LOCATION.y, MESSAGE_LOCATION.x, start_message); | ||||||
|  |  | ||||||
|  |     grid_put_state(GRID, STATE_AAN_HET_SPELEN); | ||||||
|  |  | ||||||
|  |     for (int c = getch(); c != ' '; c = getch()) { | ||||||
|  |         switch (c) { | ||||||
|  |             case KEY_BACKSPACE: | ||||||
|  |             case KEY_ESCAPE: | ||||||
|  |                 grid_put_state(GRID, STATE_QUIT); | ||||||
|  |                 mvaddstr(MESSAGE_LOCATION.y, MESSAGE_LOCATION.x, empty_message); | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Cleanup the start playing message. | ||||||
|  |     mvaddstr(MESSAGE_LOCATION.y, MESSAGE_LOCATION.x, empty_message); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Cleanup the snake memory | ||||||
|  |  * | ||||||
|  |  * Side effects: | ||||||
|  |  * Frees all the memory used by the snake | ||||||
|  |  */ | ||||||
|  | static void snake_cleanup(void) { | ||||||
|  |     pthread_mutex_destroy(&SNAKE_MUTEX); | ||||||
|  |     grid_cleanup(GRID); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void snake(void) { | ||||||
|  |     initialize(); | ||||||
|  |     if (GRID == NULL) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Show game. | ||||||
|  |     erase(); | ||||||
|  |     show_grid_on_offset(GRID, RENDER_AT); | ||||||
|  |  | ||||||
|  |     wait_for_start(); | ||||||
|  |  | ||||||
|  |     if (grid_fetch_state(GRID) == STATE_AAN_HET_SPELEN) { | ||||||
|  |         // Create and start necessary threads. | ||||||
|  |         pthread_t input_thread; | ||||||
|  |         pthread_t game_tick_thread; | ||||||
|  |  | ||||||
|  |         pthread_create(&input_thread, NULL, user_input, NULL); | ||||||
|  |         pthread_create(&game_tick_thread, NULL, snake_move, NULL); | ||||||
|  |  | ||||||
|  |         // Wait until the gamestate is no longer STATE_AAN_HET_SPELEN | ||||||
|  |         pthread_join(game_tick_thread, NULL); | ||||||
|  |         pthread_join(input_thread, NULL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     game_exit_message(GRID, MESSAGE_LOCATION); | ||||||
|  |  | ||||||
|  |     snake_cleanup(); | ||||||
|  | } | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| /*
 | /*
 | ||||||
|  * Created by snapshot112 on 10/15/25. |  * Created by snapshot112 on 15/10/2025 | ||||||
|  * |  * | ||||||
|  * A game of maze runner configured to run on the grid game engine. |  * A game of maze runner build on the grid game engine. | ||||||
|  * |  * | ||||||
|  * Please make sure to include and initialize the game engine before calling snake(); |  * Please make sure to include and initialize the game engine before calling snake(); | ||||||
|  */ |  */ | ||||||
| @@ -10,7 +10,7 @@ | |||||||
| #define MINIGAME_MENU_SNAKE_H | #define MINIGAME_MENU_SNAKE_H | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * A game of snake configured to run on the grid game engine. |  * A game of snake build on the grid game engine. | ||||||
|  * |  * | ||||||
|  * Please make sure to include and initialize the game engine before calling snake(); |  * Please make sure to include and initialize the game engine before calling snake(); | ||||||
|  * |  * | ||||||
| @@ -19,7 +19,7 @@ | |||||||
|  * |  * | ||||||
|  * Controls: |  * Controls: | ||||||
|  * Use WSAD or arrow keys to redirect the snake. |  * Use WSAD or arrow keys to redirect the snake. | ||||||
|  * Use BACKSPACE to exit the game early. |  * Use BACKSPACE or ESCAPE to exit the game early. | ||||||
|  */ |  */ | ||||||
| void snake(void); | void snake(void); | ||||||
| 
 | 
 | ||||||
							
								
								
									
										34
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | /* | ||||||
|  |  * Created by snapshot112 on 15/10/2025 | ||||||
|  |  * | ||||||
|  |  * Naam: Jeroen Boxhoorn | ||||||
|  |  * UvAnetID: 16333969 | ||||||
|  |  * Studie: BSC Informatica | ||||||
|  |  * | ||||||
|  |  * A minigame menu that lets you play games on the grid game engine. | ||||||
|  |  * | ||||||
|  |  * Currently the following games are included: | ||||||
|  |  * - maze runner | ||||||
|  |  * - snake | ||||||
|  |  * - minesweeper | ||||||
|  |  * | ||||||
|  |  * A user manual can be found in the assets or by selected it in the menu using ENTER or 'f'. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "engine/engine/grid_game_engine.h" | ||||||
|  | #include "games/minigame-menu/minigame_menu.h" | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Play minigame menu. | ||||||
|  |  * | ||||||
|  |  * Side effect: | ||||||
|  |  * Minigame menu starts. | ||||||
|  |  */ | ||||||
|  | int main(void) { | ||||||
|  |     init_engine(); | ||||||
|  |  | ||||||
|  |     // Speel het spel. | ||||||
|  |     minigame_menu(); | ||||||
|  |  | ||||||
|  |     cleanup_engine(); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user