This commit is contained in:
2025-10-14 13:58:22 +02:00
parent 9b1a8fcea9
commit 8f406d9272
5 changed files with 322 additions and 130 deletions

BIN
deel2.tar.gz Normal file

Binary file not shown.

View File

@@ -5,6 +5,8 @@
#include <stdio.h> #include <stdio.h>
// TODO: End the eternal NULL checks.
/* /*
* The rooster type this program is build around. * The rooster type this program is build around.
*/ */
@@ -16,7 +18,40 @@ typedef struct rooster_data {
} rooster; } rooster;
rooster *rooster_maak(char* input); 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) {
perror("rooster_maak");
exit(1);
}
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) {
perror("rooster_maak");
exit(1);
};
}
const int grid_size = (width + 1) * height + 1;
rooster *rp = malloc(sizeof(rooster));
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 * Sets a grids width and height
@@ -71,7 +106,7 @@ rooster *rooster_lees(FILE *fh) {
NULL, NULL,
0, 0,
0, 0,
BEGIN STATE_BEGIN
}; };
// Sets the width and height of the rooster. // Sets the width and height of the rooster.
@@ -129,23 +164,26 @@ toestand rooster_vraag_toestand(const rooster *rp) {
if (rp != NULL) { if (rp != NULL) {
return rp->state; return rp->state;
} }
return VERLOREN; return STATE_VERLOREN;
} }
void rooster_zet_toestand(rooster *rp, toestand t) { void rooster_zet_toestand(rooster *rp, toestand t) {
if (rp != NULL) { if (rp != NULL) {
switch (t) { switch (t) {
case BEGIN: case STATE_BEGIN:
rp->state = BEGIN; rp->state = STATE_BEGIN;
break; break;
case AAN_HET_SPELEN: case STATE_AAN_HET_SPELEN:
rp->state = AAN_HET_SPELEN; rp->state = STATE_AAN_HET_SPELEN;
break; break;
case GEWONNEN: case STATE_GEWONNEN:
rp->state = GEWONNEN; rp->state = STATE_GEWONNEN;
break; break;
case VERLOREN: case STATE_VERLOREN:
rp->state = VERLOREN; rp->state = STATE_VERLOREN;
break;
case STATE_QUIT:
rp->state = STATE_QUIT;
break; break;
} }
} }

View File

@@ -18,10 +18,11 @@ struct rooster_data;
typedef struct rooster_data rooster; typedef struct rooster_data rooster;
typedef enum { typedef enum {
BEGIN, STATE_BEGIN,
AAN_HET_SPELEN, STATE_AAN_HET_SPELEN,
GEWONNEN, STATE_GEWONNEN,
VERLOREN STATE_VERLOREN,
STATE_QUIT
} toestand; } toestand;
/* Maak een rooster op basis van de data in de gegeven stream. /* Maak een rooster op basis van de data in de gegeven stream.
@@ -53,7 +54,7 @@ rooster *rooster_lees(FILE *fh);
* NULL teruggegeven. (In dat geval blijft geen gereserveerd geheugen * NULL teruggegeven. (In dat geval blijft geen gereserveerd geheugen
* achter.) * achter.)
*/ */
rooster *rooster_maak(char* input); rooster *rooster_maak(const char* input);
/* /*
* Haal een rij uit het rooster op. * Haal een rij uit het rooster op.

BIN
spel

Binary file not shown.

381
spel.c
View File

@@ -21,15 +21,24 @@
*/ */
#include <assert.h> #include <assert.h>
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <ncurses.h> #include <ncurses.h>
#include <wchar.h> #include <wchar.h>
#include <locale.h> #include <locale.h>
#include <string.h>
#include "rooster.h" #include "rooster.h"
typedef enum {
GAME_QUIT,
GAME_MAZE_RUNNER,
GAME_SNAKE,
GAME_MINESWEEPER
} game;
typedef struct { typedef struct {
char name[100]; char name[100];
rooster *game_map; rooster *game_map;
@@ -66,6 +75,115 @@ void update_grid(rooster *rp, char c, int x, int y) {
} }
} }
void game_error(void) {
endwin();
exit(EXIT_FAILURE);
}
void quit_game(rooster *menu) {
if (menu != NULL) {
rooster_klaar(menu);
}
endwin();
exit(EXIT_SUCCESS);
}
/*
* Toont het victory screen.
*
* Side Effect:
* De victory message wordt op een schone console geprint.
*/
void display_victory(void) {
clear();
mvprintw(2,5, "YOU WON!!!!!");
refresh();
}
/*
* Toont het loss screen.
*
* Side Effect:
* De loss message wordt op een schone console geprint.
*/
void display_loss(void) {
clear();
mvprintw(2,5, "RIP, YOU DIED...");
refresh();
}
/*
* Toont het quit screen.
*
* Side Effect:
* De quit message wordt op een schone console geprint.
*/
void display_quit(void) {
clear();
mvprintw(2,5, "You quit the game");
refresh();
}
/*
* Toont het hackerman screen.
*
* Side Effect:
* De hackerman message wordt op een schone console geprint.
*/
void display_hackerman(void) {
clear();
mvprintw(2,5, "The hacker man strikes again...");
refresh();
}
/*
* Bepaalt afhankelijk van de eindtoestand van het rooster
* welk afsluitscherm er getoond moet worden en toont dan dat rooster.
*
* Input: Het rooster om de toestand uit af te lezen.
*
* Side Effects:
* Het end-of-game scherm wordt op een blanke console geprint.
*/
void game_exit_screen(rooster *rp) {
toestand current_state = rooster_vraag_toestand(rp);
switch (current_state) {
case STATE_GEWONNEN:
display_victory();
return;
case STATE_VERLOREN:
display_loss();
return;
case GAME_QUIT:
display_quit();
return;
}
display_hackerman();
}
/*
* Waits for the user to press an exit key 'q' before continuing.
*/
void graceful_exit(void) {
mvprintw(5, 0, "Press 'q' to exit the game.");
while (1) {
switch (getch()) {
case 'q':
return;
}
}
}
void speel_snake(void) {
mvprintw(0,0, "Snake has not yet been created");
graceful_exit();
}
void speel_minesweeper() {
mvprintw(0,0, "Minesweeper has not yet been created");
graceful_exit();
}
/* Voert de benodigde veranderingen in het rooster door als de speler in een /* Voert de benodigde veranderingen in het rooster door als de speler in een
* bepaalde richting probeert te bewegen. * bepaalde richting probeert te bewegen.
* Input: * Input:
@@ -77,7 +195,7 @@ void update_grid(rooster *rp, char c, int x, int y) {
* Side effect: het rooster wordt aangepast op basis van de handeling van * Side effect: het rooster wordt aangepast op basis van de handeling van
* de speler. * de speler.
*/ */
void beweeg(rooster *rp, int dx, int dy) { void maze_runner_beweeg(rooster *rp, int dx, int dy) {
int playerx; int playerx;
int playery; int playery;
rooster_zoek(rp, '*', &playerx, &playery); rooster_zoek(rp, '*', &playerx, &playery);
@@ -94,7 +212,7 @@ void beweeg(rooster *rp, int dx, int dy) {
break; break;
case 'X': case 'X':
update_grid(rp, ' ', playerx, playery); update_grid(rp, ' ', playerx, playery);
rooster_zet_toestand(rp, VERLOREN); rooster_zet_toestand(rp, STATE_VERLOREN);
break; break;
case ' ': case ' ':
update_grid(rp, ' ', playerx, playery); update_grid(rp, ' ', playerx, playery);
@@ -102,7 +220,7 @@ void beweeg(rooster *rp, int dx, int dy) {
break; break;
case '$': case '$':
update_grid(rp, ' ', playerx, playery); update_grid(rp, ' ', playerx, playery);
rooster_zet_toestand(rp, GEWONNEN); rooster_zet_toestand(rp, STATE_GEWONNEN);
break; break;
} }
refresh(); refresh();
@@ -117,133 +235,44 @@ void beweeg(rooster *rp, int dx, int dy) {
* *
* Side Effects: * Side Effects:
* Met WSAD en arrow keys kun je door het doolhof heen bewegen. * Met WSAD en arrow keys kun je door het doolhof heen bewegen.
*
*/ */
void run_maze(rooster *rp) { void maze_runner(rooster *rp) {
while (rooster_vraag_toestand(rp) == AAN_HET_SPELEN) while (rooster_vraag_toestand(rp) == STATE_AAN_HET_SPELEN)
{ {
switch (getch()) { switch (getch()) {
case KEY_UP: // fallthrough case KEY_UP: // fallthrough
case 'w': case 'w':
beweeg(rp, 0, -1); maze_runner_beweeg(rp, 0, -1);
break; break;
case KEY_DOWN: // fallthrough case KEY_DOWN: // fallthrough
case 's': case 's':
beweeg(rp, 0, 1); maze_runner_beweeg(rp, 0, 1);
break; break;
case KEY_LEFT: // fallthrough case KEY_LEFT: // fallthrough
case 'a': case 'a':
beweeg(rp, -1, 0); maze_runner_beweeg(rp, -1, 0);
break; break;
case KEY_RIGHT: // fallthrough case KEY_RIGHT: // fallthrough
case 'd': case 'd':
beweeg(rp, 1, 0); maze_runner_beweeg(rp, 1, 0);
break; break;
case KEY_EXIT: case KEY_BACKSPACE:
rooster_zet_toestand(rp, VERLOREN); rooster_zet_toestand(rp, STATE_QUIT);
break; break;
} }
} }
} }
/* rooster *choose_maze(void) {
* Toont het maze victory screen. // TODO: echt opties aanbieden in plaats van hardcoded 1 maze.
* // Alternatief is om random een maze te genereren. dit is miss beter.
* Side Effect:
* De victory message wordt op een schone console geprint.
*/
void display_maze_victory() {
clear();
mvprintw(2,5, "YOU WON!!!!!");
refresh();
}
/* // 2. Open het doolhof bestand en lees het rooster.
* Toont het maze loss screen. FILE *fh = fopen("assets/voorbeeld_doolhof.txt", "r");
*
* Side Effect:
* De loss message wordt op een schone console geprint.
*/
void display_maze_loss() {
clear();
mvprintw(2,5, "RIP, YOU DIED...");
refresh();
}
/*
* Toont het maze broken screen.
*
* Side Effect:
* De hackerman message wordt op een schone console geprint.
*/
void display_hackerman() {
clear();
mvprintw(2,5, "The hacker man strikes again...");
refresh();
}
/*
* Bepaalt afhankelijk van de eindtoestand van het rooster
* welk afsluitscherm er getoond moet worden en toont dan dat rooster.
*
* Input: Het rooster om de toestand uit af te lezen.
*
* Side Effects:
* Het end-of-game scherm wordt op een blanke console geprint.
*/
void maze_exit_screen(rooster *rp) {
toestand current_state = rooster_vraag_toestand(rp);
switch (current_state) {
case GEWONNEN:
display_maze_victory();
return;
case VERLOREN:
display_maze_loss();
return;
}
display_hackerman();
}
/*
* Waits for the user to press an exit key 'q' before continuing.
*/
void graceful_exit() {
mvprintw(5, 0, "Press 'q' to exit the game.");
while (1) {
switch (getch()) {
case 'q':
return;
}
}
}
void toon_menu(rooster *rp) {
toon_rooster(rp);
rooster_zet_toestand(rp, AAN_HET_SPELEN);
run_maze(rp);
maze_exit_screen(rp);
graceful_exit();
}
/*
* Speelt het spel met een gegeven rooster tot de toestand niet langer
* AAN_HET_SPELEN is.
*/
void speel(rooster *rp) {
toon_menu(rp);
}
int main(int argc, char *argv[]) {
// 1. Controleer dat er een doolhofbestand is opgegeven op de command line.
if (argc != 2) {
fprintf(stderr, "gebruik: ./spel assets/voorbeeld_doolhof.txt\n");
return 1;
}
// 2. Open het doolhofbestand en lees het rooster.
FILE *fh = fopen(argv[1], "r");
if (fh == NULL) { if (fh == NULL) {
perror("main"); perror("loading maze");
return 1; game_error();
} }
rooster *rp = rooster_lees(fh); rooster *rp = rooster_lees(fh);
fclose(fh); fclose(fh);
@@ -251,23 +280,147 @@ int main(int argc, char *argv[]) {
// 3. Bepaal of het lezen van het rooster is gelukt. // 3. Bepaal of het lezen van het rooster is gelukt.
if (rp == NULL) { if (rp == NULL) {
fprintf(stderr, "Kan rooster niet maken.\n"); fprintf(stderr, "Kan rooster niet maken.\n");
return 1; game_error();
} }
return rp;
}
/*
* Speelt het spel met een gegeven rooster tot de toestand niet langer
* AAN_HET_SPELEN is.
*/
void speel_maze(void) {
// Voorbereiding.
rooster *rp = choose_maze();
toon_rooster(rp);
rooster_zet_toestand(rp, STATE_AAN_HET_SPELEN);
// Game zelf.
maze_runner(rp);
// Exit game.
game_exit_screen(rp);
rooster_klaar(rp);
graceful_exit();
}
void launch_game(rooster *menu, const game game) {
switch (game) {
case GAME_MAZE_RUNNER:
speel_maze();
return;
case GAME_SNAKE:
speel_snake();
return;
case GAME_MINESWEEPER:
speel_minesweeper();
return;
case GAME_QUIT:
quit_game(menu);
}
}
void menu_highlight(rooster *rp, const game target, const int offset_x, const int offset_y) {
switch (target) {
case GAME_MAZE_RUNNER: // Fallthrough
case GAME_SNAKE: // Fallthrough
case GAME_MINESWEEPER: // Fallthrough
case GAME_QUIT: // Fallthrough
// TODO: Properly highlight this shit.
mvprintw(offset_y + (int)target, offset_x, rooster_vraag_rij(rp, target));
}
}
game menu_try_move(const game selected_game, const int offset) {
switch (selected_game + offset) {
case GAME_MAZE_RUNNER:
return GAME_MAZE_RUNNER;
case GAME_SNAKE:
return GAME_SNAKE;
case GAME_MINESWEEPER:
return GAME_MINESWEEPER;
case GAME_QUIT:
return GAME_QUIT;
}
return selected_game;
}
void navigate_menu(rooster *menu, const game default_game, const int offset_x, const int offset_y) {
game selected_game = default_game;
while (true) {
switch (getch()) {
case KEY_UP: // fallthrough
case 'w':
selected_game = menu_try_move(selected_game, -1);
menu_highlight(menu, selected_game, offset_x, offset_y);
break;
case KEY_DOWN: // fallthrough
case 's':
selected_game = menu_try_move(selected_game, 1);
menu_highlight(menu, selected_game, offset_x, offset_y);
break;
case KEY_ENTER:
// select current game somehow
launch_game(menu, GAME_QUIT);
menu_highlight(menu, selected_game, offset_x, offset_y);
break;
case KEY_BACKSPACE:
launch_game(menu, GAME_QUIT);
break;
}
}
}
rooster *laad_menu(void) {
char menu[] = "Maze Runner\n"
" Snake \n"
"Minesweeper\n"
" Leave \n";
rooster *rp = rooster_maak(menu);
return rp;
}
void toon_menu(rooster *menu, const game default_game, const int offset_x, const int offset_y) {
toon_rooster_op_locatie(menu, offset_x, offset_y);
menu_highlight(menu, default_game, offset_x, offset_y);
refresh();
}
void menu(void) {
rooster *menu = laad_menu();
const game default_game = GAME_MAZE_RUNNER;
while (true) {
clear();
const int offset_x = 5;
const int offset_y = 5;
toon_menu(menu, default_game, offset_x, offset_y);
navigate_menu(menu, default_game, offset_x, offset_y);
}
}
void startup_sequence(void) {
// TODO: Nice entry screen
}
int main(void) {
// 4. Initialiseer ncurses // 4. Initialiseer ncurses
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
initscr(); initscr();
cbreak(); // zodat je kunt onderbreken met Ctrl+C cbreak(); // zodat je kunt onderbreken met Ctrl+C
keypad(stdscr, TRUE); // luister ook naar extra toetsen zoals pijltjes keypad(stdscr, TRUE); // luister ook naar extra toetsen zoals pijltjes
noecho(); // druk niet de letters af die je intypt noecho(); // druk niet de letters af die je intypt
curs_set(0); // hides the cursor curs_set(0); // hides the cursor// Don't mask any mouse events
// 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
// 5. Speel het spel. // 5. Speel het spel.
speel(rp); startup_sequence();
menu();
// 6. Sluit af. // 6. Sluit af.
rooster_klaar(rp); quit_game(NULL);
endwin();
return 0;
} }