aboutsummaryrefslogtreecommitdiff
path: root/src/mazerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mazerator.cpp')
-rw-r--r--src/mazerator.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/mazerator.cpp b/src/mazerator.cpp
new file mode 100644
index 0000000..0927b4c
--- /dev/null
+++ b/src/mazerator.cpp
@@ -0,0 +1,184 @@
+#include "fmt/core.h"
+#include "getopt.h"
+#include "matrix.hpp"
+#include "maze.hpp"
+#include "stack.hpp"
+#include "utils.hpp"
+#include "vector2.hpp"
+#include <iostream>
+#include <memory>
+#include <random>
+#include <string>
+
+void optarg_error(char arg, std::string error)
+{
+ std::cout << fmt::format("Error: Invalid option argument for -{}. {}", arg, error)
+ << std::endl;
+ exit(EXIT_FAILURE);
+}
+
+void validate_start_coords(unsigned int start_x, unsigned int start_y, unsigned int width,
+ unsigned int height)
+{
+ std::string error_format =
+ "The {} start coordinate cannot be higher than or equal to the maze's {}";
+
+ if (start_x >= width)
+ throw fmt::format(error_format, "x", "width");
+
+ if (start_y >= height)
+ throw fmt::format(error_format, "y", "height");
+}
+
+/**
+ * Parses a unsigned integer command-line argument.
+ *
+ * @param num_dst A pointer to a place to store the result value
+ * @param arg The command-line argument character
+ * @param check_zero Whether or not to make sure that the result is not zero
+ */
+void parse_uint_arg(unsigned int *num_dst, char arg, bool check_zero = false)
+{
+ try
+ {
+ *num_dst = str_to_uint(std::string(optarg));
+
+ if (check_zero && *num_dst == 0)
+ throw "It should not be 0";
+ }
+ catch (const char *error)
+ {
+ optarg_error(arg, std::string(error));
+ }
+}
+
+/**
+ * Parses a unsigned integer command-line argument.
+ *
+ * @param num_dst A shared pointer to a place to store the result value
+ * @param arg The command-line argument character
+ */
+void parse_uint_arg(std::shared_ptr<unsigned int> num_dst, char arg)
+{
+ num_dst = std::make_shared<unsigned int>();
+
+ parse_uint_arg(num_dst.get(), arg);
+}
+
+const struct option options[] = {{"width", required_argument, NULL, 'w'},
+ {"height", required_argument, NULL, 'h'},
+ {"wall", required_argument, NULL, 'W'},
+ {"seed", required_argument, NULL, 's'},
+ {"start-x", required_argument, NULL, 'x'},
+ {"start-y", required_argument, NULL, 'y'},
+ {"help", no_argument, NULL, 0},
+ {NULL, 0, NULL, 0}};
+
+int main(int argc, char *argv[])
+{
+ unsigned int maze_width = 40U;
+ unsigned int maze_height = 20U;
+
+ std::shared_ptr<unsigned int> start_x = nullptr;
+ std::shared_ptr<unsigned int> start_y = nullptr;
+
+ std::unique_ptr<std::mt19937> random_gen = nullptr;
+
+ std::string wall = "█";
+
+ int arg;
+ while ((arg = getopt_long(argc, argv, "w:h:W:s:x:y:", options, nullptr)) != -1)
+ {
+ switch (arg)
+ {
+ case 'w':
+ parse_uint_arg(&maze_width, arg, true);
+ break;
+ case 'h':
+ parse_uint_arg(&maze_height, arg, true);
+ break;
+ case 'x':
+ parse_uint_arg(start_x, arg);
+ break;
+ case 'y':
+ parse_uint_arg(start_y, arg);
+ break;
+ case 'W':
+ wall = optarg;
+ break;
+ case 's':
+ unsigned int seed;
+ parse_uint_arg(&seed, arg, true);
+
+ random_gen = std::make_unique<std::mt19937>(seed);
+ break;
+ case 0:
+ std::cout
+ << fmt::format(
+ "Usage: {} [OPTION]...\n\n"
+ "Options:\n"
+ " -w, --width WIDTH The width of the maze (Default: 40)\n"
+ " -h, --height HEIGHT The height of the maze (Default: 20)\n"
+ " -x, --start-x X The x coordinate for the start "
+ "position "
+ "(Default: random)\n"
+ " -y, --start-y Y The y coordinate for the start "
+ "position "
+ "(Default: random)\n"
+ " -W, --wall WALL Single character used as maze walls "
+ "(Default: '█')\n"
+ " -s, --seed SEED The randomization seed used for maze "
+ "generation\n"
+ " --help Displays usage information",
+ argv[0])
+ << std::endl;
+ exit(0);
+ case '?':
+ std::cout << fmt::format("\nTry '{} --help' for more information", argv[0])
+ << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (random_gen == nullptr)
+ {
+ std::random_device random_device;
+ random_gen = std::make_unique<std::mt19937>(random_device());
+ }
+
+ if (start_x == nullptr)
+ {
+ auto random_dist =
+ std::uniform_int_distribution<unsigned int>(0, maze_width - 1U);
+
+ start_x = std::make_unique<unsigned int>(random_dist(*random_gen));
+ }
+
+ if (start_y == nullptr)
+ {
+ auto random_dist =
+ std::uniform_int_distribution<unsigned int>(0, maze_height - 1U);
+
+ start_y = std::make_unique<unsigned int>(random_dist(*random_gen));
+ }
+
+ try
+ {
+ validate_start_coords(*start_x, *start_y, maze_width, maze_height);
+ }
+ catch (std::string error)
+ {
+ std::cout << "Error: " << error << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ Matrix<std::string> matrix(maze_height * 2U + 1U, maze_width * 2U + 1U);
+
+ matrix.fill(wall);
+
+ auto start_pos = std::make_shared<Vector2>(*start_x * 2U + 1U, *start_y * 2U + 1U);
+
+ matrix_to_maze<std::string>(&matrix, start_pos, " ", *random_gen);
+
+ matrix.print();
+}