First version - it works
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,3 +9,5 @@ config.h
|
|||||||
install_manifest.txt
|
install_manifest.txt
|
||||||
mazemaker
|
mazemaker
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
*.png
|
||||||
|
logs
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
cmake_minimum_required (VERSION 2.8.12)
|
cmake_minimum_required (VERSION 2.8.12)
|
||||||
project (mazemaker)
|
project (mazemaker)
|
||||||
set(CMAKE_C_FLAGS "-Wall -O2 -g")
|
set(CMAKE_C_FLAGS "-Wall -O2 -g")
|
||||||
set (VERSION_MAJOR 0)
|
set (VERSION_MAJOR 1)
|
||||||
set (VERSION_MINOR 1)
|
set (VERSION_MINOR 0)
|
||||||
|
|
||||||
configure_file (
|
configure_file (
|
||||||
"${PROJECT_SOURCE_DIR}/config.h.in"
|
"${PROJECT_SOURCE_DIR}/config.h.in"
|
||||||
@@ -12,6 +12,7 @@ configure_file (
|
|||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_search_module(POPT REQUIRED popt)
|
pkg_search_module(POPT REQUIRED popt)
|
||||||
|
pkg_search_module(PNG REQUIRED libpng)
|
||||||
|
|
||||||
include_directories("${PROJECT_BINARY_DIR}")
|
include_directories("${PROJECT_BINARY_DIR}")
|
||||||
|
|
||||||
@@ -20,10 +21,10 @@ file(GLOB_RECURSE SOURCES src/*.c src/*.h)
|
|||||||
add_executable (mazemaker ${SOURCES})
|
add_executable (mazemaker ${SOURCES})
|
||||||
install (TARGETS mazemaker DESTINATION bin)
|
install (TARGETS mazemaker DESTINATION bin)
|
||||||
|
|
||||||
target_link_libraries(mazemaker PUBLIC ${POPT_LIBRARIES})
|
target_link_libraries(mazemaker PUBLIC ${POPT_LIBRARIES} ${PNG_LIBRARIES} m)
|
||||||
target_include_directories(mazemaker PUBLIC ${POPT_INCLUDE_DIRS})
|
target_include_directories(mazemaker PUBLIC ${POPT_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS})
|
||||||
target_compile_options(mazemaker PUBLIC ${POPT_CFLAGS_OTHER})
|
target_compile_options(mazemaker PUBLIC ${POPT_CFLAGS_OTHER} ${PNG_CFLAGS_OTHER})
|
||||||
target_link_options(mazemaker PUBLIC -L${POPT_LIBDIR})
|
target_link_options(mazemaker PUBLIC -L${POPT_LIBDIR} -L${PNG_LIBDIR})
|
||||||
|
|
||||||
set(
|
set(
|
||||||
CPACK_SOURCE_PACKAGE_FILE_NAME
|
CPACK_SOURCE_PACKAGE_FILE_NAME
|
||||||
|
|||||||
120
src/grid.c
120
src/grid.c
@@ -2,6 +2,21 @@
|
|||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
|
|
||||||
#define MAX_EDGE_WEIGHT 100
|
#define MAX_EDGE_WEIGHT 100
|
||||||
|
#define TOP_LEFT_CORNER "\xe2\x94\x8f"
|
||||||
|
#define TOP_RIGHT_CORNER "\xe2\x94\x93"
|
||||||
|
#define BOTTOM_LEFT_CORNER "\xe2\x94\x97"
|
||||||
|
#define BOTTOM_RIGHT_CORNER "\xe2\x94\x9b"
|
||||||
|
#define HORIZONTAL_BAR "\xe2\x94\x81"
|
||||||
|
#define VERTICAL_BAR "\xe2\x94\x83"
|
||||||
|
#define TOP_TEE "\xe2\x94\xb3"
|
||||||
|
#define BOTTOM_TEE "\xe2\x94\xbb"
|
||||||
|
#define LEFT_TEE "\xe2\x94\xa3"
|
||||||
|
#define RIGHT_TEE "\xe2\x94\xab"
|
||||||
|
#define CROSS "\xe2\x95\x8b"
|
||||||
|
#define VERTICAL_HALF_BOTTOM "\xe2\x95\xbb"
|
||||||
|
#define VERTICAL_HALF_TOP "\xe2\x95\xb9"
|
||||||
|
#define HORIZONTAL_HALF_LEFT "\xe2\x95\xb8"
|
||||||
|
#define HORIZONTAL_HALF_RIGHT "\xe2\x95\xba"
|
||||||
|
|
||||||
mazegrid_t mazegrid_new(size_t width, size_t height) {
|
mazegrid_t mazegrid_new(size_t width, size_t height) {
|
||||||
mazeedges_t** grid = calloc(height, sizeof(mazeedges_t*));
|
mazeedges_t** grid = calloc(height, sizeof(mazeedges_t*));
|
||||||
@@ -57,14 +72,117 @@ void mazegrid_randomize(mazegrid_t* g) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mazegrid_uniform(mazegrid_t* g) {
|
||||||
|
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 = (int)(255.0 - (i - g->height / 2) * (i - g->height / 2) * (255.0 * 4 / (g->height * g->height)));
|
||||||
|
if (j < g->width - 1) g->grid[i][j].right = (int)(255.0 - (j - g->width / 2) * (j - g->width / 2) * (255.0 * 4 / (g->width * g->width)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mazegrid_print(mazegrid_t const* g, FILE * f) {
|
void mazegrid_print(mazegrid_t const* g, FILE * f) {
|
||||||
|
fprintf(f, TOP_LEFT_CORNER);
|
||||||
|
for (size_t i = 0; i < g->width; i++) {
|
||||||
|
fprintf(f, HORIZONTAL_BAR);
|
||||||
|
if (i == g->width - 1) fprintf(f, HORIZONTAL_HALF_LEFT);
|
||||||
|
else if (mazegrid_get_edge(g, i, g->height - 1, EDGE_RIGHT)) fprintf(f, HORIZONTAL_BAR);
|
||||||
|
else fprintf(f, TOP_TEE);
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
|
|
||||||
size_t row = g->height - 1;
|
size_t row = g->height - 1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
if (row > 0) fprintf(f, VERTICAL_BAR);
|
||||||
|
else fprintf(f, " ");
|
||||||
for (size_t col = 0; col < g->width; col++) {
|
for (size_t col = 0; col < g->width; col++) {
|
||||||
fprintf(f, "%4u,%3u", g->grid[row][col].up, g->grid[row][col].right);
|
if ((row == g->height - 1) && (col == g->width - 1)) fprintf(f, " ");
|
||||||
|
else if (col == g->width - 1) fprintf(f, " " VERTICAL_BAR);
|
||||||
|
else if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) fprintf(f, " ");
|
||||||
|
else fprintf(f, " " VERTICAL_BAR);
|
||||||
}
|
}
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
if (row == 0) break;
|
if (row == 0) break;
|
||||||
row--;
|
row--;
|
||||||
|
if (mazegrid_get_edge(g, 0, row, EDGE_UP)) fprintf(f, VERTICAL_BAR);
|
||||||
|
else if (row > 0) fprintf(f, LEFT_TEE);
|
||||||
|
else fprintf(f, BOTTOM_LEFT_CORNER);
|
||||||
|
for (size_t col = 0; col < g->width - 1; col++) {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_UP)) fprintf(f, " ");
|
||||||
|
else fprintf(f, HORIZONTAL_BAR);
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_UP)) {
|
||||||
|
if (mazegrid_get_edge(g, col, row + 1, EDGE_RIGHT)) {
|
||||||
|
if (mazegrid_get_edge(g, col + 1, row, EDGE_UP)) {
|
||||||
|
fprintf(f, VERTICAL_HALF_BOTTOM);
|
||||||
|
} else {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) {
|
||||||
|
fprintf(f, HORIZONTAL_HALF_RIGHT);
|
||||||
|
} else fprintf(f, TOP_LEFT_CORNER);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mazegrid_get_edge(g, col + 1, row, EDGE_UP)) {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) {
|
||||||
|
fprintf(f, VERTICAL_HALF_TOP);
|
||||||
|
} else fprintf(f, VERTICAL_BAR);
|
||||||
|
} else {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) {
|
||||||
|
fprintf(f, BOTTOM_LEFT_CORNER);
|
||||||
|
} else fprintf(f, LEFT_TEE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mazegrid_get_edge(g, col, row + 1, EDGE_RIGHT)) {
|
||||||
|
if (mazegrid_get_edge(g, col + 1, row, EDGE_UP)) {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) {
|
||||||
|
fprintf(f, HORIZONTAL_HALF_LEFT);
|
||||||
|
} else fprintf(f, TOP_RIGHT_CORNER);
|
||||||
|
} else {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) {
|
||||||
|
fprintf(f, HORIZONTAL_BAR);
|
||||||
|
} else fprintf(f, TOP_TEE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mazegrid_get_edge(g, col + 1, row, EDGE_UP)) {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) {
|
||||||
|
fprintf(f, BOTTOM_RIGHT_CORNER);
|
||||||
|
} else fprintf(f, RIGHT_TEE);
|
||||||
|
} else {
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_RIGHT)) {
|
||||||
|
fprintf(f, BOTTOM_TEE);
|
||||||
|
} else fprintf(f, CROSS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if (mazegrid_get_edge(g, col, row, EDGE_UP)) {
|
||||||
|
fprintf(f, " ");
|
||||||
|
if (mazegrid_get_edge(g, col + 1, row, EDGE_UP)) fprintf(f, VERTICAL_BAR);
|
||||||
|
else {
|
||||||
|
fprintf(f, TOP_LEFT_CORNER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(f, HORIZONTAL_BAR);
|
||||||
|
if (mazegrid_get_edge(g, col + 1, row, EDGE_UP)) fprintf(f, RIGHT_TEE);
|
||||||
|
else fprintf(f, HORIZONTAL_BAR);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
if (mazegrid_get_edge(g, g->width - 1, row, EDGE_UP)) fprintf(f, " " VERTICAL_BAR);
|
||||||
|
else {
|
||||||
|
fprintf(f, HORIZONTAL_BAR);
|
||||||
|
if (row + 2 == g->height) fprintf(f, TOP_RIGHT_CORNER);
|
||||||
|
else fprintf(f, RIGHT_TEE);
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
fprintf(f, HORIZONTAL_HALF_RIGHT);
|
||||||
|
for (size_t i = 0; i < g->width; i++) {
|
||||||
|
fprintf(f, HORIZONTAL_BAR);
|
||||||
|
if (mazegrid_get_edge(g, i, 0, EDGE_RIGHT)) fprintf(f, HORIZONTAL_BAR);
|
||||||
|
else if (i == g->width - 1) fprintf(f, BOTTOM_RIGHT_CORNER);
|
||||||
|
else fprintf(f, BOTTOM_TEE);
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ int mazegrid_set_edge(mazegrid_t* g, size_t x, size_t y, mazeedge_dir_t dir, edg
|
|||||||
edgeweight_t mazegrid_get_edge(mazegrid_t const* g, size_t, size_t y, mazeedge_dir_t dir);
|
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);
|
||||||
|
void mazegrid_uniform(mazegrid_t* g);
|
||||||
|
|
||||||
void mazegrid_print(mazegrid_t const* g, FILE * f);
|
void mazegrid_print(mazegrid_t const* g, FILE * f);
|
||||||
|
|
||||||
|
|||||||
142
src/image.c
Normal file
142
src/image.c
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <png.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
#define LINE_THICKNESS 3
|
||||||
|
#define BLOCK_SIZE 32
|
||||||
|
#define MARGIN 20
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* data;
|
||||||
|
int w, h;
|
||||||
|
} img_data_t;
|
||||||
|
|
||||||
|
static void setPixel(img_data_t* img, int x, int y, char v) {
|
||||||
|
//fprintf(stderr, "setPixel(img, %d, %d, %d)\n", x, y, v);
|
||||||
|
assert((x < img->w) && (y < img->h));
|
||||||
|
img->data[y * img->w + x] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setBox(img_data_t* img, int x, int y, int w, int h, char v) {
|
||||||
|
//fprintf(stderr, "setBox(img, %d, %d, %d, %d, %d)\n", x, y, w, h, v);
|
||||||
|
for (int i = 0; i < h; i++) {
|
||||||
|
for (int j = 0; j < w; j++) {
|
||||||
|
setPixel(img, x + j, y + i, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static img_data_t* gridToImageData(mazegrid_t const* g) {
|
||||||
|
img_data_t* result = malloc(sizeof(img_data_t));
|
||||||
|
result->w = LINE_THICKNESS + g->width * BLOCK_SIZE + 2 * MARGIN;
|
||||||
|
result->h = LINE_THICKNESS + g->height * BLOCK_SIZE + 2 * MARGIN;
|
||||||
|
result->data = malloc(result->w * result->h);
|
||||||
|
//fprintf(stderr, "Box dimensions: %d x %d\n", result->w, result->h);
|
||||||
|
|
||||||
|
// white background
|
||||||
|
memset(result->data, 0, result->w * result->h);
|
||||||
|
|
||||||
|
// draw basic outline
|
||||||
|
setBox(result, MARGIN, MARGIN, result->w - 2 * MARGIN, LINE_THICKNESS, 1);
|
||||||
|
setBox(result, MARGIN, MARGIN + LINE_THICKNESS, LINE_THICKNESS, (g->height - 1) * BLOCK_SIZE, 1);
|
||||||
|
setBox(result, MARGIN, result->h - MARGIN - 1 - LINE_THICKNESS, result->w - 2 * MARGIN, LINE_THICKNESS, 1);
|
||||||
|
setBox(result, result->w - MARGIN - LINE_THICKNESS, MARGIN + LINE_THICKNESS + BLOCK_SIZE, LINE_THICKNESS, (g->height - 1) * BLOCK_SIZE, 1);
|
||||||
|
|
||||||
|
// partitions
|
||||||
|
for (int i = 0; i < g->height; i++) {
|
||||||
|
for (int j = 0; j < g->width; j++) {
|
||||||
|
//fprintf(stderr, "Drawing (%d, %d) -> %d, %d\n", j, i, mazegrid_get_edge(g, j, i, EDGE_UP), mazegrid_get_edge(g, j, i, EDGE_RIGHT));
|
||||||
|
int x = MARGIN + LINE_THICKNESS + BLOCK_SIZE * j, y = result->h - MARGIN - LINE_THICKNESS - BLOCK_SIZE * i;
|
||||||
|
if (i < g->height - 1) {
|
||||||
|
if (mazegrid_get_edge(g, j, i, EDGE_UP) == 0)
|
||||||
|
setBox(result, x - LINE_THICKNESS, y - BLOCK_SIZE, BLOCK_SIZE + LINE_THICKNESS, LINE_THICKNESS, 1);
|
||||||
|
}
|
||||||
|
if (j < g->width - 1) {
|
||||||
|
if (mazegrid_get_edge(g, j, i, EDGE_RIGHT) == 0)
|
||||||
|
setBox(result, x + BLOCK_SIZE - LINE_THICKNESS, y - BLOCK_SIZE, LINE_THICKNESS, BLOCK_SIZE, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeImageData(img_data_t const* img, png_structp png_ptr) {
|
||||||
|
for (int i = 0; i < img->h; i++) {
|
||||||
|
png_byte row[3 * img->w];
|
||||||
|
for (int j = 0; j < img->w; j++) {
|
||||||
|
if (img->data[i * img->w + j]) {
|
||||||
|
// black
|
||||||
|
row[3 * j] = row[3 * j + 1] = row[3 * j + 2] = 0;
|
||||||
|
} else {
|
||||||
|
// white
|
||||||
|
row[3 * j] = row[3 * j + 1] = row[3 * j + 2] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freeImageData(img_data_t* img) {
|
||||||
|
free(img->data);
|
||||||
|
free(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
int writePNG(mazegrid_t const* g, char const* filename) {
|
||||||
|
int code = 1;
|
||||||
|
img_data_t* img = gridToImageData(g);
|
||||||
|
FILE *f = NULL;
|
||||||
|
png_structp png_ptr = NULL;
|
||||||
|
png_infop info_ptr = NULL;
|
||||||
|
|
||||||
|
f = fopen(filename, "wb");
|
||||||
|
if (NULL == f) {
|
||||||
|
fprintf(stderr, "Could not open %s for writing.\n", filename);
|
||||||
|
code = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (png_ptr == NULL) {
|
||||||
|
fprintf(stderr, "Could not allocate PNG write struct.\n");
|
||||||
|
code = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (info_ptr == NULL) {
|
||||||
|
fprintf(stderr, "Could not allocate PNG info struct.\n");
|
||||||
|
code = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||||
|
fprintf(stderr, "Error during PNG creation.\n");
|
||||||
|
code = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init_io(png_ptr, f);
|
||||||
|
|
||||||
|
// Write header (8 bit color depth)
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, img->w, img->h,
|
||||||
|
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||||
|
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
writeImageData(img, png_ptr);
|
||||||
|
|
||||||
|
png_write_end(png_ptr, NULL);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (f != NULL) fclose(f);
|
||||||
|
if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
|
||||||
|
if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||||
|
if (img != NULL) freeImageData(img);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
8
src/image.h
Normal file
8
src/image.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _IMAGE_H
|
||||||
|
#define _IMAGE_H 1
|
||||||
|
|
||||||
|
#include "grid.h"
|
||||||
|
|
||||||
|
int writePNG(mazegrid_t const* g, char const* filename);
|
||||||
|
|
||||||
|
#endif // !def(_IMAGE_H)
|
||||||
28
src/main.c
28
src/main.c
@@ -2,17 +2,23 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <popt.h>
|
#include <popt.h>
|
||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "prim.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
char c;
|
char c;
|
||||||
int width = 0, height = 0;
|
int width = 0, height = 0;
|
||||||
|
char const *filename = NULL;
|
||||||
struct poptOption options_table[] = {
|
struct poptOption options_table[] = {
|
||||||
{ "width", 'w', POPT_ARG_INT, &width, 0 },
|
{ "width", 'w', POPT_ARG_INT, &width, 0,
|
||||||
{ "height", 'h', POPT_ARG_INT, &height, 0 },
|
"Width of the maze", "BLOCKS" },
|
||||||
|
{ "height", 'h', POPT_ARG_INT, &height, 0,
|
||||||
|
"Height of the maze", "BLOCKS" },
|
||||||
POPT_AUTOHELP
|
POPT_AUTOHELP
|
||||||
{ NULL, 0, 0, NULL, 0 }
|
{ NULL, 0, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
poptContext ctx = poptGetContext(NULL, argc, argv, options_table, 0);
|
poptContext ctx = poptGetContext(NULL, argc, (const char**) argv, options_table, 0);
|
||||||
|
poptSetOtherOptionHelp(ctx, "OUTPUT");
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
poptPrintUsage(ctx, stderr, 0);
|
poptPrintUsage(ctx, stderr, 0);
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -22,9 +28,21 @@ int main(int argc, char* argv[]) {
|
|||||||
fprintf(stderr, "%s: %s\n", poptBadOption(ctx, POPT_BADOPTION_NOALIAS), poptStrerror(c));
|
fprintf(stderr, "%s: %s\n", poptBadOption(ctx, POPT_BADOPTION_NOALIAS), poptStrerror(c));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
mazegrid_t g = mazegrid_new(width, height);
|
filename = poptGetArg(ctx);
|
||||||
|
if ((width == 0) || (height == 0)) {
|
||||||
|
fprintf(stderr, "Positive values for width (-w) and height (-h) are required.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (filename == NULL) {
|
||||||
|
fprintf(stderr, "An output filename is required.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
mazegrid_t g = mazegrid_new(width, height), maze;
|
||||||
mazegrid_randomize(&g);
|
mazegrid_randomize(&g);
|
||||||
mazegrid_print(&g, stdout);
|
//mazegrid_print(&g, stdout);
|
||||||
|
prim(&g, &maze);
|
||||||
|
writePNG(&maze, filename);
|
||||||
mazegrid_free(&g);
|
mazegrid_free(&g);
|
||||||
|
mazegrid_free(&maze);
|
||||||
poptFreeContext(ctx);
|
poptFreeContext(ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/pq.c
Normal file
110
src/pq.c
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include "pq.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int priority;
|
||||||
|
size_t x, y;
|
||||||
|
mazeedge_dir_t dir;
|
||||||
|
} _point_t;
|
||||||
|
|
||||||
|
struct pq {
|
||||||
|
size_t heap_size, next;
|
||||||
|
_point_t* heap;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pq* pq_new(size_t heap_size) {
|
||||||
|
struct pq* result = malloc(sizeof(struct pq));
|
||||||
|
result->heap_size = heap_size;
|
||||||
|
result->next = 0;
|
||||||
|
result->heap = calloc(heap_size, sizeof(_point_t));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _swap(struct pq* q, size_t idx1, size_t idx2) {
|
||||||
|
unsigned int priority = q->heap[idx1].priority;
|
||||||
|
size_t x = q->heap[idx1].x;
|
||||||
|
size_t y = q->heap[idx1].y;
|
||||||
|
mazeedge_dir_t dir = q->heap[idx1].dir;
|
||||||
|
|
||||||
|
q->heap[idx1].priority = q->heap[idx2].priority;
|
||||||
|
q->heap[idx1].x = q->heap[idx2].x;
|
||||||
|
q->heap[idx1].y = q->heap[idx2].y;
|
||||||
|
q->heap[idx1].dir = q->heap[idx2].dir;
|
||||||
|
|
||||||
|
q->heap[idx2].priority = priority;
|
||||||
|
q->heap[idx2].x = x;
|
||||||
|
q->heap[idx2].y = y;
|
||||||
|
q->heap[idx2].dir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _heapify_up(struct pq* q) {
|
||||||
|
size_t i = q->next - 1;
|
||||||
|
while (i > 0) {
|
||||||
|
size_t parent = i / 2;
|
||||||
|
if (q->heap[parent].priority > q->heap[i].priority) {
|
||||||
|
_swap(q, parent, i);
|
||||||
|
i = parent;
|
||||||
|
} else {
|
||||||
|
// done
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pq_add(struct pq* q, unsigned int priority, size_t x, size_t y, mazeedge_dir_t dir) {
|
||||||
|
q->heap[q->next].x = x;
|
||||||
|
q->heap[q->next].y = y;
|
||||||
|
q->heap[q->next].priority = priority;
|
||||||
|
q->heap[q->next].dir = dir;
|
||||||
|
q->next++;
|
||||||
|
_heapify_up(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pq_empty(struct pq const* q) {
|
||||||
|
return q->next == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _heapify_down(struct pq* q) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < q->next) {
|
||||||
|
size_t ch1 = i * 2, ch2 = i * 2 + 1;
|
||||||
|
if (ch1 >= q->next) return;
|
||||||
|
if (ch2 >= q->next) {
|
||||||
|
if (q->heap[ch1].priority < q->heap[i].priority) {
|
||||||
|
_swap(q, i, ch1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// three-way compare
|
||||||
|
if ((q->heap[i].priority < q->heap[ch1].priority) &&
|
||||||
|
(q->heap[i].priority < q->heap[ch2].priority)) {
|
||||||
|
return; // all done - partial order ensured
|
||||||
|
}
|
||||||
|
if (q->heap[ch1].priority < q->heap[ch2].priority) {
|
||||||
|
_swap(q, i, ch1);
|
||||||
|
i = ch1;
|
||||||
|
} else {
|
||||||
|
_swap(q, i, ch2);
|
||||||
|
i = ch2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pq_pop(struct pq* q, size_t* x, size_t* y, mazeedge_dir_t* dir) {
|
||||||
|
if (pq_empty(q)) return 0;
|
||||||
|
*x = q->heap[0].x;
|
||||||
|
*y = q->heap[0].y;
|
||||||
|
*dir = q->heap[0].dir;
|
||||||
|
_swap(q, 0, q->next-1);
|
||||||
|
q->next--;
|
||||||
|
_heapify_down(q);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pq_free(struct pq* q) {
|
||||||
|
free(q->heap); q->heap = NULL;
|
||||||
|
q->heap_size = 0;
|
||||||
|
q->next = 0;
|
||||||
|
free(q);
|
||||||
|
}
|
||||||
15
src/pq.h
Normal file
15
src/pq.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _PQ_H
|
||||||
|
#define _PQ_H 1
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "grid.h"
|
||||||
|
|
||||||
|
struct pq;
|
||||||
|
|
||||||
|
struct pq* pq_new(size_t heap_size);
|
||||||
|
void pq_add(struct pq* q, unsigned int priority, size_t x, size_t y, mazeedge_dir_t dir);
|
||||||
|
int pq_pop(struct pq* q, size_t* x, size_t* y, mazeedge_dir_t *dir);
|
||||||
|
bool pq_empty(struct pq const* q);
|
||||||
|
void pq_free(struct pq* q);
|
||||||
|
|
||||||
|
#endif // !def(_PQ_H)
|
||||||
43
src/prim.c
Normal file
43
src/prim.c
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "pq.h"
|
||||||
|
#include "prim.h"
|
||||||
|
#include "set.h"
|
||||||
|
|
||||||
|
void prim(mazegrid_t const* g, mazegrid_t* result) {
|
||||||
|
struct pq* q = pq_new(g->width*g->height*4);
|
||||||
|
struct node_set* s = node_set_new(g->width, g->height);
|
||||||
|
*result = mazegrid_new(g->width, g->height);
|
||||||
|
|
||||||
|
node_set_add(s, 0, 0);
|
||||||
|
if (g->height > 1) pq_add(q, mazegrid_get_edge(g, 0, 0, EDGE_UP), 0, 1, EDGE_DOWN);
|
||||||
|
if (g->width > 1) pq_add(q, mazegrid_get_edge(g, 0, 0, EDGE_RIGHT), 1, 0, EDGE_LEFT);
|
||||||
|
|
||||||
|
while (!pq_empty(q) && (node_set_size(s) < g->width * g->height)) {
|
||||||
|
size_t x, y;
|
||||||
|
mazeedge_dir_t dir;
|
||||||
|
pq_pop(q, &x, &y, &dir);
|
||||||
|
|
||||||
|
if (node_set_contains(s, x, y)) continue;
|
||||||
|
|
||||||
|
// add edge to tree
|
||||||
|
mazegrid_set_edge(result, x, y, dir, 1);
|
||||||
|
|
||||||
|
// add neighbors
|
||||||
|
if ((x > 0) && !node_set_contains(s, x - 1, y)) {
|
||||||
|
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_LEFT), x - 1, y, EDGE_RIGHT);
|
||||||
|
}
|
||||||
|
if ((x < g->width - 1) && !node_set_contains(s, x + 1, y)) {
|
||||||
|
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_RIGHT), x + 1, y, EDGE_LEFT);
|
||||||
|
}
|
||||||
|
if ((y > 0) && !node_set_contains(s, x, y - 1)) {
|
||||||
|
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_DOWN), x, y - 1, EDGE_UP);
|
||||||
|
}
|
||||||
|
if ((y < g->height - 1) && !node_set_contains(s, x, y + 1)) {
|
||||||
|
pq_add(q, mazegrid_get_edge(g, x, y, EDGE_UP), x, y + 1, EDGE_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_set_add(s, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_set_free(s);
|
||||||
|
pq_free(q);
|
||||||
|
}
|
||||||
8
src/prim.h
Normal file
8
src/prim.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _PRIM_H
|
||||||
|
#define _PRIM_H 1
|
||||||
|
|
||||||
|
#include "grid.h"
|
||||||
|
|
||||||
|
void prim(mazegrid_t const* grid, mazegrid_t* result);
|
||||||
|
|
||||||
|
#endif // !def(_PRIM_H)
|
||||||
47
src/set.c
Normal file
47
src/set.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include "set.h"
|
||||||
|
|
||||||
|
struct node_set {
|
||||||
|
size_t width, height;
|
||||||
|
size_t size;
|
||||||
|
bool** nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct node_set* node_set_new(size_t width, size_t height) {
|
||||||
|
struct node_set* result = malloc(sizeof(struct node_set));
|
||||||
|
result->nodes = calloc(height, sizeof(bool*));
|
||||||
|
for (size_t i = 0; i < height; i++) {
|
||||||
|
result->nodes[i] = calloc(width, sizeof(bool));
|
||||||
|
for (size_t j = 0; j < width; j++) {
|
||||||
|
result->nodes[i][j] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result->width = width;
|
||||||
|
result->height = height;
|
||||||
|
result->size = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_set_add(struct node_set* s, size_t x, size_t y) {
|
||||||
|
s->nodes[y][x] = true;
|
||||||
|
s->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool node_set_contains(struct node_set const* s, size_t x, size_t y) {
|
||||||
|
return s->nodes[y][x];
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_set_free(struct node_set* s) {
|
||||||
|
for (size_t i = 0; i < s->height; i++) {
|
||||||
|
free(s->nodes[i]);
|
||||||
|
s->nodes[i] = NULL;
|
||||||
|
}
|
||||||
|
free(s->nodes);
|
||||||
|
s->nodes = NULL;
|
||||||
|
s->width = s->height = s->size = 0;
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t node_set_size(struct node_set const* s) {
|
||||||
|
return s->size;
|
||||||
|
}
|
||||||
15
src/set.h
Normal file
15
src/set.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _SET_H
|
||||||
|
#define _SET_H 1
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "grid.h"
|
||||||
|
|
||||||
|
struct node_set;
|
||||||
|
|
||||||
|
struct node_set* node_set_new(size_t w, size_t h);
|
||||||
|
void node_set_add(struct node_set* s, size_t x, size_t y);
|
||||||
|
bool node_set_contains(struct node_set const* s, size_t x, size_t y);
|
||||||
|
size_t node_set_size(struct node_set const* s);
|
||||||
|
void node_set_free(struct node_set*);
|
||||||
|
|
||||||
|
#endif // !def(_SET_H)
|
||||||
Reference in New Issue
Block a user