#include "fmt/core.h" #include "getopt.h" #include "matrix.hpp" #include "maze.hpp" #include "stack.hpp" #include "utils.hpp" #include "vector2.hpp" #include #include #include #include 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 num_dst, char arg) { num_dst = std::make_shared(); 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 start_x = nullptr; std::shared_ptr start_y = nullptr; std::unique_ptr 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(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(random_device()); } if (start_x == nullptr) { auto random_dist = std::uniform_int_distribution(0, maze_width - 1U); start_x = std::make_unique(random_dist(*random_gen)); } if (start_y == nullptr) { auto random_dist = std::uniform_int_distribution(0, maze_height - 1U); start_y = std::make_unique(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 matrix(maze_height * 2U + 1U, maze_width * 2U + 1U); matrix.fill(wall); auto start_pos = std::make_shared(*start_x * 2U + 1U, *start_y * 2U + 1U); matrix_to_maze(&matrix, start_pos, " ", *random_gen); matrix.print(); }