From 0272fd726d17dadbb9d6fc85dea834c78fa6ecbe Mon Sep 17 00:00:00 2001 From: David Baer Date: Sat, 15 Jan 2022 14:40:21 -0500 Subject: [PATCH] Add option to set random seed for deterministic behavior Bump version to 1.6 --- CMakeLists.txt | 2 +- include/mazemaker.h | 2 ++ lib/CMakeLists.txt | 1 + lib/config.h.in | 1 + lib/grid.c | 29 +++++++++++++++++++++++------ lib/grid.h | 2 +- lib/maze.c | 12 ++++++++++-- lib/options.c | 6 ++++++ lib/options.h | 4 ++++ utils/mazemaker.c | 11 +++++++++-- 10 files changed, 58 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a89ec62..1c6aca8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.0) cmake_policy(VERSION 3.0) -project (mazemaker VERSION 1.5) +project (mazemaker VERSION 1.6) SET(EXEC_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE PATH "Installation prefix for executables and object code libraries" FORCE) SET(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Installation prefix for C header files" FORCE) diff --git a/include/mazemaker.h b/include/mazemaker.h index a8cc735..883f814 100644 --- a/include/mazemaker.h +++ b/include/mazemaker.h @@ -25,6 +25,7 @@ typedef enum { typedef struct mazeoptions mazeoptions_t; void mazemaker_generate_maze(int width, int height, mazegrid_t* result); +void mazemaker_generate_maze_opt(int width, int height, mazegrid_t* result, mazeoptions_t const*); void mazemaker_free_maze(mazegrid_t* maze); int mazemaker_maze_to_png(mazegrid_t const* maze, char const* filename); int mazemaker_maze_to_png_opt(mazegrid_t const* maze, char const* filename, mazeoptions_t const*); @@ -35,5 +36,6 @@ mazeoptions_t* mazemaker_options_new(); void mazemaker_options_free(mazeoptions_t*); int mazemaker_options_set_wall_color(mazeoptions_t*, char const* color_desc); int mazemaker_options_set_background_color(mazeoptions_t*, char const* color_desc); +void mazemaker_options_set_seed(mazeoptions_t*, unsigned int seed); #endif // !def(_MAZEMAKER_H) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9756998..f4f1aa6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -15,6 +15,7 @@ find_package(PkgConfig REQUIRED) pkg_search_module(PNG REQUIRED libpng) check_symbol_exists(arc4random_uniform "stdlib.h" HAVE_ARC4RANDOM) +check_symbol_exists(srand_deterministic "stdlib.h" HAVE_SRAND_DETERMINISTIC) configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/config.h" ) diff --git a/lib/config.h.in b/lib/config.h.in index 97e0210..1326b3e 100644 --- a/lib/config.h.in +++ b/lib/config.h.in @@ -1 +1,2 @@ #cmakedefine HAVE_ARC4RANDOM @HAVE_ARC4RANDOM@ +#cmakedefine HAVE_SRAND_DETERMINISTIC @HAVE_SRAND_DETERMINISTIC@ diff --git a/lib/grid.c b/lib/grid.c index b4e2b78..465709a 100644 --- a/lib/grid.c +++ b/lib/grid.c @@ -1,5 +1,6 @@ #include #include "grid.h" +#include "options.h" #include "config.h" #define MAX_EDGE_WEIGHT 100 @@ -19,14 +20,25 @@ #define HORIZONTAL_HALF_LEFT "\xe2\x95\xb8" #define HORIZONTAL_HALF_RIGHT "\xe2\x95\xba" -static edgeweight_t random_edgeweight() { +static edgeweight_t random_edgeweight(mazeoptions_t const* options) { + if (!options->seed_set) { #ifdef HAVE_ARC4RANDOM - return arc4random_uniform(MAX_EDGE_WEIGHT); + return arc4random_uniform(MAX_EDGE_WEIGHT); #else // HAVE_ARC4RANDOM - return random()%MAX_EDGE_WEIGHT; + return random()%MAX_EDGE_WEIGHT; #endif // HAVE_ARC4RANDOM + } else { + // use deterministic random number generator + return rand()%MAX_EDGE_WEIGHT; + } } +#ifdef HAVE_SRAND_DETERMINISTIC +#define SRAND(x) (srand_deterministic(x)) +#else +#define SRAND(x) (srand(x)) +#endif // defined(HAVE_SRAND_DETERMINISTIC) + mazegrid_t mazegrid_new(size_t width, size_t height) { mazeedges_t** grid = calloc(height, sizeof(mazeedges_t*)); for (size_t i = 0; i < height; i++) { @@ -72,11 +84,16 @@ edgeweight_t mazegrid_get_edge(mazegrid_t const* g, size_t x, size_t y, mazeedge else return g->grid[y][x].up; } -void mazegrid_randomize(mazegrid_t* g) { +void mazegrid_randomize(mazegrid_t* g, mazeoptions_t const* options) { + // initialize random system + if (options->seed_set) { + SRAND(options->seed); + } + for (size_t i = 0; i < g->height; i++) { for (size_t j = 0; j < g->width; j++) { - if (i < g->height - 1) g->grid[i][j].up = random_edgeweight(); - if (j < g->width - 1) g->grid[i][j].right = random_edgeweight(); + if (i < g->height - 1) g->grid[i][j].up = random_edgeweight(options); + if (j < g->width - 1) g->grid[i][j].right = random_edgeweight(options); } } } diff --git a/lib/grid.h b/lib/grid.h index e45093d..32a04fa 100644 --- a/lib/grid.h +++ b/lib/grid.h @@ -10,7 +10,7 @@ void mazegrid_free(mazegrid_t* g); int mazegrid_set_edge(mazegrid_t* g, size_t x, size_t y, mazeedge_dir_t dir, edgeweight_t wt); edgeweight_t mazegrid_get_edge(mazegrid_t const* g, size_t, size_t y, mazeedge_dir_t dir); -void mazegrid_randomize(mazegrid_t* g); +void mazegrid_randomize(mazegrid_t* g, mazeoptions_t const* options); void mazegrid_uniform(mazegrid_t* g); void mazegrid_print(mazegrid_t const* g, FILE * f); diff --git a/lib/maze.c b/lib/maze.c index 3851c80..409abdf 100644 --- a/lib/maze.c +++ b/lib/maze.c @@ -1,13 +1,21 @@ #include +#include #include "grid.h" #include "prim.h" -void mazemaker_generate_maze(int width, int height, mazegrid_t* result) { +void mazemaker_generate_maze_opt(int width, int height, mazegrid_t* result, mazeoptions_t const* options) { mazegrid_t g = mazegrid_new(width, height); - mazegrid_randomize(&g); + mazegrid_randomize(&g, options); prim(&g, result); mazegrid_free(&g); } + +void mazemaker_generate_maze(int width, int height, mazegrid_t* result) { + mazeoptions_t* options = mazemaker_options_new(); // use defaults + mazemaker_generate_maze_opt(width, height, result, options); + mazemaker_options_free(options); +} + void mazemaker_free_maze(mazegrid_t* maze) { mazegrid_free(maze); } diff --git a/lib/options.c b/lib/options.c index 8476add..1ac7598 100644 --- a/lib/options.c +++ b/lib/options.c @@ -10,6 +10,8 @@ mazeoptions_t* mazemaker_options_new() { // set defaults memset(result->wall_color, 0, 3); memset(result->background_color, 0xff, 3); + result->seed = 0; + result->seed_set = false; return result; } @@ -78,3 +80,7 @@ int mazemaker_options_set_background_color(mazeoptions_t* options, char const* c return stringToColor(color_desc, options->background_color); } +void mazemaker_options_set_seed(mazeoptions_t* options, rand_seed_t seed) { + options->seed = seed; + options->seed_set = true; +} diff --git a/lib/options.h b/lib/options.h index 5066608..bef31c4 100644 --- a/lib/options.h +++ b/lib/options.h @@ -2,12 +2,16 @@ #define _OPTIONS_H 1 #include +#include typedef uint8_t rgb_color_t[3]; +typedef unsigned int rand_seed_t; typedef struct mazeoptions { rgb_color_t wall_color; rgb_color_t background_color; + rand_seed_t seed; + bool seed_set; } mazeoptions_t; #endif // !def(_OPTIONS_H) diff --git a/utils/mazemaker.c b/utils/mazemaker.c index 622c585..a1e9303 100644 --- a/utils/mazemaker.c +++ b/utils/mazemaker.c @@ -6,7 +6,8 @@ int main(int argc, char* argv[]) { char c; int width = 0, height = 0; - char const *filename = NULL, *fg_color = NULL, *bg_color = NULL; + unsigned int seed = 0; + char const *filename = NULL, *fg_color = NULL, *bg_color = NULL, *seed_str = NULL; struct poptOption options_table[] = { { "width", 'w', POPT_ARG_INT, &width, 0, "Width of the maze", "BLOCKS" }, @@ -16,6 +17,8 @@ int main(int argc, char* argv[]) { "Foreground (wall) color", "#rrggbb" }, { "background", 'b', POPT_ARG_STRING, &bg_color, 0, "Background color", "#rrggbb" }, + { "seed", 's', POPT_ARG_STRING, &seed_str, 0, + "Random seed", "SEED" }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; @@ -53,7 +56,11 @@ int main(int argc, char* argv[]) { exit(1); } } - mazemaker_generate_maze(width, height, &maze); + if (seed_str != NULL) { + seed = (unsigned int)atol(seed_str); + mazemaker_options_set_seed(options, seed); + } + mazemaker_generate_maze_opt(width, height, &maze, options); mazemaker_maze_to_png_opt(&maze, filename, options); mazemaker_free_maze(&maze); mazemaker_options_free(options);