aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSopár Adrián <adrian.sopar@protonmail.com>2024-06-20 09:28:14 +0200
committerSopár Adrián <adrian.sopar@protonmail.com>2024-06-20 09:28:14 +0200
commit74ea6dc86646cee9915292d73d8c7afef01ef3e0 (patch)
tree9a58866f7765dad8ba56f1f40b1fa031e9d2687d /src
First commit. This is mostly the state of the project as I left it around the end of 2019.HEADmaster
Diffstat (limited to 'src')
-rw-r--r--src/app.h15
-rw-r--r--src/args.c27
-rw-r--r--src/args.h21
-rw-r--r--src/color.c21
-rw-r--r--src/color.h16
-rw-r--r--src/config.c16
-rw-r--r--src/config.h54
-rw-r--r--src/defaults.h48
-rw-r--r--src/file.c95
-rw-r--r--src/file.h10
-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
-rw-r--r--src/main.c44
-rw-r--r--src/maze.h32
-rw-r--r--src/maze_generator.c113
-rw-r--r--src/maze_generator.h8
-rw-r--r--src/maze_solver.c78
-rw-r--r--src/maze_solver.h8
-rw-r--r--src/menu.c184
-rw-r--r--src/menu.h8
-rw-r--r--src/utilities.c56
-rw-r--r--src/utilities.h14
28 files changed, 1478 insertions, 0 deletions
diff --git a/src/app.h b/src/app.h
new file mode 100644
index 0000000..cc45fbc
--- /dev/null
+++ b/src/app.h
@@ -0,0 +1,15 @@
+#ifndef H_MAZE_APP
+#define H_MAZE_APP
+
+#include "maze.h"
+#include "config.h"
+#include "args.h"
+
+struct app
+{
+ struct maze *maze;
+ struct args *args;
+ struct conf *conf;
+};
+
+#endif \ No newline at end of file
diff --git a/src/args.c b/src/args.c
new file mode 100644
index 0000000..67e7b81
--- /dev/null
+++ b/src/args.c
@@ -0,0 +1,27 @@
+#include "args.h"
+#include <string.h>
+
+void load_args(int argc, char **argv, struct args *args)
+{
+ args->maze_source = MS_UNDEFINIED;
+ args->input_file_name[0] = 0;
+ args->output_file_name[0] = 0;
+ args->start = false;
+ args->hide_menu = false;
+ for (int i = 1; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-g"))
+ args->maze_source = MS_RANDOM;
+ else if (!strcmp(argv[i], "-s"))
+ args->start = true;
+ else if (!strcmp(argv[i], "-h"))
+ args->hide_menu = true;
+ else if (i + 1 < argc)
+ {
+ if (!strcmp(argv[i], "-i"))
+ strcpy(args->input_file_name, argv[i + 1]);
+ else if (!strcmp(argv[i], "-o"))
+ strcpy(args->output_file_name, argv[i + 1]);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/args.h b/src/args.h
new file mode 100644
index 0000000..31e42f4
--- /dev/null
+++ b/src/args.h
@@ -0,0 +1,21 @@
+#ifndef MAZE_ARGS_H
+#define MAZE_ARGS_H
+
+#include <stdbool.h>
+
+#define MS_UNDEFINIED 0
+#define MS_FROM_FILE 1
+#define MS_RANDOM 2
+
+struct args
+{
+ int maze_source;
+ char input_file_name[256];
+ char output_file_name[256];
+ bool start;
+ bool hide_menu;
+};
+
+void load_args(int argc, char **argv, struct args *args);
+
+#endif \ No newline at end of file
diff --git a/src/color.c b/src/color.c
new file mode 100644
index 0000000..b2cc725
--- /dev/null
+++ b/src/color.c
@@ -0,0 +1,21 @@
+#include "color.h"
+#include <ncurses.h>
+
+#define COLOR3_COUNT 8
+
+void maze_color_init()
+{
+ start_color();
+ short colors[COLOR3_COUNT] = {COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE};
+ for (short f = 0; f < COLOR3_COUNT; f++)
+ for (short b = 0; b < COLOR3_COUNT; b++)
+ init_pair(get_color_code(f, b), f, b);
+}
+
+short get_color_code(short foreground, short background)
+{
+ short code = foreground;
+ code |= background << 3;
+ code++;
+ return code;
+} \ No newline at end of file
diff --git a/src/color.h b/src/color.h
new file mode 100644
index 0000000..ce1e3d3
--- /dev/null
+++ b/src/color.h
@@ -0,0 +1,16 @@
+#ifndef H_MAZE_COLOR
+#define H_MAZE_COLOR
+
+#include <ncurses.h>
+
+short get_color_code(short foreground, short background);
+
+#define CI_DEFAULT get_color_code(COLOR_WHITE,COLOR_BLACK)
+#define CI_LINE_INFO get_color_code(COLOR_BLACK,COLOR_CYAN)
+#define CI_LINE_SUCCESS get_color_code(COLOR_BLACK,COLOR_GREEN)
+#define CI_LINE_CMD get_color_code(COLOR_BLACK,COLOR_YELLOW)
+#define CI_LINE_ERROR get_color_code(COLOR_BLACK,COLOR_RED)
+
+void maze_color_init();
+
+#endif \ No newline at end of file
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..98f806a
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,16 @@
+#include "config.h"
+#include "defaults.h"
+#include <string.h>
+
+struct conf *load_default_conf()
+{
+ struct conf *conf = malloc(sizeof(struct conf));
+ //Bindings.
+ struct binding bindings[] = DEFAULT_BINDINGS;
+ conf->bindings = malloc(sizeof(bindings));
+ memcpy(conf->bindings, bindings, sizeof(bindings));
+ conf->count = sizeof(bindings) / sizeof(struct binding);
+ //Game blocks.
+ set_blocks(&(conf->blocks));
+ return conf;
+} \ No newline at end of file
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..6ee5a47
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,54 @@
+#ifndef H_MAZE_CONFIG
+#define H_MAZE_CONFIG
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include "game/operations.h"
+
+struct binding
+{
+ wchar_t c;
+ char cname[5];
+ enum op_res (*operation)(struct game_state *, int);
+ int param;
+};
+
+struct block
+{
+ wchar_t chr;
+ bool bold;
+ short color;
+};
+
+struct game_blocks
+{
+ struct block wall;
+ struct block road;
+ struct block path;
+ struct block solve;
+ struct block player;
+ struct block start;
+ struct block target;
+};
+
+struct conf
+{
+ struct binding *bindings;
+ struct game_blocks blocks;
+ size_t count;
+};
+
+static inline struct block get_block(wchar_t chr, bool bold, short color)
+{
+ struct block result;
+ result.chr = chr;
+ result.bold = bold;
+ result.color = color;
+ return result;
+}
+
+struct conf *load_default_conf();
+
+void destroy_conf(struct conf *);
+
+#endif \ No newline at end of file
diff --git a/src/defaults.h b/src/defaults.h
new file mode 100644
index 0000000..d4fdc1b
--- /dev/null
+++ b/src/defaults.h
@@ -0,0 +1,48 @@
+#ifndef H_MAZE_DEFAULTS
+#define H_MAZE_DEFAULTS
+
+#include "config.h"
+#include "color.h"
+#include <ncurses.h>
+#include <stdio.h>
+
+static inline void set_blocks(struct game_blocks *game_blocks)
+{
+ game_blocks->wall = get_block(' ', false, get_color_code(COLOR_BLACK, COLOR_WHITE));
+ game_blocks->road = get_block(' ', false, get_color_code(COLOR_WHITE, COLOR_BLACK));
+ game_blocks->path = get_block(0x2022, false, get_color_code(COLOR_YELLOW, COLOR_BLACK));
+ game_blocks->solve = get_block(0x2022, false, get_color_code(COLOR_BLUE, COLOR_BLACK));
+ game_blocks->player = get_block(0x25CF, false, get_color_code(COLOR_CYAN, COLOR_BLACK));
+ game_blocks->start = get_block('S', true, get_color_code(COLOR_GREEN, COLOR_BLACK));
+ game_blocks->target = get_block('T', true, get_color_code(COLOR_RED, COLOR_BLACK));
+}
+
+#define DEFAULT_BINDINGS \
+ { \
+ {KEY_UP, "", move_player, MOVE_UP}, \
+ {KEY_DOWN, "", move_player, MOVE_DOWN}, \
+ {KEY_LEFT, "", move_player, MOVE_LEFT}, \
+ {KEY_RIGHT, "", move_player, MOVE_RIGHT}, \
+ {'k', "", move_player, MOVE_UP}, \
+ {'j', "", move_player, MOVE_DOWN}, \
+ {'h', "", move_player, MOVE_LEFT}, \
+ {'l', "", move_player, MOVE_RIGHT}, \
+ {0, "kUP5", move_maze, MOVE_UP}, \
+ {0, "kDN5", move_maze, MOVE_DOWN}, \
+ {0, "kLFT5", move_maze, MOVE_LEFT}, \
+ {0, "kRIT5", move_maze, MOVE_RIGHT}, \
+ {0, "^K", move_maze, MOVE_UP}, \
+ {0, "^J", move_maze, MOVE_DOWN}, \
+ {0, "^H", move_maze, MOVE_LEFT}, \
+ {0, "^L", move_maze, MOVE_RIGHT}, \
+ {'0', "", move_maze, MOVE_BEGINNING}, \
+ {'p', "", turn_display_switch, DISP_PATH}, \
+ {'q', "", quit, GR_QUIT}, \
+ {'r', "", new_random, 0}, \
+ {'c', "", center, 0}, \
+ {'n', "", help_by_n_move, 1}, \
+ {'s', "", solve, 0}, \
+ {':', "", start_command_prompt, ':'}, \
+ }
+
+#endif \ No newline at end of file
diff --git a/src/file.c b/src/file.c
new file mode 100644
index 0000000..511b580
--- /dev/null
+++ b/src/file.c
@@ -0,0 +1,95 @@
+#include "file.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "utilities.h"
+
+struct data
+{
+ int x;
+ int y;
+ int value;
+};
+
+static int **list_to_map(struct data *values, int count, int width, int height)
+{
+ int **map = malloc(sizeof_2d(width, height, sizeof(int)));
+ init2d((void **)map, width, height, sizeof(int));
+ for (int i = 0; i < count; i++)
+ map[values[i].x][values[i].y] = values[i].value;
+ return map;
+}
+
+static void get_numbers(char *line, int *left_int, int *right_int)
+{
+ char *left, *right;
+ if (find_lr_ints(line, &left, &right))
+ {
+ *left_int = strtol(left, NULL, 10);
+ *right_int = strtol(right, NULL, 10);
+ }
+}
+
+struct maze *maze_from_file(char *path)
+{
+ FILE *file = fopen(path, "r");
+ if (file == NULL)
+ return NULL;
+ struct maze *maze = malloc(sizeof(struct maze));
+ struct data values[50 * 50];
+ char buffer[256];
+ int i = 0, y = 0, max_width = 0;
+ while (fgets(buffer, 256, file))
+ {
+ int length = strlen(buffer);
+ if (length > 0)
+ {
+ if (length > 5 && !strncmp(buffer, "start", 5))
+ {
+ get_numbers(buffer + 5, &(maze->starting_point.x), &(maze->starting_point.y));
+ }
+ else if (length > 3 && !strncmp(buffer, "end", 3))
+ {
+ get_numbers(buffer + 3, &(maze->end_point.x), &(maze->end_point.y));
+ }
+ else
+ {
+ int x;
+ for (x = 0; buffer[x] != 10; x++)
+ {
+ values[i].x = x;
+ values[i].y = y;
+ values[i].value = buffer[x] == '0' ? 0 : 1;
+ i++;
+ }
+ if (x > max_width)
+ max_width = x;
+ y++;
+ }
+ }
+ }
+ fclose(file);
+ maze->width = max_width;
+ maze->height = y;
+ maze->map = list_to_map(values, i, maze->width, maze->height);
+ return maze;
+}
+
+int maze_to_file(char *path, struct maze *maze)
+{
+ FILE *file = fopen(path, "w");
+ if (file == NULL)
+ return -1;
+ fprintf(file, "start=(%d,%d)\n", maze->starting_point.x, maze->starting_point.y);
+ fprintf(file, "end=(%d,%d)\n", maze->end_point.x, maze->end_point.y);
+ for (int y = 0; y < maze->height; y++)
+ {
+ for (int x = 0; x < maze->width; x++)
+ {
+ fprintf(file, "%d", maze->map[x][y]);
+ }
+ fprintf(file, "\n");
+ }
+ fclose(file);
+ return 0;
+} \ No newline at end of file
diff --git a/src/file.h b/src/file.h
new file mode 100644
index 0000000..5e5268d
--- /dev/null
+++ b/src/file.h
@@ -0,0 +1,10 @@
+#ifndef MAZE_FILE_H
+#define MAZE_FILE_H
+
+#include "maze.h"
+
+struct maze *maze_from_file(char *path);
+
+int maze_to_file(char *path, struct maze *maze);
+
+#endif \ No newline at end of file
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
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..20ff774
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,44 @@
+#include <ncurses.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <time.h>
+#include "app.h"
+#include "color.h"
+#include "menu.h"
+
+void handle(struct app *app)
+{
+}
+
+int main(int argc, char **argv)
+{
+ srand(time(NULL));
+ //Setup ncurses
+ setlocale(LC_ALL, "");
+ initscr();
+ raw();
+ keypad(stdscr, TRUE);
+ maze_color_init();
+ //Construct app
+ struct app app;
+ app.maze = NULL;
+ //Load args
+ struct args args;
+ args.hide_menu = true;
+ load_args(argc, argv, &args);
+ app.args = &args;
+ //Load config
+ app.conf = load_default_conf();
+ //Start main loop
+ handle(&app);
+ if (!args.hide_menu)
+ main_menu_loop(&app);
+ //Deallocate
+ if (app.maze != NULL)
+ {
+ free(app.maze->map);
+ free(app.maze);
+ }
+ //End
+ endwin();
+} \ No newline at end of file
diff --git a/src/maze.h b/src/maze.h
new file mode 100644
index 0000000..5b3581a
--- /dev/null
+++ b/src/maze.h
@@ -0,0 +1,32 @@
+#ifndef MAZE_H
+#define MAZE_H
+
+struct point
+{
+ int x;
+ int y;
+};
+
+struct maze
+{
+ int width;
+ int height;
+ int **map;
+ struct point starting_point;
+ struct point end_point;
+};
+
+static inline struct point relative_point(struct point point, int x, int y)
+{
+ struct point new_point;
+ new_point.x = point.x + x;
+ new_point.y = point.y + y;
+ return new_point;
+}
+
+static inline int is_valid_maze_size(int size)
+{
+ return size > 2 && size % 2 != 0;
+}
+
+#endif \ No newline at end of file
diff --git a/src/maze_generator.c b/src/maze_generator.c
new file mode 100644
index 0000000..3a2e3b2
--- /dev/null
+++ b/src/maze_generator.c
@@ -0,0 +1,113 @@
+#include <stdlib.h>
+#include "maze_generator.h"
+#include "utilities.h"
+#include "maze.h"
+
+static void remove_wall(int **graph, struct point a, struct point b)
+{
+ int diff_x = a.x - b.x;
+ int diff_y = a.y - b.y;
+ if (diff_y == 0)
+ {
+ if (diff_x == 1)
+ graph[b.x][b.y] &= 3;
+ else if (diff_x == -1)
+ graph[a.x][a.y] &= 3;
+ }
+ else if (diff_x == 0)
+ {
+ if (diff_y == 1)
+ graph[b.x][b.y] &= 5;
+ else if (diff_y == -1)
+ graph[a.x][a.y] &= 5;
+ }
+}
+
+static void generate_maze_graph(int **graph, int width, int height, struct point point)
+{
+ //I've been here.
+ graph[point.x][point.y] &= 6;
+ struct point points[4];
+ int index = 0;
+ //Possibilities:
+ if (point.x > 0)
+ points[index++] = relative_point(point, -1, 0);
+ if (point.x < width - 1)
+ points[index++] = relative_point(point, 1, 0);
+ if (point.y > 0)
+ points[index++] = relative_point(point, 0, -1);
+ if (point.y < height - 1)
+ points[index++] = relative_point(point, 0, 1);
+ //Shuffle:
+ shuffle(points, index, sizeof(struct point));
+ //Examine possibilities:
+ index--;
+ struct point new_point;
+ while (index >= 0)
+ {
+ new_point = points[index];
+ if ((graph[new_point.x][new_point.y] & 1) == 1)
+ {
+ //Remove wall:
+ remove_wall(graph, point, new_point);
+ //Go on:
+ generate_maze_graph(graph, width, height, new_point);
+ }
+ index--;
+ }
+}
+
+int generate_maze(struct maze *maze)
+{
+ if (!is_valid_maze_size(maze->width) || !is_valid_maze_size(maze->height))
+ return -1;
+ //Init graph:
+ int graph_width = ((maze->width - 2) + 1) / 2;
+ int graph_height = ((maze->height - 2) + 1) / 2;
+ char mem[sizeof_2d(graph_width, graph_height, sizeof(int))];
+ init2d((void **)mem, graph_width, graph_height, sizeof(int));
+ int **graph = (int **)mem;
+ for (int x = 0; x < graph_width; x++)
+ for (int y = 0; y < graph_height; y++)
+ graph[x][y] = 7;
+ //Generate graph:
+ struct point starting_point;
+ starting_point.x = 0;
+ starting_point.y = 0;
+ generate_maze_graph(graph, graph_width, graph_height, starting_point);
+ //Convert:
+ for (int x = 0; x < graph_width; x++)
+ {
+ for (int y = 0; y < graph_height; y++)
+ {
+ int real_x = (2 * x) + 1;
+ int real_y = (2 * y) + 1;
+ int is_last_x = x == maze->width - 2;
+ int is_last_y = y == maze->height - 2;
+ maze->map[real_x][real_y] = 0;
+ if (!is_last_x)
+ maze->map[real_x + 1][real_y] = (graph[x][y] & 4) == 4;
+ if (!is_last_y)
+ maze->map[real_x][real_y + 1] = (graph[x][y] & 2) == 2;
+ if (!(is_last_x || is_last_y))
+ maze->map[real_x + 1][real_y + 1] = 1;
+ }
+ }
+ //Set sides:
+ for (int x = 0; x < maze->width; x++)
+ {
+ maze->map[x][0] = 1;
+ maze->map[x][maze->height - 1] = 1;
+ }
+ for (int y = 0; y < maze->height; y++)
+ {
+ maze->map[0][y] = 1;
+ maze->map[maze->width - 1][y] = 1;
+ }
+ //Set start and end:
+ maze->starting_point.x = 1;
+ maze->starting_point.y = 1;
+ maze->end_point.x = maze->width - 2;
+ maze->end_point.y = maze->height - 2;
+ return 0;
+} \ No newline at end of file
diff --git a/src/maze_generator.h b/src/maze_generator.h
new file mode 100644
index 0000000..2176703
--- /dev/null
+++ b/src/maze_generator.h
@@ -0,0 +1,8 @@
+#ifndef MAZE_GENERATOR_H
+#define MAZE_GENERATOR_H
+
+#include "maze.h"
+
+int generate_maze(struct maze *maze);
+
+#endif \ No newline at end of file
diff --git a/src/maze_solver.c b/src/maze_solver.c
new file mode 100644
index 0000000..6286d24
--- /dev/null
+++ b/src/maze_solver.c
@@ -0,0 +1,78 @@
+#include "maze_solver.h"
+#include <string.h>
+#include "utilities.h"
+
+struct solver_data
+{
+ struct maze *maze;
+ struct point *first_point;
+ struct point *last_point;
+ int count;
+ //int temp[51][51];
+ int **temp;
+};
+
+static void get_neighbours(struct point point, struct point *neighbours)
+{
+ neighbours[0].x = point.x + 1;
+ neighbours[0].y = point.y;
+ neighbours[1].x = point.x - 1;
+ neighbours[1].y = point.y;
+ neighbours[2].x = point.x;
+ neighbours[2].y = point.y + 1;
+ neighbours[3].x = point.x;
+ neighbours[3].y = point.y - 1;
+}
+
+static int solve_maze_rec(struct solver_data *data, struct point point)
+{
+ if (data->first_point == NULL)
+ data->count++;
+ else
+ *(data->last_point++) = point;
+
+ data->temp[point.x][point.y] = 1;
+ if (data->maze->end_point.x == point.x && data->maze->end_point.y == point.y)
+ {
+ if (data->first_point == NULL)
+ return data->count;
+ else
+ return (data->last_point - data->first_point);
+ }
+ struct point neighbours[4];
+ get_neighbours(point, neighbours);
+ for (int i = 0; i < 4; i++)
+ {
+ if (neighbours[i].x >= 0 &&
+ neighbours[i].y >= 0 &&
+ neighbours[i].x < data->maze->width &&
+ neighbours[i].y < data->maze->height &&
+ data->maze->map[neighbours[i].x][neighbours[i].y] != 1 &&
+ data->temp[neighbours[i].x][neighbours[i].y] != 1)
+ {
+ int value = solve_maze_rec(data, neighbours[i]);
+ if (value >= 0)
+ return value;
+ }
+ }
+ if (data->first_point == NULL)
+ data->count--;
+ else
+ data->last_point--;
+ return -1;
+}
+
+int solve_maze(struct maze *maze, struct point point, struct point *path)
+{
+ struct solver_data solver_data;
+ solver_data.maze = maze;
+ solver_data.first_point = path;
+ solver_data.last_point = path;
+ solver_data.count = 0;
+ int length = sizeof_2d(maze->width, maze->height, sizeof(int));
+ char mem[length];
+ memset(mem, 0, length);
+ init2d((void **)mem, maze->width, maze->height, sizeof(int));
+ solver_data.temp = (int **)mem;
+ return solve_maze_rec(&solver_data, point) - 1;
+} \ No newline at end of file
diff --git a/src/maze_solver.h b/src/maze_solver.h
new file mode 100644
index 0000000..8dac12c
--- /dev/null
+++ b/src/maze_solver.h
@@ -0,0 +1,8 @@
+#ifndef MAZE_SOLVER_H
+#define MAZE_SOLVER_H
+
+#include "maze.h"
+
+int solve_maze(struct maze *maze, struct point point, struct point *path);
+
+#endif \ No newline at end of file
diff --git a/src/menu.c b/src/menu.c
new file mode 100644
index 0000000..eca1a20
--- /dev/null
+++ b/src/menu.c
@@ -0,0 +1,184 @@
+#include "menu.h"
+#include <stdlib.h>
+#include <ncurses.h>
+#include "color.h"
+#include "game/entry.h"
+#include "utilities.h"
+#include "maze_generator.h"
+#include "file.h"
+
+#define MO_LOAD_FROM_FILE 1
+#define MO_SAVE_TO_FILE 2
+#define MO_GENERATE 3
+#define MO_START 4
+#define MO_QUIT 5
+#define MO_INVALID_OPTION 6
+
+int choose_menu_option()
+{
+ attron(COLOR_PAIR(CI_DEFAULT));
+ clear();
+ printw("1. Load from file.\n");
+ printw("2. Save to file.\n");
+ printw("3. Random maze.\n");
+ printw("4. Start the game.\n");
+ printw("q. Quit.\n");
+ printw("Choose:\n");
+ curs_set(1);
+ echo();
+ refresh();
+ //char buffer[8];
+ //wgetnstr(stdscr, buffer, 8);
+ switch (getch())
+ {
+ case '1':
+ return MO_LOAD_FROM_FILE;
+ break;
+ case '2':
+ return MO_SAVE_TO_FILE;
+ break;
+ case '3':
+ return MO_GENERATE;
+ break;
+ case '4':
+ return MO_START;
+ break;
+ case 'q':
+ return MO_QUIT;
+ break;
+ }
+ return MO_INVALID_OPTION;
+}
+
+int get_file_path(char *path)
+{
+ attron(COLOR_PAIR(CI_DEFAULT));
+ clear();
+ printw("Enter the path of file:\n");
+ curs_set(1);
+ echo();
+ wgetnstr(stdscr, path, 256);
+ return *path == 0 ? -1 : 1;
+}
+
+int save_file_path(char *path)
+{
+ return get_file_path(path);
+}
+
+int open_file_path(char *path)
+{
+ return get_file_path(path);
+}
+
+void get_size(int *width, int *height)
+{
+ attron(COLOR_PAIR(CI_DEFAULT));
+ while (1)
+ {
+ clear();
+ printw("Enter a size:\n");
+ curs_set(1);
+ echo();
+ char buffer[16];
+ wgetnstr(stdscr, buffer, 16);
+ char *left, *right;
+ if (find_lr_ints(buffer, &left, &right))
+ {
+ char *end;
+ *width = strtol(left, &end, 10);
+ printw("\nwidth=%d\n", *width);
+ if (*end == '%')
+ {
+ *width = ((double)*width / 100) * getmaxx(stdscr);
+ if (!is_valid_maze_size(*width))
+ (*width)--;
+ }
+ *height = strtol(right, &end, 10);
+ printw("\nheight=%d\n", *height);
+ if (*end == '%')
+ {
+ *height = ((double)*height / 100) * getmaxy(stdscr);
+ if (!is_valid_maze_size(*height))
+ (*height)--;
+ }
+ printw("\nwidth=%d\nheight=%d\n", *width, *height);
+ }
+ if (is_valid_maze_size(*width) && is_valid_maze_size(*height))
+ return;
+ printw("\nWrong size number!\n");
+ while (getch() != 10)
+ ;
+ }
+}
+
+void main_menu_loop(struct app *app)
+{
+ while (1)
+ {
+ switch (choose_menu_option())
+ {
+ case MO_LOAD_FROM_FILE:
+ {
+ char path[256];
+ if (open_file_path(path))
+ {
+ app->maze = maze_from_file(path);
+ if (app->maze == NULL)
+ {
+ printw("\nFile is not exsist!\n");
+ while (getch() != 10)
+ ;
+ }
+ }
+ }
+ break;
+ case MO_SAVE_TO_FILE:
+ {
+ char path[256];
+ if (save_file_path(path))
+ {
+ maze_to_file(path, app->maze);
+ }
+ }
+ break;
+ case MO_GENERATE:
+ {
+ app->maze = malloc(sizeof(struct maze));
+ get_size(&(app->maze->width), &(app->maze->height));
+ //maze->width = 41;
+ //maze->height = 21;
+ app->maze->map = malloc(sizeof_2d(app->maze->width, app->maze->height, sizeof(int)));
+ init2d((void **)app->maze->map, app->maze->width, app->maze->height, sizeof(int));
+ generate_maze(app->maze);
+ }
+ break;
+ case MO_START:
+ {
+ if (app->maze == NULL)
+ {
+ printw("\nThere is no maze!\n");
+ while (getch() != 10)
+ ;
+ }
+ else if (game(app) == GR_QUIT)
+ {
+ return;
+ }
+ }
+ break;
+ case MO_QUIT:
+ {
+ return;
+ }
+ case MO_INVALID_OPTION:
+ {
+ printw("\nError!\n");
+ while (getch() != 10)
+ ;
+ }
+ break;
+ }
+ //TODO: Handle.
+ }
+} \ No newline at end of file
diff --git a/src/menu.h b/src/menu.h
new file mode 100644
index 0000000..83394f5
--- /dev/null
+++ b/src/menu.h
@@ -0,0 +1,8 @@
+#ifndef H_MAZE_MENU
+#define H_MAZE_MENU
+
+#include "app.h"
+
+void main_menu_loop(struct app *app);
+
+#endif \ No newline at end of file
diff --git a/src/utilities.c b/src/utilities.c
new file mode 100644
index 0000000..1142ec4
--- /dev/null
+++ b/src/utilities.c
@@ -0,0 +1,56 @@
+#include "utilities.h"
+#include <string.h>
+#include <time.h>
+
+static unsigned int random_number(unsigned int max)
+{
+ return rand() / (RAND_MAX / max);
+}
+
+void shuffle(void *base, size_t nitems, size_t size)
+{
+ char *c_base = base;
+ char swap[size];
+ for (int i = 0; i < nitems; i++)
+ {
+ char *a = c_base + (i * size);
+ char *b = c_base + (random_number(nitems - 1) * size);
+ memcpy(swap, a, size);
+ memcpy(a, b, size);
+ memcpy(b, swap, size);
+ }
+}
+
+void init2d(void **array, size_t width, size_t height, size_t size)
+{
+ char **c_array = (char **)array;
+ char *start = (char *)array;
+ for (size_t x = 0; x < width; x++)
+ c_array[x] = start + (width * sizeof(int *)) + (x * height * size);
+}
+
+size_t sizeof_2d(size_t width, size_t height, size_t size)
+{
+ return (width * sizeof(char *)) + (width * height * size);
+}
+
+/*
+ * Find left and right ints.
+ */
+int find_lr_ints(char *text, char **left, char **right)
+{
+ *left = text;
+ while (**left != 0 && (**left < '0' || **left > '9'))
+ (*left)++;
+ if (**left == 0)
+ return 0;
+
+ *right = text + strlen(text);
+ while (**right < '0' || **right > '9')
+ (*right)--;
+
+ while (**right >= '0' && **right <= '9')
+ (*right)--;
+ (*right)++;
+ return 1;
+} \ No newline at end of file
diff --git a/src/utilities.h b/src/utilities.h
new file mode 100644
index 0000000..6787883
--- /dev/null
+++ b/src/utilities.h
@@ -0,0 +1,14 @@
+#ifndef UTILITIES_H
+#define UTILITIES_H
+
+#include <stdlib.h>
+
+void shuffle(void *base, size_t nitems, size_t size);
+
+void init2d(void **array, size_t width, size_t height, size_t size);
+
+size_t sizeof_2d(size_t width, size_t height, size_t size);
+
+int find_lr_ints(char *text, char **left, char **right);
+
+#endif \ No newline at end of file