aboutsummaryrefslogtreecommitdiff
path: root/mazerator.c
diff options
context:
space:
mode:
Diffstat (limited to 'mazerator.c')
-rw-r--r--mazerator.c345
1 files changed, 180 insertions, 165 deletions
diff --git a/mazerator.c b/mazerator.c
index f15c4ae..8ebc7d3 100644
--- a/mazerator.c
+++ b/mazerator.c
@@ -6,38 +6,27 @@
#include <string.h>
#include <unistd.h>
-// Error handling
-void err(int id)
+/**
+ * Returns a position in the maze from coordinates y and x.
+ *
+ * This is achieved by concatenating the binary values of the two variables.
+ *
+ * For example:
+ *
+ * Y: 8 (0b00001000)
+ * X: 15 (0b00001111)
+ *
+ * Will become:
+ * 0b0000100000001111
+ */
+int get_maze_pos(int posY, int posX)
{
- switch (id)
- {
- case 0:
- printf("Error: Stack overflow\nBe kind and report this problem.");
- break;
- case 1:
- printf("Error: Stack underflow\nBe kind and report this problem.");
- break;
- }
- exit(1);
+ return ((posY) << 8) | posX;
}
-// Get a position in the maze from coordinates y and x
-//
-// This is achieved by concatenating the binary values of the two variables.
-//
-// For example:
-// Y: 8 00001000
-// X: 15 00001111
-// Will become:
-// 0000100000001111
-int get_maze_pos(int posY, int posX) { return ((posY) << 8) | posX; }
-
-// Get y and x coordinates from a position in the maze
-//
-// This is achived by using bitwise operations
-//
-// >> is the bitwise right shift operator and will shift bits to the right
-// & is the bitwise and operator and is used to get only specific bits
+/**
+ * Returns y and x coordinates from a position in the maze.
+ */
int get_maze_coords(int pos, int *y, int *x)
{
*y = pos >> 8;
@@ -45,8 +34,9 @@ int get_maze_coords(int pos, int *y, int *x)
return 1;
}
-// Find out if a string is a number by running it through
-// isdigit() char-by-char
+/**
+ * Returns whether or not a string is a number.
+ */
int is_number(char *str)
{
size_t len = strlen(str);
@@ -58,21 +48,138 @@ int is_number(char *str)
return 1;
}
+/**
+ * Returns a maze filled with walls.
+ *
+ * Arguments:
+ * - height: The height of the new maze
+ * - width: The width of the new maze
+ * - wall: The wall to fill the new maze with
+ */
+char ***create_maze(int height, int width, char *wall)
+{
+ char ***maze;
+
+ // Fill the maze with walls
+ maze = malloc(height * sizeof(char **));
+ for (int y = 0; y < height; y++)
+ {
+ maze[y] = malloc(width * sizeof(char *));
+
+ for (int x = 0; x < width; x++)
+ {
+ maze[y][x] = wall;
+ }
+ }
+
+ return maze;
+}
+
+/**
+ * Excavates a maze.
+ *
+ * This is what creates the actual maze.
+ *
+ * Arguments:
+ * - maze: The maze to excavate
+ * - maze_height: The height of the maze
+ * - maze_width: The width of the maze
+ */
+void excavate_maze(char ***maze, int maze_height, int maze_width)
+{
+ struct stack *path = create_stack(maze_width * maze_height);
+
+ stack_push(path, 0);
+
+ int visited_pos_cnt = 0;
+ while (1)
+ {
+ int pos = stack_peek(path);
+ int posY, posX;
+ get_maze_coords(pos, &posY, &posX);
+
+ // Set the currently visited grid square to 1 indicating that it has been
+ // visited and excavate the visual maze
+ maze[posY * 2 + 1][posX * 2 + 1] = " ";
+
+ // Find out available next positions to go to
+ int neighbours[3];
+ int neighbour_cnt = 0;
+
+ if (posY != 0 && strcmp(maze[posY * 2 - 1][posX * 2 + 1], " ") != 0)
+ {
+ neighbours[neighbour_cnt] = get_maze_pos(posY - 1, posX);
+ neighbour_cnt++;
+ }
+ if (posY != maze_height - 1 && strcmp(maze[(posY + 1) * 2 + 1][posX * 2 + 1], " ") != 0)
+ {
+ neighbours[neighbour_cnt] = get_maze_pos(posY + 1, posX);
+ neighbour_cnt++;
+ }
+ if (posX != 0 && strcmp(maze[posY * 2 + 1][posX * 2 - 1], " ") != 0)
+ {
+ neighbours[neighbour_cnt] = get_maze_pos(posY, posX - 1);
+ neighbour_cnt++;
+ }
+ if (posX != maze_width - 1 && strcmp(maze[posY * 2 + 1][(posX + 1) * 2 + 1], " ") != 0)
+ {
+ neighbours[neighbour_cnt] = get_maze_pos(posY, posX + 1);
+ neighbour_cnt++;
+ }
+
+ if (neighbour_cnt == 0)
+ {
+ if (visited_pos_cnt == (maze_height * maze_width) - 1)
+ {
+ // The whole maze have been visited
+ break;
+ }
+
+ // Go back a step
+ stack_pop(path);
+ continue;
+ }
+
+ visited_pos_cnt++;
+
+ int next_pos = neighbours[rand() % neighbour_cnt];
+
+ int next_pos_y, next_pos_x;
+ get_maze_coords(next_pos, &next_pos_y, &next_pos_x);
+
+ maze[posY * 2 - (posY - next_pos_y) + 1]
+ [posX * 2 - (posX - next_pos_x) + 1] = " ";
+
+ stack_push(path, next_pos);
+ }
+}
+
+void print_maze(char ***maze, int height, int width)
+{
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ printf("%s", maze[y][x]);
+ }
+ printf("\n");
+ }
+}
+
+const struct option options[] = {
+ {"width", required_argument, NULL, 'w'},
+ {"heigth", required_argument, NULL, 'h'},
+ {"wall", required_argument, NULL, 'W'},
+ {"seed", required_argument, NULL, 's'},
+ {"help", no_argument, NULL, 0},
+ {NULL, 0, NULL, 0}};
+
int main(int argc, char *argv[])
{
int maze_width = 40;
- int maze_heigth = 20;
+ int maze_height = 20;
char *wall = "█";
- int seed = 0;
-
- static struct option options[] = {
- /* NAME ARGUMENT FLAG SHORTNAME */
- {"width", required_argument, NULL, 'w'},
- {"heigth", required_argument, NULL, 'h'},
- {"wall", required_argument, NULL, 'W'},
- {"seed", required_argument, NULL, 's'},
- {"help", no_argument, NULL, 0},
- {NULL, 0, NULL, 0}};
+ int seed = -1;
int c;
while ((c = getopt_long(argc, argv, "w:h:W:s:", options, NULL)) != -1)
@@ -80,159 +187,67 @@ int main(int argc, char *argv[])
switch (c)
{
case 'w':
+ if (!is_number(optarg) || atoi(optarg) < 1 || atoi(optarg) > 255)
+ {
+ printf("Invalid option argument for -%c!\n", c);
+ exit(1);
+ }
+
+ maze_width = atoi(optarg);
+ break;
case 'h':
- // Set heigth or width
- if (is_number(optarg) && atoi(optarg) >= 1 && atoi(optarg) <= 255)
- switch (c)
- {
- case 'h':
- maze_heigth = atoi(optarg);
- case 'w':
- maze_width = atoi(optarg);
- }
- else
+ if (!is_number(optarg) || atoi(optarg) < 1 || atoi(optarg) > 255)
{
printf("Invalid option argument for -%c!\n", c);
exit(1);
}
+
+ maze_height = atoi(optarg);
break;
case 'W':
- // Set the wall
wall = optarg;
break;
case 's':
- // Set the seed
- if (is_number(optarg))
- {
- seed = atoi(optarg);
- break;
- }
- else
+ if (!is_number(optarg))
{
printf("Invalid option argument for -s/--seed!\n");
exit(1);
}
+
+ seed = atoi(optarg);
+ break;
case 0:
- // Help
printf(
- "Usage: mazerator [--help] [-W wall] [-s seed] [-w width] [-h heigth]\n\n\
-OPTIONS\n\
- --width -w The width of the maze. (1-255). Default: 40\n\
- --heigth -h The heigth of the maze. (1-255). Default: 20\n\
- --wall -W Single character used as maze walls. Default: '█'\n\
- --seed -s The randomization seed used for maze generation. (Any number). Default is to read /dev/urandom\n\
- --help Displays usage information\n\
-");
+ "Usage: %s [OPTION]...\n\n"
+ "Options:\n"
+ " -w, --width WIDTH The width of the maze. (1-255) (Default: 40)\n"
+ " -h, --heigth HEIGHT The heigth of the maze. (1-255) (Default: 20)\n"
+ " -w, --wall WALL Single character used as maze walls (Default: '█')\n"
+ " -s, --seed SEED The randomization seed used for maze generation. (Any number)\n"
+ " --help Displays usage information\n",
+ argv[0]);
exit(0);
case '?':
- printf("\nTry 'mazerator --help' for more information\n");
+ printf("\nTry '%s --help' for more information\n", argv[0]);
exit(1);
}
}
- int maze[maze_heigth][maze_width];
- char *maze_visual[maze_heigth * 2 + 1][maze_width * 2 + 1];
- struct stack *path = new_stack(maze_width * maze_heigth);
-
- // Prepares seed value for randr()
- // Get's a seed from /dev/urandom if not already set
- if (seed == 0)
+ if (seed == -1)
{
- printf("What");
FILE *f = fopen("/dev/urandom", "r");
fread(&seed, sizeof(seed), 1, f);
fclose(f);
}
- srand(seed);
- // Prepares the maze grids
- // Fills the maze with zeroes indicating that none of the grid squares have
- // been visited
- //
- // Fills the visual maze with walls
- for (int y = 0; y < sizeof(maze) / sizeof(maze[0]); y++)
- {
- for (int x = 0; x < sizeof(maze[0]) / sizeof(maze[0][0]); x++)
- {
- maze[y][x] = 0;
- }
- }
- for (int y = 0; y < sizeof(maze_visual) / sizeof(maze_visual[0]); y++)
- {
- for (int x = 0; x < sizeof(maze_visual[0]) / sizeof(maze_visual[0][0]);
- x++)
- {
- maze_visual[y][x] = wall;
- }
- }
+ srand(seed);
- // Set the start value (0, 0) and begin the algoritm loop
- stack_push(path, 0);
- int cnt = 0;
- while (1)
- {
- int pos = stack_peek(path);
- int posY, posX;
- get_maze_coords(pos, &posY, &posX);
+ int full_maze_height = maze_height * 2 + 1;
+ int full_maze_width = maze_width * 2 + 1;
- // Set the currently visited grid square to 1 indicating that it has been
- // visited and excavate the visual maze
- maze[posY][posX] = 1;
- maze_visual[posY * 2 + 1][posX * 2 + 1] = " ";
+ char ***maze = create_maze(full_maze_height, full_maze_width, wall);
- // Find out available next positions to go to
- int neighbours[3];
- int i = 0;
- if (posY != 0 && maze[posY - 1][posX] == 0)
- {
- neighbours[i] = get_maze_pos(posY - 1, posX);
- i++;
- }
- if (posY != maze_heigth - 1 && maze[posY + 1][posX] == 0)
- {
- neighbours[i] = get_maze_pos(posY + 1, posX);
- i++;
- }
- if (posX != 0 && maze[posY][posX - 1] == 0)
- {
- neighbours[i] = get_maze_pos(posY, posX - 1);
- i++;
- }
- if (posX != maze_width - 1 && maze[posY][posX + 1] == 0)
- {
- neighbours[i] = get_maze_pos(posY, posX + 1);
- i++;
- }
+ excavate_maze(maze, maze_height, maze_width);
- switch (i)
- {
- case 0:
- // No available next positions
- if (cnt == (maze_heigth * maze_width) - 1)
- {
- for (int y = 0; y < sizeof(maze_visual) / sizeof(maze_visual[0]); y++)
- {
- for (int x = 0;
- x < sizeof(maze_visual[0]) / sizeof(maze_visual[0][0]); x++)
- {
- printf("%s", maze_visual[y][x]);
- }
- printf("\n");
- }
- exit(0);
- }
- stack_pop(path);
- break;
- default:
- // Available next positions
- // Choose a random one and go there
- cnt++;
- int next = neighbours[rand() % i];
- int next_y, next_x;
- get_maze_coords(next, &next_y, &next_x);
- maze_visual[posY * 2 - (posY - next_y) + 1]
- [posX * 2 - (posX - next_x) + 1] = " ";
- stack_push(path, next);
- }
- }
+ print_maze(maze, full_maze_height, full_maze_width);
}