diff options
Diffstat (limited to 'src/mazerator.cpp')
-rw-r--r-- | src/mazerator.cpp | 184 |
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(); +} |