manual??? and refactoring

This commit is contained in:
2025-10-17 21:08:03 +02:00
parent a2d4290076
commit 103f85d07e
15 changed files with 211 additions and 52 deletions

View File

@@ -1,6 +1,6 @@
CC = gcc CC = gcc
CFLAGS = -std=c11 -Wextra -Wpedantic -g3 -fsanitize=address CFLAGS = -std=c11 -Wextra -Wpedantic -g3 -fsanitize=address
LDFLAGS = -lncursesw -fsanitize=address LDFLAGS = -lncurses -fsanitize=address
SRC = $(filter-out voorbeeld.c,$(wildcard *.c)) SRC = $(filter-out voorbeeld.c,$(wildcard *.c))
HEADERS = $(wildcard *.h) HEADERS = $(wildcard *.h)

75
assets/handleiding.txt Normal file
View File

@@ -0,0 +1,75 @@
*--------------------------------------------*
| |
| !!! HOWTO MINIGAME !!! |
| |
| *________________* |
| |--- MANUAL ---| |
| *------------------------------------* |
| | | |
| | Exit: | |
| | Escape, backspace | |
| | | |
| *------------------------------------* |
| |
| *________________* |
| |---- MENU ----| |
| *------------------------------------* |
| | | |
| | Move down: | |
| | 's', arrow_down | |
| | | |
| | Move up: | |
| | 'w', arrow_up | |
| | | |
| | Select: | |
| | 'f', enter, space bar | |
| | | |
| | Exit: | |
| | Escape, backspace | |
| | | |
| *------------------------------------* |
| |
| *-----------------* |
| |- MAZE RUNNER -| |
| *------------------------------------* |
| | | |
| | Move up: | |
| | 'w', arrow_up | |
| | | |
| | Move down: | |
| | 's', arrow_down | |
| | | |
| | Move right: | |
| | 'd', arrow_right | |
| | | |
| | Move left: | |
| | 'a', arrow_left | |
| | | |
| | Exit: | |
| | Escape, backspace | |
| | | |
| *------------------------------------* |
| |
| *-----------------* |
| |---- SNAKE ----| |
| *------------------------------------* |
| | | |
| | Turn up: | |
| | 'w', arrow_up | |
| | | |
| | Turn down: | |
| | 's', arrow_down | |
| | | |
| | Turn right: | |
| | 'd', arrow_right | |
| | | |
| | Turn left: | |
| | 'a', arrow_left | |
| | | |
| | Exit: | |
| | Escape, backspace | |
| | | |
| *------------------------------------* |
*--------------------------------------------*
1234567890123456789012345678901234567890123456
10 20 30 40 |

Binary file not shown.

View File

@@ -12,7 +12,7 @@
#include "rooster.h" #include "rooster.h"
int same_coordinate(coordinate a, coordinate b) { int same_coordinate(const coordinate a, const coordinate b) {
return a.x == b.x && a.y == b.y; return a.x == b.x && a.y == b.y;
} }
@@ -35,12 +35,12 @@ void show_grid_on_offset(const rooster *gp, const int starting_x, const int star
refresh(); refresh();
} }
void show_grid(const rooster *rp) { void show_grid(const rooster *gp) {
show_grid_on_offset(rp, 0, 0); show_grid_on_offset(gp, 0, 0);
} }
void update_grid(rooster *rp, char c, int x, int y) { void update_grid(rooster *gp, const char c, const int x, const int y) {
if (rooster_plaats(rp, x, y, c) == 1) { if (rooster_plaats(gp, x, y, c) == 1) {
mvaddch(y, x, c); mvaddch(y, x, c);
} }
} }
@@ -51,9 +51,9 @@ void update_grid(rooster *rp, char c, int x, int y) {
* Side Effect: * Side Effect:
* Clears the console and prints the victory message. * Clears the console and prints the victory message.
*/ */
static void display_victory(void) { static void display_victory(const coordinate location) {
erase(); erase();
mvprintw(2,5, "YOU WON!!!!!"); mvprintw(location.y, location.x, "YOU WON!!!!!");
refresh(); refresh();
} }
@@ -63,9 +63,9 @@ static void display_victory(void) {
* Side Effect: * Side Effect:
* Clears the console and prints the GAME OVER message. * Clears the console and prints the GAME OVER message.
*/ */
static void display_loss(void) { static void display_loss(const coordinate location) {
erase(); erase();
mvprintw(2,5, "GAME OVER"); mvprintw(location.y, location.x, "GAME OVER");
refresh(); refresh();
} }
@@ -75,9 +75,9 @@ static void display_loss(void) {
* Side Effect: * Side Effect:
* Clears the console and prints the quit message. * Clears the console and prints the quit message.
*/ */
static void display_quit(void) { static void display_quit(const coordinate location) {
erase(); erase();
mvprintw(2,5, "You quit the game"); mvprintw(location.y, location.x, "You quit the game");
refresh(); refresh();
} }
@@ -87,42 +87,46 @@ static void display_quit(void) {
* Side Effect: * Side Effect:
* Clears the console and prints the hacker man message. * Clears the console and prints the hacker man message.
*/ */
static void display_hackerman(void) { static void display_hackerman(const coordinate location) {
erase(); erase();
mvprintw(2,5, "The hacker man strikes again..."); mvprintw(location.y, location.x, "The hacker man strikes again...");
refresh(); refresh();
} }
void graceful_exit(void) { void graceful_exit(const coordinate message_location) {
mvprintw(25, 5, "Press 'q' to exit."); mvprintw(message_location.y, message_location.x, "Press ENTER or SPACE to exit.");
while (1) { while (1) {
switch (getch()) { switch (getch()) {
case 'q': case KEY_ENTER:
case 'Q': case '\n':
case ' ':
return; return;
} }
} }
} }
void game_exit_screen(rooster *gp) { void game_exit_screen(const rooster *gp, coordinate location) {
toestand current_state = rooster_vraag_toestand(gp); const toestand current_state = rooster_vraag_toestand(gp);
switch (current_state) { switch (current_state) {
case STATE_GEWONNEN: case STATE_GEWONNEN:
display_victory(); display_victory(location);
break; break;
case STATE_VERLOREN: case STATE_VERLOREN:
display_loss(); display_loss(location);
break; break;
case STATE_QUIT: case STATE_QUIT:
display_quit(); display_quit(location);
break; break;
default: default:
display_hackerman(); display_hackerman(location);
} }
graceful_exit();
location.y += 2;
graceful_exit(location);
} }
static void init_ncurses() { static void init_ncurses() {
ESCDELAY = 0;
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
initscr(); initscr();
cbreak(); // So you can cancel the game with ctrl + c. cbreak(); // So you can cancel the game with ctrl + c.

View File

@@ -2,7 +2,7 @@
* Created by snapshot112 on 10/15/25. * Created by snapshot112 on 10/15/25.
* *
* A game engine that uses the can run and display games in rectangular grids. * A game engine that uses the can run and display games in rectangular grids.
* The graphics are made using ncursesw. * The graphics are made using ncurses.
* *
* Please make sure to initialize the game engine before running any games. * Please make sure to initialize the game engine before running any games.
*/ */
@@ -11,6 +11,8 @@
#define MINIGAME_MENU_GRID_GAME_ENGINE_H #define MINIGAME_MENU_GRID_GAME_ENGINE_H
#include "rooster.h" #include "rooster.h"
#define KEY_ESCAPE 27
typedef struct { typedef struct {
int x; int x;
int y; int y;
@@ -92,25 +94,29 @@ void update_grid(rooster *gp, char c, int x, int y);
* Display the ending screen that matches the end state of the grid. * Display the ending screen that matches the end state of the grid.
* *
* Input: * Input:
* gp: A pointer to the grid. * gp: A pointer to the grid.
* coordinate: The location to show the ending screen.
* *
* Side Effects: * Side Effects:
* The end of game screen gets displayed with a graceful exit. * The end of game screen gets displayed with a graceful exit.
*/ */
void game_exit_screen(rooster *gp); void game_exit_screen(const rooster *gp, coordinate location);
/* /*
* Waits for you to press 'q' before exiting the game. * Waits for you to press ENTER or SPACE before exiting the game.
* *
* Side effect: Prints "Press 'q' to exit." game to the console. * Input:
* coordinate: The location to show the message.
*
* Side effect: Prints "Press ENTER or SPACE to exit." game to the console.
*/ */
void graceful_exit(void); void graceful_exit(coordinate message_location);
/* /*
* Initialize ncurses. * Initialize ncurses.
* *
* This enables cbreak, noecho, hides the cursor and enables the extra keys. * This enables cbreak, noecho, hides the cursor and enables the extra keys.
* This also creates the color pairs needed for game_colors, * This also creates the color pairs needed for game_colors and sets ESCDELAY to 0.
*/ */
void init_engine(void); void init_engine(void);

33
manual.c Normal file
View File

@@ -0,0 +1,33 @@
//
// Created by snapshot112 on 10/17/25.
//
#include "manual.h"
#include <ncurses.h>
#include "rooster.h"
void manual(const coordinate display_location) {
erase();
FILE *fp = fopen("assets/handleiding.txt", "r");
if (fp == NULL) {
return;
}
rooster *grid = grid_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.x, display_location.y);
rooster_klaar(grid);
int ch = getch();
while (ch != KEY_ESCAPE && ch != KEY_BACKSPACE && ch != ' ') {
ch = getch();
}
}

27
manual.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* Created by snapshot112 on 10/15/25.
*
* Display the manual for the minigames
*/
#ifndef MINIGAME_MENU_MANUAL_H
#define MINIGAME_MENU_MANUAL_H
#include "grid_game_engine.h"
/*
* A 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 ENTER to exit the manual.
*/
void manual(coordinate display_location);
#endif //MINIGAME_MENU_MANUAL_H

View File

@@ -105,7 +105,9 @@ static void speel_maze(rooster *rp) {
case 'D': case 'D':
maze_runner_beweeg(rp, 1, 0); maze_runner_beweeg(rp, 1, 0);
break; break;
case 'p':
case KEY_BACKSPACE: case KEY_BACKSPACE:
case KEY_ESCAPE:
rooster_zet_toestand(rp, STATE_QUIT); rooster_zet_toestand(rp, STATE_QUIT);
break; break;
} }
@@ -126,6 +128,6 @@ void maze_runner(void) {
} }
// Exit game. // Exit game.
game_exit_screen(rp); game_exit_screen(rp, (coordinate){0, 0});
rooster_klaar(rp); rooster_klaar(rp);
} }

View File

@@ -11,6 +11,6 @@
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();
} }

View File

@@ -8,14 +8,23 @@
#include <stdlib.h> #include <stdlib.h>
#include "grid_game_engine.h" #include "grid_game_engine.h"
#include "manual.h"
#include "maze_runner.h" #include "maze_runner.h"
#include "minesweeper.h" #include "minesweeper.h"
#include "rooster.h" #include "rooster.h"
#include "snake.h" #include "snake.h"
#define AMOUNT_OF_MENU_OPTIONS 4 #define AMOUNT_OF_MENU_OPTIONS 5
static game SELECTED_GAME = GAME_MAZE_RUNNER; typedef enum {
GAME_HELP = 0,
GAME_MAZE_RUNNER = 1,
GAME_SNAKE = 2,
GAME_MINESWEEPER = 3,
GAME_QUIT = 4,
} game;
static game SELECTED_GAME = GAME_HELP;
static int OFFSET_Y = 5; static int OFFSET_Y = 5;
static int OFFSET_X = 5; static int OFFSET_X = 5;
@@ -28,6 +37,9 @@ static int OFFSET_X = 5;
*/ */
static void launch_game(const game game) { static void launch_game(const game game) {
switch (game) { switch (game) {
case GAME_HELP:
manual((coordinate){0,0});
break;
case GAME_MAZE_RUNNER: case GAME_MAZE_RUNNER:
maze_runner(); maze_runner();
break; break;
@@ -55,6 +67,7 @@ static void launch_game(const game game) {
*/ */
static void menu_highlight(const rooster *menu) { static void menu_highlight(const rooster *menu) {
switch (SELECTED_GAME) { switch (SELECTED_GAME) {
case GAME_HELP:
case GAME_MAZE_RUNNER: case GAME_MAZE_RUNNER:
case GAME_SNAKE: case GAME_SNAKE:
case GAME_MINESWEEPER: case GAME_MINESWEEPER:
@@ -82,7 +95,7 @@ static void menu_highlight(const rooster *menu) {
* Displays the menu * Displays the menu
*/ */
static void show_menu(const rooster *menu) { static void show_menu(const rooster *menu) {
clear(); erase();
show_grid_on_offset(menu, OFFSET_X, OFFSET_Y); show_grid_on_offset(menu, OFFSET_X, OFFSET_Y);
menu_highlight(menu); menu_highlight(menu);
refresh(); refresh();
@@ -118,7 +131,7 @@ static void menu_move(const int offset) {
* 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':
@@ -134,12 +147,15 @@ static int navigate_menu(rooster *menu) {
case '\n': 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(SELECTED_GAME); launch_game(SELECTED_GAME);
break; break;
case 'p':
case KEY_BACKSPACE: case KEY_BACKSPACE:
case KEY_ESCAPE:
return 1; return 1;
} }
return 0; return 0;
@@ -152,7 +168,8 @@ static int navigate_menu(rooster *menu) {
* A pointer to the menu grid. * A pointer to the menu grid.
*/ */
static rooster *initialize_menu(void) { static rooster *initialize_menu(void) {
char menu[] = "Maze Runner\n" char menu[] = "How to play\n"
"Maze Runner\n"
" Snake \n" " Snake \n"
"Minesweeper\n" "Minesweeper\n"
" Leave \n"; " Leave \n";
@@ -165,7 +182,7 @@ void minigame_menu(void) {
while (true) { while (true) {
show_menu(menu); show_menu(menu);
if (navigate_menu(menu) == 1) { if (navigate_menu() == 1) {
break; break;
} }
} }

View File

@@ -9,13 +9,6 @@
#ifndef MINIGAME_MENU_MINIGAME_MENU_H #ifndef MINIGAME_MENU_MINIGAME_MENU_H
#define 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. * A minigame menu for games configured to run on the grid game engine.
* *

View File

@@ -1,6 +1,5 @@
#include "rooster.h" #include "rooster.h"
#include <ncurses.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@@ -89,7 +88,7 @@ static int get_grid_sizes(FILE *fh, rooster *rost) {
return 0; return 0;
} }
rost->height = (int)ftell(fh) / (int)sizeof(char) / rost->width; rost->height = (int)ftell(fh) / (int)sizeof(char) / (rost->width + 1);
fseek(fh, 0, SEEK_SET); fseek(fh, 0, SEEK_SET);
return 1; return 1;

View File

@@ -244,7 +244,7 @@ static void update_snake(coordinate new_head, snake_action action) {
static void *snake_move(void *arg) { static void *snake_move(void *arg) {
struct timespec timer; struct timespec timer;
timer.tv_sec = 0; timer.tv_sec = 0;
timer.tv_nsec = 250000000L; timer.tv_nsec = 250000000L; // Snake moves every 0.25 seconds.
while (rooster_vraag_toestand(GRID) == STATE_AAN_HET_SPELEN) { while (rooster_vraag_toestand(GRID) == STATE_AAN_HET_SPELEN) {
nanosleep(&timer, NULL); nanosleep(&timer, NULL);
@@ -311,6 +311,7 @@ static void *play_snake(void *arg) {
turn_snake(DIRECTION_RIGHT); turn_snake(DIRECTION_RIGHT);
break; break;
case KEY_BACKSPACE: case KEY_BACKSPACE:
case KEY_ESCAPE:
rooster_zet_toestand(GRID, STATE_QUIT); rooster_zet_toestand(GRID, STATE_QUIT);
break; break;
} }
@@ -352,5 +353,5 @@ void snake(void) {
pthread_mutex_destroy(&MUTEX); pthread_mutex_destroy(&MUTEX);
rooster_klaar(GRID); rooster_klaar(GRID);
graceful_exit(); graceful_exit(MESSAGE_LOCATION);
} }

BIN
spel

Binary file not shown.

4
spel.c
View File

@@ -12,12 +12,14 @@
*/ */
#include "grid_game_engine.h" #include "grid_game_engine.h"
#include "manual.h"
#include "minigame_menu.h" #include "minigame_menu.h"
int main(void) { int main(void) {
init_engine(); init_engine();
// 5. Speel het spel. // Speel het spel.
// manual((coordinate){0,3});
minigame_menu(); minigame_menu();
cleanup_engine(); cleanup_engine();