aboutsummaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/commands.c61
-rw-r--r--src/game/commands.h24
-rw-r--r--src/game/entry.c152
-rw-r--r--src/game/entry.h9
-rw-r--r--src/game/game.c109
-rw-r--r--src/game/game.h67
-rw-r--r--src/game/operations.c144
-rw-r--r--src/game/operations.h44
8 files changed, 610 insertions, 0 deletions
diff --git a/src/game/commands.c b/src/game/commands.c
new file mode 100644
index 0000000..7e0e865
--- /dev/null
+++ b/src/game/commands.c
@@ -0,0 +1,61 @@
+#include "commands.h"
+#include <string.h>
+
+static struct cmd_res command_switch(struct game_state *state, int argc, char **argv);
+
+struct cmd_res run_command(struct game_state *state, char *command)
+{
+ int argc = 0;
+ char *argv[MAX_ARGS_COUNT];
+ char *arg = command;
+ char *space;
+ int arg_length;
+ while ((space = strchr(arg, ' ')) != NULL)
+ {
+ if (*arg != ' ')
+ {
+ arg_length = space - arg;
+ argv[argc] = malloc(arg_length + 1);
+ strncpy(argv[argc], arg, arg_length);
+ argv[argc][arg_length] = 0;
+ arg = space + 1;
+ argc++;
+ }
+ }
+ //Last arg
+ arg_length = strlen(arg);
+ argv[argc] = malloc(arg_length + 1);
+ strncpy(argv[argc], arg, arg_length);
+ argv[argc][arg_length] = 0;
+ argc++;
+
+ struct cmd_res response = command_switch(state, argc, argv);
+ for (int i = 0; i < argc; i++)
+ free(argv[i]);
+ return response;
+}
+
+static struct cmd_res nothing(struct game_state *state, int argc, char **argv)
+{
+ struct cmd_res response;
+ response.type = CRT_FAIL;
+ strncpy(response.text, "There is no command you entered!", MAX_CR_TEXT_LENGTH);
+ return response;
+}
+
+static struct cmd_res quit(struct game_state *state, int argc, char **argv)
+{
+ state->result = GR_QUIT;
+ struct cmd_res response;
+ response.type = CRT_QUIT;
+ *(response.text) = 0;
+ return response;
+}
+
+static struct cmd_res command_switch(struct game_state *state, int argc, char **argv)
+{
+ if (!strcmp("", *argv))
+ return nothing(state, argc, argv);
+ else if (!strcmp("q", *argv))
+ return quit(state, argc, argv);
+} \ No newline at end of file
diff --git a/src/game/commands.h b/src/game/commands.h
new file mode 100644
index 0000000..8e2cc5f
--- /dev/null
+++ b/src/game/commands.h
@@ -0,0 +1,24 @@
+#ifndef H_MAZE_GAME_COMMANDS
+#define H_MAZE_GAME_COMMANDS
+
+#include "game.h"
+
+enum cmd_res_type
+{
+ CRT_SUCCESS,
+ CRT_FAIL,
+ CRT_QUIT
+};
+
+#define MAX_CR_TEXT_LENGTH 256
+#define MAX_ARGS_COUNT 100
+
+struct cmd_res
+{
+ enum cmd_res_type type;
+ char text[MAX_CR_TEXT_LENGTH];
+};
+
+struct cmd_res run_command(struct game_state *state, char *command);
+
+#endif \ No newline at end of file
diff --git a/src/game/entry.c b/src/game/entry.c
new file mode 100644
index 0000000..50cf78c
--- /dev/null
+++ b/src/game/entry.c
@@ -0,0 +1,152 @@
+#include "entry.h"
+#include "game.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+#include "utilities.h"
+#include "color.h"
+#include "maze_solver.h"
+
+static inline int mvaddwch(int y, int x, wchar_t wch)
+{
+ wchar_t arr[2];
+ arr[0] = wch;
+ arr[1] = 0;
+ return mvaddwstr(y, x, arr);
+}
+
+static inline int addwch(wchar_t wch)
+{
+ wchar_t arr[2];
+ arr[0] = wch;
+ arr[1] = 0;
+ return addwstr(arr);
+}
+
+static void darw_block(struct block *block)
+{
+ attron(COLOR_PAIR(block->color));
+ if (block->bold)
+ attron(A_BOLD);
+ addwch(block->chr);
+ if (block->bold)
+ attroff(A_BOLD);
+}
+
+static void mv_draw_block(int y, int x, struct block *block)
+{
+ int width = getmaxx(stdscr);
+ int height = getmaxy(stdscr) - 1;
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ {
+ move(y, x);
+ darw_block(block);
+ }
+}
+
+void draw_maze(struct maze_display *maze_draw, struct game_blocks *blocks)
+{
+ int width = getmaxx(stdscr);
+ int height = getmaxy(stdscr) - 1;
+ enum signs path_sign;
+ for (int y = 0; y < maze_draw->maze->height; y++)
+ {
+ int real_y = maze_draw->maze_pos.y + y;
+ if (real_y >= 0 && real_y < height)
+ {
+ if (maze_draw->maze_pos.x >= 0)
+ move(real_y, maze_draw->maze_pos.x);
+ for (int x = 0; x < maze_draw->maze->width && y < width; x++)
+ {
+ int real_x = maze_draw->maze_pos.x + x;
+ if (real_x == 0 && x > 0)
+ {
+ move(real_y, 0);
+ }
+ if (real_x >= 0 && real_x < width)
+ {
+ path_sign = maze_draw->signs[x][y];
+ if (path_sign == RS_NONE || (path_sign == RS_PATH && !maze_draw->display_player_path)) //Maze
+ {
+ if (maze_draw->maze->map[x][y])
+ darw_block(&(blocks->wall));
+ else
+ darw_block(&(blocks->road));
+ }
+ else
+ {
+ if (path_sign == RS_PATH)
+ darw_block(&(blocks->path));
+ else if (path_sign == RS_SOLVE)
+ darw_block(&(blocks->solve));
+ }
+ }
+ }
+ }
+ }
+ //Player
+ mv_draw_block(
+ maze_draw->maze_pos.y + maze_draw->player_pos.y,
+ maze_draw->maze_pos.x + maze_draw->player_pos.x, &(blocks->player));
+ mv_draw_block(
+ maze_draw->maze_pos.y + maze_draw->maze->starting_point.y,
+ maze_draw->maze_pos.x + maze_draw->maze->starting_point.x, &(blocks->start));
+ mv_draw_block(
+ maze_draw->maze_pos.y + maze_draw->maze->end_point.y,
+ maze_draw->maze_pos.x + maze_draw->maze->end_point.x, &(blocks->target));
+}
+
+static void own_clear()
+{
+ attron(COLOR_PAIR(CI_DEFAULT));
+ int width = getmaxx(stdscr);
+ int height = getmaxy(stdscr) - 1;
+ for (int y = 0; y < height; y++)
+ for (int x = 0; x < width; x++)
+ mvaddch(y, x, ' ');
+}
+
+enum game_res game(struct app *app)
+{
+ curs_set(0);
+ noecho();
+ struct game_state *state = create_game_state(app->maze);
+
+ while (1)
+ {
+ if (state->display->player_pos.x != state->new_player_pos.x ||
+ state->display->player_pos.y != state->new_player_pos.y) //Does player moved?
+ {
+ state->display->signs[state->display->player_pos.x][state->display->player_pos.y] = RS_PATH;
+ state->display->player_pos = state->new_player_pos;
+ if (state->center)
+ state->new_maze_pos = get_player_center(state->display->player_pos);
+ if (state->display->player_pos.x == state->display->maze->end_point.x &&
+ state->display->player_pos.y == state->display->maze->end_point.y) //Win?
+ state->win = true;
+ }
+ state->display->maze_pos = state->new_maze_pos;
+ //Draw!
+ own_clear();
+ draw_maze(state->display, &(app->conf->blocks));
+ if (state->win)
+ draw_line_win();
+ else
+ draw_line_info(state->steps_taken, solve_maze(app->maze, state->display->player_pos, NULL));
+ wrefresh(stdscr);
+ //Get user input!
+ wchar_t c = wgetch(stdscr);
+ struct binding *last_binding = &(app->conf->bindings[app->conf->count - 1]);
+ for (struct binding *binding = app->conf->bindings; binding <= last_binding; binding++)
+ {
+ if ((*(binding->cname) != 0 && strcmp(keyname(c), binding->cname) == 0) || c == binding->c)
+ {
+ if (binding->operation(state, binding->param) == OPR_QUIT)
+ {
+ return state->result;
+ }
+ }
+ }
+ }
+ return GR_QUIT;
+}
diff --git a/src/game/entry.h b/src/game/entry.h
new file mode 100644
index 0000000..655f719
--- /dev/null
+++ b/src/game/entry.h
@@ -0,0 +1,9 @@
+#ifndef H_MAZE_GAME_ENTRY
+#define H_MAZE_GAME_ENTRY
+
+#include "app.h"
+#include "game.h"
+
+enum game_res game(struct app *app);
+
+#endif \ No newline at end of file
diff --git a/src/game/game.c b/src/game/game.c
new file mode 100644
index 0000000..a9ac239
--- /dev/null
+++ b/src/game/game.c
@@ -0,0 +1,109 @@
+#include "game.h"
+#include "color.h"
+#include "utilities.h"
+#include <string.h>
+
+void draw_line(int color, char *text, size_t length)
+{
+ int width = getmaxx(stdscr);
+ int height = getmaxy(stdscr) - 1;
+ char footer[width + 1];
+ memset(footer, ' ', width);
+ footer[width] = 0;
+ //Display:
+ attron(COLOR_PAIR(color));
+ mvprintw(height, 0, footer);
+ strncpy(footer, text, length);
+ mvprintw(height, 0, footer);
+}
+
+void draw_line_info(int steps_taken, int steps_remaining)
+{
+ char buffer[getmaxx(stdscr) + 1];
+ int length = sprintf(buffer, "%d/%d", steps_taken, steps_remaining);
+ draw_line(CI_LINE_INFO, buffer, length);
+}
+
+void draw_line_win()
+{
+ char buffer[getmaxx(stdscr) + 1];
+ int length = sprintf(buffer, "\u2714 Win! \u263A");
+ draw_line(CI_LINE_SUCCESS, buffer, length);
+}
+
+int get_command(char prompt, char *command)
+{
+ int width = getmaxx(stdscr);
+ int height = getmaxy(stdscr) - 1;
+
+ char line[width + 1];
+ memset(line, ' ', width);
+ line[width] = 0;
+ attron(COLOR_PAIR(CI_LINE_CMD));
+ curs_set(1);
+
+ char *current = command;
+ *(current++) = prompt;
+ *current = 0;
+ while (1)
+ {
+ mvaddstr(height, 0, line);
+ mvaddstr(height, 0, command);
+ refresh();
+ wchar_t c = wgetch(stdscr);
+ if (c == KEY_BACKSPACE)
+ {
+ current--;
+ *current = 0;
+ if (current == command)
+ {
+ curs_set(0);
+ return 0;
+ }
+ }
+ else if (c == 10)
+ {
+ curs_set(0);
+ return 1;
+ }
+ else
+ {
+ *(current++) = c;
+ *current = 0;
+ }
+ }
+}
+
+struct game_state *create_game_state(struct maze *maze)
+{
+ struct maze_display *display = malloc(sizeof(struct maze_display));
+
+ display->maze_pos.x = 0;
+ display->maze_pos.y = 0;
+ display->maze = maze;
+ display->player_pos = maze->starting_point;
+ display->display_player_path = true;
+ //Signs
+ int signs_length = sizeof_2d(maze->width, maze->height, sizeof(int));
+ display->signs = malloc(signs_length);
+ memset(display->signs, (int)RS_NONE, signs_length);
+ init2d((void **)display->signs, maze->width, maze->height, sizeof(int));
+ display->signs[display->player_pos.x][display->player_pos.y] = RS_PATH;
+
+ struct game_state *state = malloc(sizeof(struct game_state));
+ state->display = display;
+
+ state->center = false;
+ state->win = false;
+ state->steps_taken = 0;
+ state->new_maze_pos = display->maze_pos;
+ state->new_player_pos = display->player_pos;
+ return state;
+}
+
+struct array
+{
+ int width;
+ int height;
+ int *arr;
+};
diff --git a/src/game/game.h b/src/game/game.h
new file mode 100644
index 0000000..4b0de07
--- /dev/null
+++ b/src/game/game.h
@@ -0,0 +1,67 @@
+#ifndef H_MAZE_GAME_GAME
+#define H_MAZE_GAME_GAME
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ncurses.h>
+#include "maze.h"
+
+enum game_res
+{
+ GR_MENU,
+ GR_QUIT
+};
+
+enum signs
+{
+ RS_NONE,
+ RS_SOLVE,
+ RS_PATH
+};
+
+struct maze_display
+{
+ struct point maze_pos;
+ struct point player_pos;
+ struct maze *maze;
+ enum signs **signs;
+ bool display_player_path;
+};
+
+struct game_state
+{
+ struct maze_display *display;
+ struct point new_maze_pos;
+ struct point new_player_pos;
+ int steps_taken;
+ bool center;
+ bool win;
+ char cmd_history[100][256];
+ size_t cmd_count;
+ enum game_res result;
+};
+
+struct game_state *create_game_state(struct maze *maze);
+
+void draw_line_win();
+
+void draw_line_info(int steps_taken, int steps_remaining);
+
+int get_command(char prompt, char *command);
+
+static inline int is_movable(struct maze_display *display, int x, int y)
+{
+ return display->maze->map[display->player_pos.x + x][display->player_pos.y + y] == 0;
+}
+
+static inline struct point get_player_center(struct point player_pos)
+{
+ int width = getmaxx(stdscr);
+ int height = getmaxy(stdscr) - 1;
+ struct point maze_pos;
+ maze_pos.x = (width / 2) - player_pos.x;
+ maze_pos.y = (height / 2) - player_pos.y;
+ return maze_pos;
+}
+
+#endif \ No newline at end of file
diff --git a/src/game/operations.c b/src/game/operations.c
new file mode 100644
index 0000000..aa9424f
--- /dev/null
+++ b/src/game/operations.c
@@ -0,0 +1,144 @@
+#include "operations.h"
+#include <string.h>
+#include "maze_generator.h"
+#include "maze_solver.h"
+#include "commands.h"
+
+enum op_res move_player(struct game_state *state, int data)
+{
+ if (state->win)
+ return OPR_NONE;
+ enum move move = (enum move)data;
+ if (move == MOVE_UP && is_movable(state->display, 0, -1))
+ {
+ state->new_player_pos.y--;
+ state->steps_taken++;
+ }
+ else if (move == MOVE_DOWN && is_movable(state->display, 0, 1))
+ {
+ state->new_player_pos.y++;
+ state->steps_taken++;
+ }
+ else if (move == MOVE_LEFT && is_movable(state->display, -1, 0))
+ {
+ state->new_player_pos.x--;
+ state->steps_taken++;
+ }
+ else if (move == MOVE_RIGHT && is_movable(state->display, 1, 0))
+ {
+ state->new_player_pos.x++;
+ state->steps_taken++;
+ }
+ return OPR_NONE;
+}
+
+enum op_res move_maze(struct game_state *state, int data)
+{
+ switch ((enum move)data)
+ {
+ case MOVE_UP:
+ state->new_maze_pos.y--;
+ break;
+ case MOVE_DOWN:
+ state->new_maze_pos.y++;
+ break;
+ case MOVE_LEFT:
+ state->new_maze_pos.x--;
+ break;
+ case MOVE_RIGHT:
+ state->new_maze_pos.x++;
+ break;
+ case MOVE_BEGINNING:
+ {
+ state->new_maze_pos.x = 0;
+ state->new_maze_pos.y = 0;
+ }
+ break;
+ }
+ return OPR_NONE;
+}
+
+enum op_res quit(struct game_state *state, int data)
+{
+ state->result = data;
+ return OPR_QUIT;
+}
+
+enum op_res turn_display_switch(struct game_state *state, int data)
+{
+ switch ((enum display)data)
+ {
+ case DISP_PATH:
+ state->display->display_player_path = !(state->display->display_player_path);
+ break;
+ }
+ return OPR_NONE;
+}
+
+enum op_res new_random(struct game_state *state, int data)
+{
+ struct maze_display *display = state->display;
+ generate_maze(display->maze);
+ display->player_pos = display->maze->starting_point;
+ state->new_player_pos = display->player_pos;
+ for (int x = 0; x < display->maze->width; x++)
+ {
+ for (int y = 0; y < display->maze->height; y++)
+ {
+ display->signs[x][y] = RS_NONE;
+ }
+ }
+ state->win = false;
+ state->steps_taken = 0;
+ return OPR_NONE;
+}
+
+enum op_res center(struct game_state *state, int data)
+{
+ state->center = !state->center;
+ if (state->center)
+ state->new_maze_pos = get_player_center(state->display->player_pos);
+ return OPR_NONE;
+}
+
+enum op_res help_by_n_move(struct game_state *state, int data)
+{
+ struct point path[3000];
+ int count = solve_maze(state->display->maze, state->display->player_pos, path);
+ if (count > 0)
+ {
+ state->new_player_pos = path[1];
+ state->steps_taken++;
+ }
+ return OPR_NONE;
+}
+
+enum op_res solve(struct game_state *state, int data)
+{
+ struct point path[3000];
+ int count = solve_maze(state->display->maze, state->display->player_pos, path);
+ for (int i = 0; i < count; i++)
+ {
+ state->display->signs[path[i].x][path[i].y] = RS_SOLVE;
+ }
+ return OPR_NONE;
+}
+
+enum op_res start_command_prompt(struct game_state *state, int data)
+{
+ char command[256];
+ if (get_command((char)data, command))
+ {
+ struct cmd_res response = run_command(state, command + 1);
+ switch (response.type)
+ {
+ case CRT_SUCCESS:
+ break;
+ case CRT_FAIL:
+ break;
+ case CRT_QUIT:
+ return OPR_QUIT;
+ }
+ }
+ return OPR_NONE;
+} \ No newline at end of file
diff --git a/src/game/operations.h b/src/game/operations.h
new file mode 100644
index 0000000..2f2af47
--- /dev/null
+++ b/src/game/operations.h
@@ -0,0 +1,44 @@
+#ifndef H_MAZE_GAME_OPERATION
+#define H_MAZE_GAME_OPERATION
+
+#include "game.h"
+
+enum op_res
+{
+ OPR_NONE,
+ OPR_QUIT
+};
+
+enum move
+{
+ MOVE_UP,
+ MOVE_DOWN,
+ MOVE_LEFT,
+ MOVE_RIGHT,
+ MOVE_BEGINNING
+};
+
+enum display
+{
+ DISP_PATH
+};
+
+enum op_res move_player(struct game_state *state, int data);
+
+enum op_res move_maze(struct game_state *state, int data);
+
+enum op_res quit(struct game_state *state, int data);
+
+enum op_res turn_display_switch(struct game_state *state, int data);
+
+enum op_res new_random(struct game_state *state, int data);
+
+enum op_res center(struct game_state *state, int data);
+
+enum op_res help_by_n_move(struct game_state *state, int data);
+
+enum op_res solve(struct game_state *state, int data);
+
+enum op_res start_command_prompt(struct game_state *state, int data);
+
+#endif \ No newline at end of file