diff options
author | HampusM <hampus@hampusmat.com> | 2022-01-09 21:47:23 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2022-01-09 21:47:23 +0100 |
commit | 8ceb79db1d0687bba005cef4a77bb889bf7ec3c3 (patch) | |
tree | b7c13359f652506d60c8556ea386ae8d50bfc5bc /src | |
parent | 097aa95c1f0cb159e7d9d0a3edf9284c421ee298 (diff) |
refactor: rewrite to c++
Diffstat (limited to 'src')
-rw-r--r-- | src/grid.c | 55 | ||||
-rw-r--r-- | src/grid.h | 58 | ||||
-rw-r--r-- | src/matrix.hpp | 67 | ||||
-rw-r--r-- | src/matrix.tpp | 62 | ||||
-rw-r--r-- | src/maze.c | 124 | ||||
-rw-r--r-- | src/maze.h | 15 | ||||
-rw-r--r-- | src/maze.hpp | 24 | ||||
-rw-r--r-- | src/maze.tpp | 131 | ||||
-rw-r--r-- | src/mazerator.c | 176 | ||||
-rw-r--r-- | src/mazerator.cpp | 184 | ||||
-rw-r--r-- | src/position.c | 8 | ||||
-rw-r--r-- | src/position.h | 12 | ||||
-rw-r--r-- | src/position_stack.c | 76 | ||||
-rw-r--r-- | src/position_stack.h | 26 | ||||
-rw-r--r-- | src/stack.hpp | 43 | ||||
-rw-r--r-- | src/stack.tpp | 36 | ||||
-rw-r--r-- | src/utils.c | 45 | ||||
-rw-r--r-- | src/utils.cpp | 34 | ||||
-rw-r--r-- | src/utils.h | 21 | ||||
-rw-r--r-- | src/utils.hpp | 15 | ||||
-rw-r--r-- | src/vector2.cpp | 58 | ||||
-rw-r--r-- | src/vector2.hpp | 62 |
22 files changed, 716 insertions, 616 deletions
diff --git a/src/grid.c b/src/grid.c deleted file mode 100644 index 1ad01cd..0000000 --- a/src/grid.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "grid.h" -#include "utils.h" -#include <stdio.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 = 0U; y < height; y++) - { - grid.grid[y] = malloc_s(mem_width); - - for (unsigned int x = 0U; 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 = 0U; y < grid.dimens.height; y++) - { - for (unsigned int x = 0U; 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 = 0U; y < grid.dimens.height; y++) - free(grid.grid[y]); - - free(grid.grid); -} diff --git a/src/grid.h b/src/grid.h deleted file mode 100644 index 262035e..0000000 --- a/src/grid.h +++ /dev/null @@ -1,58 +0,0 @@ -#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/matrix.hpp b/src/matrix.hpp new file mode 100644 index 0000000..83f9fc2 --- /dev/null +++ b/src/matrix.hpp @@ -0,0 +1,67 @@ +#ifndef MATRIX_HPP +#define MATRIX_HPP + +#include "vector2.hpp" +#include <vector> + +/** + * A Matrix. + */ +template <typename Element> +class Matrix +{ +public: + /** + * Creates a matrix. + * + * @param rows The number of rows of the matrix + * @param columns The number of columns of the matrix + */ + Matrix(unsigned int rows, unsigned int columns); + + /** + * Fills the matrix with a element. + * + * @param element A element + */ + void fill(Element element); + + /** + * Prints the matrix. + */ + void print(); + + /** + * Returns a element of the matrix. + * + * @param pos The position of a element + */ + Element get(Vector2 pos); + + /** + * Sets a element of the matrix. + * + * @param pos The position of a element + * @param element A new element + */ + void set(Vector2 pos, Element element); + + /** + * Returns the number of rows the matrix has. + */ + unsigned int rows(); + + /** + * Returns the number of columns the matrix has. + */ + unsigned int columns(); + +private: + std::vector<std::vector<Element>> _matrix; + unsigned int _rows; + unsigned int _columns; +}; + +#include "matrix.tpp" + +#endif diff --git a/src/matrix.tpp b/src/matrix.tpp new file mode 100644 index 0000000..b9fa495 --- /dev/null +++ b/src/matrix.tpp @@ -0,0 +1,62 @@ +#include "matrix.hpp" +#include <iostream> + +template <typename Element> +Matrix<Element>::Matrix(unsigned int rows, unsigned int columns) +{ + _rows = rows; + _columns = columns; + + _matrix.reserve(rows); + _matrix.assign(_matrix.capacity(), std::vector<Element>(columns)); +}; + +template <typename Element> +void Matrix<Element>::fill(Element element) +{ + for (unsigned int row = 0U; row < _matrix.capacity(); row++) + { + std::vector<Element> row_vector = _matrix[row]; + + for (unsigned int column = 0U; column < row_vector.capacity(); column++) + _matrix[row][column] = element; + } +} + +template <typename Element> +void Matrix<Element>::print() +{ + for (std::vector<Element> row : _matrix) + { + for (Element element : row) + std::cout << element; + + std::cout << "\n"; + } + + std::cout << std::flush; +} + +template <typename Element> +Element Matrix<Element>::get(Vector2 pos) +{ + return _matrix[pos.y()][pos.x()]; +} + +template <typename Element> +void Matrix<Element>::set(Vector2 pos, Element element) +{ + _matrix[pos.y()][pos.x()] = element; +} + +template <typename Element> +unsigned int Matrix<Element>::rows() +{ + return _rows; +} + +template <typename Element> +unsigned int Matrix<Element>::columns() +{ + return _columns; +} diff --git a/src/maze.c b/src/maze.c deleted file mode 100644 index 76775b2..0000000 --- a/src/maze.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "maze.h" -#include "grid.h" -#include "position.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -int is_pos_empty(Grid grid, Position pos) -{ - return strcmp(grid_get(grid, pos), " ") != 0; -} - -void add_neighbour(Position neighbours[3], unsigned int *neighbour_cnt, - Position neighbour_pos) -{ - neighbours[*neighbour_cnt] = neighbour_pos; - (*neighbour_cnt)++; -} - -void get_neighbours(Grid grid, Position pos, Position neighbours[3], - unsigned int *neighbour_cnt) -{ - if (pos.y != 1U) - { - Position pos_down = position_create(pos.x, pos.y - 2U); - - if (is_pos_empty(grid, pos_down)) - add_neighbour(neighbours, neighbour_cnt, pos_down); - } - - if (pos.y != grid.dimens.height - 2U) - { - Position pos_up = position_create(pos.x, pos.y + 2U); - - if (is_pos_empty(grid, pos_up)) - add_neighbour(neighbours, neighbour_cnt, pos_up); - } - - if (pos.x != 1U) - { - Position pos_left = position_create(pos.x - 2U, pos.y); - - if (is_pos_empty(grid, pos_left)) - add_neighbour(neighbours, neighbour_cnt, pos_left); - } - - if (pos.x != grid.dimens.width - 2U) - { - Position pos_right = position_create(pos.x + 2U, pos.y); - - if (is_pos_empty(grid, pos_right)) - add_neighbour(neighbours, neighbour_cnt, pos_right); - } -} - -unsigned int get_maze_size(Grid grid) -{ - return ((grid.dimens.width - 1U) / 2U) * ((grid.dimens.height - 1U) / 2U); -} - -int is_whole_maze_visited(Grid grid, unsigned int visited_pos_cnt) -{ - return visited_pos_cnt == get_maze_size(grid) - 1U; -} - -void grid_to_maze(Grid grid, Position start_pos) -{ - PositionStack *path = pos_stack_create(get_maze_size(grid)); - - pos_stack_push(path, start_pos); - - unsigned int visited_pos_cnt = 0U; - while (1) - { - Position pos = pos_stack_peek(path); - - grid_set(grid, pos, " "); - - Position neighbours[3]; - unsigned int neighbour_cnt = 0U; - - get_neighbours(grid, pos, neighbours, &neighbour_cnt); - - if (neighbour_cnt == 0U) - { - if (is_whole_maze_visited(grid, visited_pos_cnt)) - break; - - // Go back a step - pos_stack_pop(path); - continue; - } - - visited_pos_cnt++; - - Position next_pos = neighbours[rand() % neighbour_cnt]; - - Position between_pos = position_create(pos.x, pos.y); - - if (next_pos.y != pos.y) - { - if (next_pos.y > pos.y) - between_pos.y += 1U; - else - between_pos.y -= 1U; - } - - if (next_pos.x != pos.x) - { - if (next_pos.x > pos.x) - between_pos.x += 1U; - else - between_pos.x -= 1U; - } - - grid_set(grid, between_pos, " "); - - pos_stack_push(path, next_pos); - - // grid_print(grid); - } - - pos_stack_destroy(path); -} diff --git a/src/maze.h b/src/maze.h deleted file mode 100644 index a3c932c..0000000 --- a/src/maze.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MAZE_H -#define MAZE_H - -#include "grid.h" -#include "position_stack.h" - -/** - * Creates a maze from a grid - * - * @param grid A grid - * @param start_pos Start position - */ -void grid_to_maze(Grid grid, Position start_pos); - -#endif diff --git a/src/maze.hpp b/src/maze.hpp new file mode 100644 index 0000000..0ff1d06 --- /dev/null +++ b/src/maze.hpp @@ -0,0 +1,24 @@ +#ifndef MAZE_HPP +#define MAZE_HPP + +#include "matrix.hpp" +#include "vector2.hpp" +#include <memory> +#include <random> +#include <string> + +/** + * Turns a matrix into a maze. + * + * @param matrix A matrix + * @param start_pos The start position in the matrix + * @param space_element A matrix element used to indicate a space in a maze + * @param random_gen A pseudo-random number generator + */ +template <typename Element> +void matrix_to_maze(Matrix<Element> *matrix, std::shared_ptr<Vector2> start_pos, + Element space_element, std::mt19937 random_gen); + +#include "maze.tpp" + +#endif diff --git a/src/maze.tpp b/src/maze.tpp new file mode 100644 index 0000000..6c4fd71 --- /dev/null +++ b/src/maze.tpp @@ -0,0 +1,131 @@ +#include "matrix.hpp" +#include "maze.hpp" +#include "stack.hpp" +#include <vector> + +/** + * Returns the neighbours of a position in a maze. + * + * @param matrix A matrix + * @param pos A matrix position + * @param space_element A matrix element used to indicate a space in a maze + */ +template <typename Element> +std::vector<std::shared_ptr<Vector2>> get_neighbours(Matrix<Element> *matrix, + std::shared_ptr<Vector2> pos, + Element space_element) +{ + std::vector<std::shared_ptr<Vector2>> neighbours; + neighbours.reserve(3); + + if (pos->y() != 1U) + { + auto pos_down = (*pos - Vector2(0U, 2U)).copy(); + + if (matrix->get(*pos_down) != space_element) + neighbours.push_back(pos_down); + } + + if (pos->y() != matrix->rows() - 2U) + { + auto pos_up = (*pos + Vector2(0U, 2U)).copy(); + + if (matrix->get(*pos_up) != space_element) + neighbours.push_back(pos_up); + } + + if (pos->x() != 1U) + { + auto pos_left = (*pos - Vector2(2U, 0U)).copy(); + + if (matrix->get(*pos_left) != space_element) + neighbours.push_back(pos_left); + } + + if (pos->x() != matrix->columns() - 2U) + { + auto pos_right = (*pos + Vector2(2U, 0U)).copy(); + + if (matrix->get(*pos_right) != space_element) + neighbours.push_back(pos_right); + } + + return neighbours; +} + +/** + * Returns the logical size of a maze for a matrix. + * + * @param matrix A matrix + */ +template <typename Element> +unsigned int get_maze_size(Matrix<Element> *matrix) +{ + return ((matrix->columns() - 1U) / 2U) * ((matrix->rows() - 1U) / 2U); +} + +/** + * Makes a position be between two coordinates with a differential vector. + * + * @param between_pos Target position + * @param coord A coordinate + * @param coord A second coordinate that must not be equal too the first + * @param diff A differential vector to apply to the target position + */ +void pos_to_between(std::shared_ptr<Vector2> between_pos, unsigned int coord, + unsigned int away_coord, Vector2 diff) +{ + if (away_coord > coord) + *between_pos += diff; + else + *between_pos -= diff; +} + +template <typename Element> +void matrix_to_maze(Matrix<Element> *matrix, std::shared_ptr<Vector2> start_pos, + Element space_element, std::mt19937 random_gen) +{ + Stack<std::shared_ptr<Vector2>> path_stack(get_maze_size(matrix)); + + path_stack.push(start_pos); + + unsigned int visited_pos_cnt = 0U; + while (1) + { + auto pos = path_stack.peek(); + + matrix->set(*pos, space_element); + + std::vector<std::shared_ptr<Vector2>> neighbours = + get_neighbours(matrix, pos, space_element); + + if (neighbours.empty()) + { + if (visited_pos_cnt == get_maze_size(matrix) - 1U) + break; + + // Go back a step + path_stack.pop(); + continue; + } + + visited_pos_cnt++; + + auto random_dist = + std::uniform_int_distribution<unsigned int>(0U, neighbours.size() - 1UL); + + auto next_pos = neighbours[random_dist(random_gen)]; + + auto between_pos = pos->copy(); + + if (next_pos->y() != pos->y()) + pos_to_between(between_pos, pos->y(), next_pos->y(), Vector2(0U, 1U)); + + if (next_pos->x() != pos->x()) + pos_to_between(between_pos, pos->x(), next_pos->x(), Vector2(1U, 0U)); + + matrix->set(*between_pos, space_element); + + path_stack.push(next_pos); + } +} diff --git a/src/mazerator.c b/src/mazerator.c deleted file mode 100644 index 9926c1e..0000000 --- a/src/mazerator.c +++ /dev/null @@ -1,176 +0,0 @@ -#include "grid.h" -#include "maze.h" -#include "position.h" -#include "utils.h" -#include <getopt.h> -#include <stdio.h> -#include <stdlib.h> - -void optarg_error(char arg, char *error) -{ - printf("Error: Invalid option argument for -%c. %s\n", arg, error); - exit(EXIT_FAILURE); -} - -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"; - - if (start_x > width) - { - printf(error_format, "x", "width"); - exit(EXIT_FAILURE); - } - - if (start_y > height) - { - printf(error_format, "y", "height"); - exit(EXIT_FAILURE); - } -} - -void get_seed(unsigned int *seed_dst) -{ - FILE *urandom = fopen("/dev/urandom", "r"); - fread(seed_dst, sizeof(*seed_dst), 1, urandom); - fclose(urandom); -} - -const struct option options[] = {{"width", required_argument, NULL, 'w'}, - {"heigth", 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; - - unsigned int *start_x = NULL; - unsigned int *start_y = NULL; - - unsigned int *seed = NULL; - - char *wall = "█"; - - int arg; - while ((arg = getopt_long(argc, argv, "w:h:W:s:x:y:", options, NULL)) != -1) - { - char *err = NULL; - - switch (arg) - { - case 'w': - maze_width = str_to_uint(optarg, &err); - - if (err != NULL) - optarg_error(arg, err); - - if (maze_width == 0) - optarg_error(arg, "It should not be 0"); - - break; - case 'h': - maze_height = str_to_uint(optarg, &err); - - if (err != NULL) - optarg_error(arg, err); - - if (maze_height == 0) - optarg_error(arg, "It should not be 0"); - - break; - case 'x': - start_x = malloc_s(sizeof(unsigned int *)); - *start_x = str_to_uint(optarg, &err); - - if (err != NULL) - optarg_error(arg, err); - - break; - case 'y': - start_y = malloc_s(sizeof(unsigned int *)); - *start_y = str_to_uint(optarg, &err); - - if (err != NULL) - optarg_error(arg, err); - - break; - case 'W': - wall = optarg; - break; - case 's': - seed = malloc_s(sizeof(unsigned int *)); - *seed = str_to_uint(optarg, &err); - - if (err != NULL) - optarg_error(arg, err); - - if (*seed == 0) - optarg_error(arg, "It should not be 0"); - - break; - case 0: - printf("Usage: %s [OPTION]...\n\n" - "Options:\n" - " -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: 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\n", - argv[0]); - exit(0); - case '?': - printf("\nTry '%s --help' for more information\n", argv[0]); - exit(EXIT_FAILURE); - } - } - - if (seed == NULL) - { - seed = malloc_s(sizeof(unsigned int *)); - get_seed(seed); - } - - srand(*seed); - free(seed); - - if (start_x == NULL) - { - start_x = malloc_s(sizeof(unsigned int *)); - *start_x = rand() % maze_width; - } - - if (start_y == NULL) - { - start_y = malloc_s(sizeof(unsigned int *)); - *start_y = rand() % maze_height; - } - - validate_start_coords(*start_x, *start_y, maze_width, maze_height); - - Position start_pos = position_create(*start_x * 2U + 1U, *start_y * 2U + 1U); - - Grid grid = grid_create(maze_width * 2U + 1U, maze_height * 2U + 1U, wall); - - grid_to_maze(grid, start_pos); - - grid_print(grid); - - grid_destroy(grid); - - free(start_x); - free(start_y); -} 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(); +} diff --git a/src/position.c b/src/position.c deleted file mode 100644 index a7465ab..0000000 --- a/src/position.c +++ /dev/null @@ -1,8 +0,0 @@ -#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 deleted file mode 100644 index 05d21fa..0000000 --- a/src/position.h +++ /dev/null @@ -1,12 +0,0 @@ -#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 deleted file mode 100644 index 0b4895a..0000000 --- a/src/position_stack.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "position_stack.h" -#include "utils.h" -#include <stdio.h> -#include <stdlib.h> - -// Error handler for stack errors -void stack_error(int err) -{ - switch (err) - { - case STACK_ERR_OVERFLOW: - printf("Error: Stack overflow\nBe kind and report this problem."); - break; - case STACK_ERR_UNDERFLOW: - printf("Error: Stack underflow\nBe kind and report this problem."); - break; - } - - exit(1); -} - -// Creates a new stack -PositionStack *pos_stack_create(unsigned int capacity) -{ - PositionStack *pos_stack = malloc_s(sizeof(PositionStack)); - - pos_stack->capacity = capacity; - pos_stack->top = -1; - pos_stack->items = malloc_s(sizeof(Position) * capacity); - - return pos_stack; -} - -void pos_stack_destroy(PositionStack *pos_stack) -{ - free(pos_stack->items); - free(pos_stack); -} - -// Adds a new item to a stack -void pos_stack_push(PositionStack *pos_stack, Position pos) -{ - // Avoid a overflow by checking if the stack is full - if (pos_stack->top == pos_stack->capacity - 1U) - { - stack_error(STACK_ERR_OVERFLOW); - } - - // Add an element and increase the top index - pos_stack->items[++pos_stack->top] = pos; -} - -// Returns the topmost item of a stack -Position pos_stack_peek(PositionStack *pos_stack) -{ - // Avoid a underflow by checking if the stack is empty - if (pos_stack->top == -1) - { - stack_error(STACK_ERR_UNDERFLOW); - } - - return pos_stack->items[pos_stack->top]; -} - -// Deletes the topmost item of a stack -Position pos_stack_pop(PositionStack *pos_stack) -{ - // Avoid a underflow by checking if the stack is empty - if (pos_stack->top == -1) - { - stack_error(STACK_ERR_UNDERFLOW); - } - - // Decrease the stack size by 1 and return the popped element - return pos_stack->items[pos_stack->top--]; -} diff --git a/src/position_stack.h b/src/position_stack.h deleted file mode 100644 index 674da23..0000000 --- a/src/position_stack.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef POSITION_STACK_H -#define POSITION_STACK_H - -#include "position.h" - -#define STACK_ERR_OVERFLOW 0xFFF01 -#define STACK_ERR_UNDERFLOW 0xFFF02 - -typedef struct PositionStack -{ - unsigned int capacity; - int top; - Position *items; -} PositionStack; - -PositionStack *pos_stack_create(unsigned int capacity); - -void pos_stack_destroy(PositionStack *pos_stack); - -void pos_stack_push(PositionStack *pos_stack, Position pos); - -Position pos_stack_peek(PositionStack *pos_stack); - -Position pos_stack_pop(PositionStack *pos_stack); - -#endif diff --git a/src/stack.hpp b/src/stack.hpp new file mode 100644 index 0000000..b156242 --- /dev/null +++ b/src/stack.hpp @@ -0,0 +1,43 @@ +#ifndef STACK_HPP +#define STACK_HPP + +#include <vector> + +/** + * A stack data structure. + */ +template <typename Item> +class Stack +{ +public: + /** + * Creates a stack. + * + * @param capacity The capacity of the stack + */ + Stack(int capacity); + + /** + * Pushes a item onto the stack. + */ + void push(Item item); + + /** + * Pops the topmost item from the stack. + */ + void pop(); + + /** + * Peeks into the stack. + * + * @returns The topmost stack item. + */ + Item peek(); + +private: + std::vector<Item> _items; +}; + +#include "stack.tpp" + +#endif diff --git a/src/stack.tpp b/src/stack.tpp new file mode 100644 index 0000000..958d6ca --- /dev/null +++ b/src/stack.tpp @@ -0,0 +1,36 @@ +#include "stack.hpp" +#include <iostream> +#include <stdexcept> + +template <typename Item> +Stack<Item>::Stack(int capacity) +{ + _items.reserve(capacity); +} + +template <typename Item> +void Stack<Item>::push(Item item) +{ + if (_items.size() == _items.capacity()) + throw std::overflow_error("Tried to push when stack is full"); + + _items.push_back(item); +} + +template <typename Item> +void Stack<Item>::pop() +{ + if (_items.size() == 0) + throw std::underflow_error("Tried to pop when stack size is 0"); + + _items.pop_back(); +} + +template <typename Item> +Item Stack<Item>::peek() +{ + if (_items.size() == 0) + throw std::underflow_error("Tried to peek when stack size is 0"); + + return _items.back(); +} diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index fa33cb0..0000000 --- a/src/utils.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "utils.h" -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -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 = "Less than 0"; - return 0; - } - - char *str_waste; - unsigned long num = strtoul(str, &str_waste, 10); - - if (strlen(str_waste) != 0UL) - { - *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.cpp b/src/utils.cpp new file mode 100644 index 0000000..30ff4ec --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,34 @@ +#include "utils.hpp" +#include <climits> +#include <stdexcept> + +unsigned int str_to_uint(std::string str) +{ + if (str.at(0) == '-') + throw "Less than 0"; + + std::size_t waste_pos; + + unsigned long num; + + try + { + num = std::stoul(str, &waste_pos, 10); + } + catch (const std::invalid_argument &exc) + { + throw "Not a number"; + } + catch (const std::out_of_range &exc) + { + throw "Out of range"; + } + + if (waste_pos != str.length()) + throw "Not a number"; + + if (num > (unsigned long)UINT_MAX) + throw "Out of range"; + + return (unsigned int)num; +} diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 2f36034..0000000 --- a/src/utils.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -/** - * 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 diff --git a/src/utils.hpp b/src/utils.hpp new file mode 100644 index 0000000..91a1d8e --- /dev/null +++ b/src/utils.hpp @@ -0,0 +1,15 @@ +#ifndef UTILS_HPP +#define UTILS_HPP + +#include <memory> +#include <string> + +/** + * Converts a string to a unsigned integer. + * + * @param str A string that possibly is a unsigned integer + * @returns A unsigned integer + */ +unsigned int str_to_uint(std::string str); + +#endif diff --git a/src/vector2.cpp b/src/vector2.cpp new file mode 100644 index 0000000..effc8b5 --- /dev/null +++ b/src/vector2.cpp @@ -0,0 +1,58 @@ +#include "vector2.hpp" + +Vector2::Vector2(unsigned int x, unsigned int y) +{ + _x = x; + _y = y; +} + +unsigned int Vector2::x() const +{ + return _x; +} + +void Vector2::x(unsigned int x) +{ + _x = x; +} + +unsigned int Vector2::y() const +{ + return _y; +} + +void Vector2::y(unsigned int y) +{ + _y = y; +} + +std::shared_ptr<Vector2> Vector2::copy() +{ + return std::shared_ptr<Vector2>(new Vector2(*this)); +} + +Vector2 Vector2::operator+(const Vector2 vector2) +{ + return Vector2(_x + vector2.x(), _y + vector2.y()); +} + +Vector2 Vector2::operator-(const Vector2 vector2) +{ + return Vector2(_x - vector2.x(), _y - vector2.y()); +} + +Vector2 &Vector2::operator+=(const Vector2 &vector2) +{ + _x += vector2.x(); + _y += vector2.y(); + + return *this; +} + +Vector2 &Vector2::operator-=(const Vector2 &vector2) +{ + _x -= vector2.x(); + _y -= vector2.y(); + + return *this; +} diff --git a/src/vector2.hpp b/src/vector2.hpp new file mode 100644 index 0000000..ccfa75b --- /dev/null +++ b/src/vector2.hpp @@ -0,0 +1,62 @@ +#ifndef VECTOR2_HPP +#define VECTOR2_HPP + +#include <memory> + +/** + * A 2D Vector. + */ +class Vector2 +{ +public: + /** + * Creates a 2D vector. + * + * @param x A X coordinate + * @param y A Y coordinate + */ + Vector2(unsigned int x, unsigned int y); + + /** + * Returns the X coordinate. + */ + unsigned int x() const; + + /** + * Sets the X coordinate. + * + * @param x A new X coordinate + */ + void x(unsigned int x); + + /** + * Returns the Y coordinate. + */ + unsigned int y() const; + + /** + * Sets the Y coordinate. + * + * @param Y A new Y coordinate + */ + void y(unsigned int y); + + /** + * Creates a copy of the 2D vector. + * + * @returns A identical 2D vector. + */ + std::shared_ptr<Vector2> copy(); + + Vector2 operator+(const Vector2 vector2); + Vector2 operator-(const Vector2 vector2); + + Vector2 &operator+=(const Vector2 &vector2); + Vector2 &operator-=(const Vector2 &vector2); + +private: + unsigned int _x; + unsigned int _y; +}; + +#endif |