aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/grid.c55
-rw-r--r--src/grid.h59
-rw-r--r--src/maze.c145
-rw-r--r--src/maze.h28
-rw-r--r--src/mazerator.c118
-rw-r--r--src/position.c9
-rw-r--r--src/position.h13
-rw-r--r--src/position_stack.c7
-rw-r--r--src/position_stack.h12
-rw-r--r--src/utils.c54
-rw-r--r--src/utils.h22
12 files changed, 331 insertions, 192 deletions
diff --git a/.gitignore b/.gitignore
index 5acb669..69b610c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
build
.vscode
+.cache
diff --git a/src/grid.c b/src/grid.c
new file mode 100644
index 0000000..7248087
--- /dev/null
+++ b/src/grid.c
@@ -0,0 +1,55 @@
+#include "grid.h"
+#include "utils.h"
+#include <stdlib.h>
+
+Grid grid_create(unsigned int width, unsigned int height, char *fill)
+{
+ unsigned int mem_height = height * sizeof(char **);
+ unsigned int mem_width = width * sizeof(char *);
+
+ Dimensions dimens = {.width = width, .height = height};
+
+ Grid grid = {.grid = malloc_s(mem_height), .dimens = dimens};
+
+ // Fill the grid
+ for (unsigned int y = 0; y < height; y++)
+ {
+ grid.grid[y] = malloc_s(mem_width);
+
+ for (unsigned int x = 0; x < width; x++)
+ grid.grid[y][x] = fill;
+ }
+
+ return grid;
+}
+
+char *grid_get(Grid grid, Position pos)
+{
+ return grid.grid[pos.y][pos.x];
+}
+
+void grid_set(Grid grid, Position pos, char *value)
+{
+ grid.grid[pos.y][pos.x] = value;
+}
+
+void grid_print(Grid grid)
+{
+ for (unsigned int y = 0; y < grid.dimens.height; y++)
+ {
+ for (unsigned int x = 0; x < grid.dimens.width; x++)
+ printf("%s", grid.grid[y][x]);
+
+ printf("\n");
+ }
+}
+
+void grid_destroy(Grid grid)
+{
+ // Deallocate the memory of the grid
+ for (unsigned int y = 0; y < grid.dimens.height; y++)
+ free(grid.grid[y]);
+
+ free(grid.grid);
+}
+
diff --git a/src/grid.h b/src/grid.h
new file mode 100644
index 0000000..65fa01a
--- /dev/null
+++ b/src/grid.h
@@ -0,0 +1,59 @@
+#ifndef GRID_H
+#define GRID_H
+
+#include "position.h"
+
+typedef struct Dimensions
+{
+ unsigned int width;
+ unsigned int height;
+} Dimensions;
+
+typedef struct Grid
+{
+ char ***grid;
+ Dimensions dimens;
+} Grid;
+
+/**
+ * Returns a grid.
+ *
+ * @param width The grid width
+ * @param height The grid height
+ * @param fill A string to fill the new grid with
+ */
+Grid grid_create(unsigned int width, unsigned int height, char *fill);
+
+/*
+ * Returns a value from a position in a grid.
+ *
+ * @param grid A grid
+ * @param pos A grid position
+ */
+char *grid_get(Grid grid, Position pos);
+
+/*
+ * Sets the value of a position in a grid.
+ *
+ * @param grid A grid
+ * @param pos A grid position
+ * @param value A new value
+ */
+void grid_set(Grid grid, Position pos, char *value);
+
+/**
+ * Prints a grid.
+ *
+ * @param grid A grid
+ */
+void grid_print(Grid grid);
+
+/**
+ * Destroys a grid.
+ *
+ * @param grid A grid
+ */
+void grid_destroy(Grid grid);
+
+#endif
+
diff --git a/src/maze.c b/src/maze.c
index ec627b9..2097906 100644
--- a/src/maze.c
+++ b/src/maze.c
@@ -1,124 +1,89 @@
#include "maze.h"
+#include "grid.h"
+#include "position.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-/**
- * Returns a filled grid.
- *
- * @param width The width of the new grid
- * @param height The height of the new grid
- * @param fill A string to fill the new grid with
- */
-char ***create_grid(int width, int height, char *fill)
+int is_pos_empty(Grid grid, Position pos)
{
- char ***grid;
-
- // Fill the grid
- grid = malloc(height * sizeof(char **));
- for (int y = 0; y < height; y++)
- {
- grid[y] = malloc(width * sizeof(char *));
-
- for (int x = 0; x < width; x++)
- {
- grid[y][x] = fill;
- }
- }
-
- return grid;
+ return strcmp(grid_get(grid, pos), " ") != 0;
}
-Maze maze_create(Dimensions dimens, char *wall)
+void add_neighbour(Position neighbours[], uint8_t *neighbour_cnt, Position neighbour_pos)
{
- Maze maze;
-
- maze.dimens = dimens;
-
- Dimensions full_dimens = {.width = dimens.width * 2 + 1,
- .height = dimens.height * 2 + 1};
+ neighbours[*neighbour_cnt] = neighbour_pos;
+ (*neighbour_cnt)++;
- maze.full_dimens = full_dimens;
-
- maze.grid = create_grid(full_dimens.width, full_dimens.height, wall);
-
- return maze;
}
-void maze_destroy(Maze *maze)
+void get_neighbours(Grid grid, Position pos, Position neighbours[], uint8_t *neighbour_cnt)
{
- // Deallocate the memory of the maze's grid
- for (int y = 0; y < maze->full_dimens.height; y++)
+ if (pos.y != 1)
{
- free(maze->grid[y]);
- }
- free(maze->grid);
-}
+ Position pos_down = position_create(pos.x, pos.y - 2);
-void get_neighbours(Maze *maze, Position pos, Position neighbours[3], int *neighbour_cnt)
-{
- if (pos.y != 0 && strcmp(maze->grid[pos.y * 2 - 1][pos.x * 2 + 1], " ") != 0)
- {
- Position down_neighbour_pos = {.x = pos.x, .y = pos.y - 1};
- neighbours[*neighbour_cnt] = down_neighbour_pos;
- (*neighbour_cnt)++;
+ if (is_pos_empty(grid, pos_down))
+ add_neighbour(neighbours, neighbour_cnt, pos_down);
}
- if (pos.y != maze->dimens.height - 1 &&
- strcmp(maze->grid[(pos.y + 1) * 2 + 1][pos.x * 2 + 1], " ") != 0)
+
+ if (pos.y != grid.dimens.height - 2)
{
- Position up_neighbour_pos = {.x = pos.x, .y = pos.y + 1};
- neighbours[*neighbour_cnt] = up_neighbour_pos;
- (*neighbour_cnt)++;
+ Position pos_up = position_create(pos.x, pos.y + 2);
+
+ if (is_pos_empty(grid, pos_up))
+ add_neighbour(neighbours, neighbour_cnt, pos_up);
}
- if (pos.x != 0 && strcmp(maze->grid[pos.y * 2 + 1][pos.x * 2 - 1], " ") != 0)
+
+ if (pos.x != 1)
{
- Position left_neighbour_pos = {.x = pos.x - 1, .y = pos.y};
- neighbours[*neighbour_cnt] = left_neighbour_pos;
- (*neighbour_cnt)++;
+ Position pos_left = position_create(pos.x - 2, pos.y);
+
+ if (is_pos_empty(grid, pos_left))
+ add_neighbour(neighbours, neighbour_cnt, pos_left);
}
- if (pos.x != maze->dimens.width - 1 &&
- strcmp(maze->grid[pos.y * 2 + 1][(pos.x + 1) * 2 + 1], " ") != 0)
+
+ if (pos.x != grid.dimens.width - 2)
{
- Position right_neighbour_pos = {.x = pos.x + 1, .y = pos.y};
- neighbours[*neighbour_cnt] = right_neighbour_pos;
- (*neighbour_cnt)++;
+ Position pos_right = position_create(pos.x + 2, pos.y);
+
+ if (is_pos_empty(grid, pos_right))
+ add_neighbour(neighbours, neighbour_cnt, pos_right);
}
}
-int is_whole_maze_visited(Maze *maze, int visited_pos_cnt)
+unsigned int get_maze_size(Grid grid)
{
- if (visited_pos_cnt == (maze->dimens.height * maze->dimens.width) - 1)
- {
- return 1;
- }
+ return ((grid.dimens.width - 1) / 2) * ((grid.dimens.height - 1) / 2);
+}
- return 0;
+int is_whole_maze_visited(Grid grid, unsigned int visited_pos_cnt)
+{
+ return visited_pos_cnt == get_maze_size(grid) - 1;
}
-void maze_excavate(Maze *maze, Position start_pos)
+void grid_to_maze(Grid grid, Position start_pos)
{
- PositionStack *path = pos_stack_create(maze->dimens.width * maze->dimens.height);
+ PositionStack *path = pos_stack_create(get_maze_size(grid));
pos_stack_push(path, start_pos);
- int visited_pos_cnt = 0;
+ unsigned int visited_pos_cnt = 0;
while (1)
{
Position pos = pos_stack_peek(path);
- maze->grid[pos.y * 2 + 1][pos.x * 2 + 1] = " ";
+ grid_set(grid, pos, " ");
- Position neighbours[3] = {};
- int neighbour_cnt = 0;
+ Position neighbours[3];
+ uint8_t neighbour_cnt = 0;
- get_neighbours(maze, pos, neighbours, &neighbour_cnt);
+ get_neighbours(grid, pos, neighbours, &neighbour_cnt);
if (neighbour_cnt == 0)
{
- if (is_whole_maze_visited(maze, visited_pos_cnt))
- {
+ if (is_whole_maze_visited(grid, visited_pos_cnt))
break;
- }
// Go back a step
pos_stack_pop(path);
@@ -129,8 +94,15 @@ void maze_excavate(Maze *maze, Position start_pos)
Position next_pos = neighbours[rand() % neighbour_cnt];
- maze->grid[pos.y * 2 - (pos.y - next_pos.y) + 1]
- [pos.x * 2 - (pos.x - next_pos.x) + 1] = " ";
+ Position between_pos = position_create(pos.x, pos.y);
+
+ if (next_pos.y != pos.y)
+ between_pos.y += next_pos.y > pos.y ? 1 : -1;
+
+ if (next_pos.x != pos.x)
+ between_pos.x += next_pos.x > pos.x ? 1 : -1;
+
+ grid_set(grid, between_pos, " ");
pos_stack_push(path, next_pos);
}
@@ -138,14 +110,3 @@ void maze_excavate(Maze *maze, Position start_pos)
pos_stack_destroy(path);
}
-void maze_print(Maze maze)
-{
- for (int y = 0; y < maze.full_dimens.height; y++)
- {
- for (int x = 0; x < maze.full_dimens.width; x++)
- {
- printf("%s", maze.grid[y][x]);
- }
- printf("\n");
- }
-}
diff --git a/src/maze.h b/src/maze.h
index 8c66ff7..1a3937f 100644
--- a/src/maze.h
+++ b/src/maze.h
@@ -2,34 +2,14 @@
#define MAZE_H
#include "position_stack.h"
-
-typedef struct Dimensions
-{
- int width;
- int height;
-} Dimensions;
-
-typedef struct Maze
-{
- char ***grid;
- Dimensions dimens;
- Dimensions full_dimens;
-} Maze;
-
-Maze maze_create(Dimensions dimens, char *wall);
-
-void maze_destroy(Maze *maze);
+#include "grid.h"
/**
- * Excavates a maze.
- *
- * This is what creates the actual maze.
+ * Creates a maze from a grid
*
- * @param maze The maze to excavate
+ * @param grid A grid
* @param start_pos Start position
*/
-void maze_excavate(Maze *maze, Position start_pos);
-
-void maze_print(Maze maze);
+void grid_to_maze(Grid grid, Position start_pos);
#endif
diff --git a/src/mazerator.c b/src/mazerator.c
index d231173..95c6fb6 100644
--- a/src/mazerator.c
+++ b/src/mazerator.c
@@ -1,38 +1,19 @@
#include "maze.h"
+#include "grid.h"
+#include "position.h"
#include "utils.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
-void validate_number_optarg(char *optarg, int c)
+void optarg_error(char arg, char *error)
{
- unsigned int is_invalid = 0;
-
- size_t error_length = 40;
- char *error = malloc(error_length + 1);
-
- if (!is_number(optarg))
- {
- is_invalid = 1;
- snprintf(error, error_length, "It must be a number");
- }
- else if (atoi(optarg) < 1)
- {
- is_invalid = 1;
- snprintf(error, error_length, "It must be greater than 0");
- }
-
- if (is_invalid == 1)
- {
- printf("Error: Invalid option argument for -%c. %s\n", c, error);
- free(error);
- exit(1);
- }
-
- free(error);
+ printf("Error: Invalid option argument for -%c. %s\n", arg, error);
+ exit(EXIT_FAILURE);
}
-void validate_start_coords(int start_x, int start_y, int width, int height)
+void validate_start_coords(unsigned int start_x, unsigned int start_y, unsigned int width,
+ unsigned int height)
{
char *error_format =
"Error: The %s start coordinate is not allowed to be higher than the maze's %s\n";
@@ -40,17 +21,17 @@ void validate_start_coords(int start_x, int start_y, int width, int height)
if (start_x > width)
{
printf(error_format, "x", "width");
- exit(1);
+ exit(EXIT_FAILURE);
}
if (start_y > height)
{
printf(error_format, "y", "height");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
-void get_seed(int *seed_dst)
+void get_seed(unsigned int *seed_dst)
{
FILE *urandom = fopen("/dev/urandom", "r");
fread(seed_dst, sizeof(*seed_dst), 1, urandom);
@@ -68,40 +49,60 @@ const struct option options[] = {{"width", required_argument, NULL, 'w'},
int main(int argc, char *argv[])
{
- int maze_width = 40;
- int maze_height = 20;
- int start_x = 0;
- int start_y = 0;
+ unsigned int maze_width = 40U;
+ unsigned int maze_height = 20U;
+ unsigned int start_x = 1U;
+ unsigned int start_y = 1U;
+ unsigned int *seed = NULL;
+
char *wall = "█";
- int seed = -1;
- int c;
- while ((c = getopt_long(argc, argv, "w:h:W:s:x:y:", options, NULL)) != -1)
+ int arg;
+ while ((arg = getopt_long(argc, argv, "w:h:W:s:x:y:", options, NULL)) != -1)
{
- switch (c)
+ char *err = NULL;
+
+ switch (arg)
{
case 'w':
- validate_number_optarg(optarg, c);
- maze_width = atoi(optarg);
+ maze_width = str_to_uint(optarg, &err);
+
+ if (err != NULL)
+ optarg_error(arg, err);
+
break;
case 'h':
- validate_number_optarg(optarg, c);
- maze_height = atoi(optarg);
+ maze_height = str_to_uint(optarg, &err);
+
+ if (err != NULL)
+ optarg_error(arg, err);
+
break;
case 'x':
- validate_number_optarg(optarg, c);
- start_x = atoi(optarg);
+ start_x = str_to_uint(optarg, &err);
+
+ if (err != NULL)
+ optarg_error(arg, err);
+
break;
case 'y':
- validate_number_optarg(optarg, c);
- start_y = atoi(optarg);
+ start_y = str_to_uint(optarg, &err);
+
+ if (err != NULL)
+ optarg_error(arg, err);
+
break;
case 'W':
wall = optarg;
break;
case 's':
- validate_number_optarg(optarg, c);
- seed = atoi(optarg);
+ seed = malloc_s(sizeof(unsigned int *));
+
+ *seed = str_to_uint(optarg, &err);
+
+ if (err != NULL)
+ optarg_error(arg, err);
+
break;
case 0:
printf("Usage: %s [OPTION]...\n\n"
@@ -109,9 +110,9 @@ int main(int argc, char *argv[])
" -w, --width WIDTH The width of the maze (Default: 40)\n"
" -h, --heigth HEIGHT The heigth of the maze (Default: 20)\n"
" -x, --start-x X The x coordinate for the start position "
- "(Default: 0)\n"
+ "(Default: 1)\n"
" -y, --start-y Y The y coordinate for the start position "
- "(Default: 0)\n"
+ "(Default: 1)\n"
" -W, --wall WALL Single character used as maze walls "
"(Default: '█')\n"
" -s, --seed SEED The randomization seed used for maze "
@@ -127,22 +128,23 @@ int main(int argc, char *argv[])
validate_start_coords(start_x, start_y, maze_width, maze_height);
- if (seed == -1)
+ if (seed == NULL)
{
- get_seed(&seed);
+ seed = malloc_s(sizeof(unsigned int *));
+ get_seed(seed);
}
- srand(seed);
+ srand(*seed);
- Dimensions dimens = {.width = maze_width, .height = maze_height};
+ free(seed);
- Maze maze = maze_create(dimens, wall);
+ Position start_pos = position_create(start_x, start_y);
- Position start_pos = {.x = start_x, .y = start_y};
+ Grid grid = grid_create(maze_width * 2 + 1, maze_width * 2 + 1, wall);
- maze_excavate(&maze, start_pos);
+ grid_to_maze(grid, start_pos);
- maze_print(maze);
+ grid_print(grid);
- maze_destroy(&maze);
+ grid_destroy(grid);
}
diff --git a/src/position.c b/src/position.c
new file mode 100644
index 0000000..937edd5
--- /dev/null
+++ b/src/position.c
@@ -0,0 +1,9 @@
+#include "position.h"
+
+Position position_create(unsigned int x, unsigned int y)
+{
+ Position pos = {.x = x, .y = y};
+
+ return pos;
+}
+
diff --git a/src/position.h b/src/position.h
new file mode 100644
index 0000000..d1bc9eb
--- /dev/null
+++ b/src/position.h
@@ -0,0 +1,13 @@
+#ifndef POSITION_H
+#define POSITION_H
+
+typedef struct Position
+{
+ unsigned int x;
+ unsigned int y;
+} Position;
+
+Position position_create(unsigned int x, unsigned int y);
+
+#endif
+
diff --git a/src/position_stack.c b/src/position_stack.c
index 846d933..597ed5a 100644
--- a/src/position_stack.c
+++ b/src/position_stack.c
@@ -1,4 +1,5 @@
#include "position_stack.h"
+#include "utils.h"
#include <stdio.h>
#include <stdlib.h>
@@ -19,13 +20,13 @@ void stack_error(int err)
}
// Creates a new stack
-PositionStack *pos_stack_create(int capacity)
+PositionStack *pos_stack_create(unsigned int capacity)
{
- PositionStack *pos_stack = malloc(sizeof(PositionStack));
+ PositionStack *pos_stack = malloc_s(sizeof(PositionStack));
pos_stack->capacity = capacity;
pos_stack->top = -1;
- pos_stack->items = malloc(sizeof(Position) * capacity);
+ pos_stack->items = malloc_s(sizeof(Position) * capacity);
return pos_stack;
}
diff --git a/src/position_stack.h b/src/position_stack.h
index 83fb98c..674da23 100644
--- a/src/position_stack.h
+++ b/src/position_stack.h
@@ -1,23 +1,19 @@
#ifndef POSITION_STACK_H
#define POSITION_STACK_H
+#include "position.h"
+
#define STACK_ERR_OVERFLOW 0xFFF01
#define STACK_ERR_UNDERFLOW 0xFFF02
-typedef struct Position
-{
- int x;
- int y;
-} Position;
-
typedef struct PositionStack
{
- int capacity;
+ unsigned int capacity;
int top;
Position *items;
} PositionStack;
-PositionStack *pos_stack_create(int capacity);
+PositionStack *pos_stack_create(unsigned int capacity);
void pos_stack_destroy(PositionStack *pos_stack);
diff --git a/src/utils.c b/src/utils.c
index 93f7c53..69ce55d 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,17 +1,57 @@
#include "utils.h"
#include <ctype.h>
#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
-/**
- * Returns whether or not a string is a number.
- */
int is_number(char *str)
{
- size_t len = strlen(str);
- for (int c = 0; c < len; c++)
- {
+ unsigned int length = strlen(str);
+
+ for (unsigned int c = 0; c < length; c++)
if (!isdigit(str[c]))
return 0;
- }
+
return 1;
}
+
+
+void *malloc_s(unsigned long amount)
+{
+ void *memory = malloc(amount);
+
+ if (memory == NULL)
+ {
+ printf("Error: Memory allocation failed");
+ exit(EXIT_FAILURE);
+ }
+
+ return memory;
+}
+
+unsigned int str_to_uint(char *str, char **err)
+{
+ if (*str == '-')
+ {
+ *err = "Not greater than 0";
+ return 0;
+ }
+
+ char *str_waste;
+ unsigned long num = strtoul(str, &str_waste, 10);
+
+ if (strlen(str_waste) != 0)
+ {
+ *err = "Not a number";
+ return 0;
+ }
+
+ if (num > (unsigned long)UINT_MAX)
+ {
+ *err = "Too large";
+ return 0;
+ }
+
+ return (unsigned int)num;
+}
+
diff --git a/src/utils.h b/src/utils.h
index a1b69e1..049e583 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,6 +1,28 @@
#ifndef UTILS_H
#define UTILS_H
+/**
+ * Returns whether or not a string is a number.
+ *
+ * @param str A string
+ */
int is_number(char *str);
+/**
+ * Safely allocates memory to the heap.
+ *
+ * @param amount The amount of memory to allocate
+ * @returns The allocated memory.
+ */
+void *malloc_s(unsigned long amount);
+
+/**
+ * Converts a string to a unsigned integer.
+ *
+ * @param str A string
+ * @param err A error destination
+ * @returns A unsigned integer.
+ */
+unsigned int str_to_uint(char *str, char **err);
+
#endif