Mercurial > public > maze-solver
changeset 8:deeb54b231aa
refactor code
author | Dennis <denniscmartin@protonmail.com> |
---|---|
date | Sun, 30 Oct 2022 17:00:56 +0100 |
parents | a9dd80a69887 |
children | 22cf01362b45 |
files | .github/resources/maze.png .github/resources/sol.png .gitignore .idea/misc.xml CMakeLists.txt README.md algo.c algo.h build.sh main.c mazes/maze1.png mazes/maze2.png mazes/maze3.png resources/maze.png resources/sol.png src/algos.c src/algos.h src/handlers.c src/handlers.h src/main.c src/process.c src/process.h |
diffstat | 22 files changed, 381 insertions(+), 371 deletions(-) [+] |
line wrap: on
line diff
--- a/.gitignore Sun Oct 16 17:17:15 2022 +0200 +++ b/.gitignore Sun Oct 30 17:00:56 2022 +0100 @@ -1,4 +1,5 @@ sols +mazes # Created by https://www.toptal.com/developers/gitignore/api/python,c,pycharm,clion,macos # Edit at https://www.toptal.com/developers/gitignore?templates=python,c,pycharm,clion,macos
--- a/.idea/misc.xml Sun Oct 16 17:17:15 2022 +0200 +++ b/.idea/misc.xml Sun Oct 30 17:00:56 2022 +0100 @@ -3,6 +3,7 @@ <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" /> <component name="CidrRootsConfiguration"> <excludeRoots> + <file path="$PROJECT_DIR$/mazes" /> <file path="$PROJECT_DIR$/sols" /> </excludeRoots> </component>
--- a/CMakeLists.txt Sun Oct 16 17:17:15 2022 +0200 +++ b/CMakeLists.txt Sun Oct 30 17:00:56 2022 +0100 @@ -7,6 +7,6 @@ set(CMAKE_C_STANDARD 99) -add_executable(maze_solver main.c algo.c algo.h) +add_executable(maze_solver src/main.c src/algos.c src/algos.h src/process.c src/process.h src/handlers.c src/handlers.h) target_link_libraries(maze_solver png) # Link libraries
--- a/README.md Sun Oct 16 17:17:15 2022 +0200 +++ b/README.md Sun Oct 30 17:00:56 2022 +0100 @@ -13,11 +13,10 @@ ## Usage 1. Build executable -2. Make a folder named `mazes` and place the `png` files there. -3. Make a folder named `sols`. The script place the solutions here. +2. Make a folder named `sols`. The script place the solutions here. - - + + ## Resources - [Maze generator](https://keesiemeijer.github.io/maze-generator/#generate)
--- a/algo.c Sun Oct 16 17:17:15 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -// -// Created by Dennis Concepción Martín on 15/10/22. -// - -#include "algo.h" - -int isPath(unsigned x, unsigned y, png_bytep* pRows) { - png_byte *pRow = pRows[y]; - png_byte *pPixel = &pRow[x * 4]; - - /* - * pPixel[0] -> R - * pPixel[1] -> G - * pPixel[2] -> B - */ - - if (pPixel[0] == 255) { - pPixel[1] = 0; - pPixel[2] = 0; - - return 1; - } else { - return 0; - } -} - - -void wallFollower(png_bytep* pRows, unsigned int width) { - unsigned int x = 0; - unsigned int y = 1; - char direction = 'R'; - - isPath(x, y, pRows); - - while (x < width && y < width) { - - if (x == width - 1 && y == width - 2) { - break; - } - - switch (direction) { // NOLINT(hicpp-multiway-paths-covered) - case 'R': - - // Check if down position is white - if (isPath(x, y + 1, pRows)) { - ++y; - direction = 'D'; - } - - // Check if right position is white - else if (isPath(x + 1, y, pRows)) { - ++x; - direction = 'R'; - } - - // Check if up position is white - else if (isPath(x, y - 1, pRows)) { - --y; - direction = 'U'; - } - - // Turn 180 - else { - --x; - direction = 'L'; - } - - break; - - case 'L': - - // Check if up position is white - if (isPath(x, y - 1, pRows)) { - --y; - direction = 'U'; - } - - // Check if left position is white - else if (isPath(x - 1, y, pRows)) { - --x; - direction = 'L'; - } - - // Check if down position is white - else if (isPath(x, y + 1, pRows)) { - ++y; - direction = 'D'; - } - - // Turn 180 - else { - ++x; - direction = 'R'; - } - - break; - - case 'U': - - // Check if right position is white - if (isPath(x + 1, y, pRows)) { - ++x; - direction = 'R'; - } - - // Check if up position is white - else if (isPath(x, y - 1, pRows)) { - --y; - direction = 'U'; - } - - // Check if left position is white - else if (isPath(x - 1, y, pRows)) { - --x; - direction = 'L'; - } - - // Turn 180 - else { - ++y; - direction = 'D'; - } - - break; - - case 'D': - - // Check if left position is white - if (isPath(x - 1, y, pRows)) { - --x; - direction = 'L'; - } - - // Check if down position is white - else if (isPath(x, y + 1, pRows)) { - ++y; - direction = 'D'; - } - - // Check if right position is white - else if (isPath(x + 1, y, pRows)) { - ++x; - direction = 'R'; - } - - // Turn 180 - else { - --y; - direction = 'U'; - } - - break; - } - } -} \ No newline at end of file
--- a/algo.h Sun Oct 16 17:17:15 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -// -// Created by Dennis Concepción Martín on 15/10/22. -// - -#ifndef MAZE_SOLVER_ALGO_H -#define MAZE_SOLVER_ALGO_H - -#include <png.h> -#include <time.h> -#include <stdio.h> -#include <stdlib.h> - -void wallFollower(png_bytep* pRows, unsigned int width); - -#endif //MAZE_SOLVER_ALGO_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build.sh Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,4 @@ +#!/bin/bash + +mkdir mazes +mkdir sols \ No newline at end of file
--- a/main.c Sun Oct 16 17:17:15 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -#include "algo.h" - -int main(int argc, char* argv[]) { - char* unsolvedFilename; - char* solvedFilename; - int phases; - unsigned int width, height; - - clock_t start, end; - double cpuTimeUsed; - - FILE* unsolvedFp; - png_structp unsolvedPngStruct; - png_infop unsolvedPngInfo; - png_byte colorType; - png_byte bitDepth; - png_bytep* pRows; - - FILE* solvedFp; - png_structp solvedPngStruct; - png_infop solvedPngInfo; - - start = clock(); - - if (argc < 2) { - printf("Incorrect arguments\n"); - abort(); - } - - // Get user arguments - unsolvedFilename = argv[1]; - - /* - * READ FILE - */ - - // Add path to unsolvedFilename - asprintf(&unsolvedFilename, "mazes/%s", unsolvedFilename); - - // Open file - unsolvedFp = fopen(unsolvedFilename, "rb"); - - if (!unsolvedFp) { - printf("Error opening image named %s\n", unsolvedFilename); - abort(); - } - - // Allocate and initialize a unsolvedPngStruct for reading PNG file - unsolvedPngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!unsolvedPngStruct) { - printf("png_create_read_struct failed\n"); - abort(); - } - - // Allocate and initialize a unsolvedPngInfo structure - unsolvedPngInfo = png_create_info_struct(unsolvedPngStruct); - - if (!unsolvedPngInfo) { - printf("png_create_info_struct failed\n"); - abort(); - } - - /* - * When libpng encounters an error, it expects to longjmp back to your routine. - * Therefore, you will need to call setjmp and pass your png_jmpbuf(unsolvedPngStruct). - * More about setjmp -> https://es.wikipedia.org/wiki/Setjmp.h - */ - - if (setjmp(png_jmpbuf(unsolvedPngStruct))) { - printf("Error during init_io\n"); - abort(); - } - - png_init_io(unsolvedPngStruct, unsolvedFp); // Initialize the default input/output functions for the PNG file - png_set_sig_bytes(unsolvedPngStruct, 0); // Set signature bytes - png_read_info(unsolvedPngStruct, unsolvedPngInfo); // Read info - - width = png_get_image_width(unsolvedPngStruct, unsolvedPngInfo); - height = png_get_image_height(unsolvedPngStruct, unsolvedPngInfo); - colorType = png_get_color_type(unsolvedPngStruct, unsolvedPngInfo); - bitDepth = png_get_bit_depth(unsolvedPngStruct, unsolvedPngInfo); - - phases = png_set_interlace_handling(unsolvedPngStruct); - png_read_update_info(unsolvedPngStruct, unsolvedPngInfo); - - printf("Image width: %d\n", width); - printf("Image height: %d\n", height); - printf("Color type: %d\n", colorType); - printf("Bit depth: %d\n", bitDepth); - printf("Number of phases: %d\n", phases); - - // Read file - if (setjmp(png_jmpbuf(unsolvedPngStruct))) { - printf("Error during read_image"); - abort(); - } - - pRows = (png_bytep*) malloc(sizeof(png_bytep) * height); - - for (int y = 0; y < height; y++) { - pRows[y] = (png_byte *) malloc(png_get_rowbytes(unsolvedPngStruct, unsolvedPngInfo)); - } - - // Read the image into memory - png_read_image(unsolvedPngStruct, pRows); - fclose(unsolvedFp); - - /* - * ALGOS - */ - - wallFollower(pRows, width); - - /* - * WRITE FILE - */ - - // Add path to unsolvedFilename - solvedFilename = argv[1]; - asprintf(&solvedFilename, "sols/%s", solvedFilename); - - // Open file - solvedFp = fopen(solvedFilename, "wb"); - - if (!solvedFp) { - printf("File %s could not be opened for writing", solvedFilename); - abort(); - } - - // Allocate and initialize a solvedPngStruct for writting PNG file - solvedPngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!solvedPngStruct) { - printf("png_create_read_struct failed\n"); - abort(); - } - - // Allocate and initialize a unsolvedPngInfo structure - solvedPngInfo = png_create_info_struct(solvedPngStruct); - - if (!solvedPngInfo) { - printf("png_create_info_struct failed\n"); - abort(); - } - - if (setjmp(png_jmpbuf(solvedPngStruct))) { - printf("Error during init_io\n"); - abort(); - } - - png_init_io(solvedPngStruct, solvedFp); - - // Write header - if (setjmp(png_jmpbuf(solvedPngStruct))) { - printf("Error writing header"); - abort(); - } - - png_set_IHDR(solvedPngStruct, solvedPngInfo, width, height, bitDepth, colorType, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE - ); - - png_write_info(solvedPngStruct, solvedPngInfo); - - // Write bytes - if (setjmp(png_jmpbuf(solvedPngStruct))) { - printf("Error writing bytes"); - abort(); - } - - png_write_image(solvedPngStruct, pRows); - - // End write - if (setjmp(png_jmpbuf(solvedPngStruct))) { - printf("Error during end of write"); - abort(); - } - - png_write_end(solvedPngStruct, NULL); - - // Cleanup heap allocation - for (int y = 0; y < height; y++) { - free(pRows[y]); - } - - free(pRows); - fclose(solvedFp); - - end = clock(); - cpuTimeUsed = ((double) (end - start)) / CLOCKS_PER_SEC; - - printf("Maze solved in %f seconds\n", cpuTimeUsed); - - return 0; -} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/algos.c Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,148 @@ +// +// Created by Dennis Concepción Martín on 15/10/22. +// + +#include "algos.h" + +int is_path(unsigned x, unsigned y, png_bytep* pRows) { + png_byte *pRow = pRows[y]; + png_byte *pPixel = &pRow[x * 4]; + + if (pPixel[0] == 255) { // pPixel[0] -> R + pPixel[1] = 0; // pPixel[1] -> G + pPixel[2] = 0; // pPixel[2] -> B + + return 1; + } else { + return 0; + } +} + +void wall_follower(png_bytep* pRows, unsigned int width) { + unsigned int x = 0; + unsigned int y = 1; + char direction = 'R'; + + is_path(x, y, pRows); + + while (x < width && y < width) { + + if (x == width - 1 && y == width - 2) { + break; + } + + switch (direction) { // NOLINT(hicpp-multiway-paths-covered) + case 'R': + + // Check if down position is white + if (is_path(x, y + 1, pRows)) { + ++y; + direction = 'D'; + } + + // Check if right position is white + else if (is_path(x + 1, y, pRows)) { + ++x; + direction = 'R'; + } + + // Check if up position is white + else if (is_path(x, y - 1, pRows)) { + --y; + direction = 'U'; + } + + // Turn 180 + else { + --x; + direction = 'L'; + } + + break; + + case 'L': + + // Check if up position is white + if (is_path(x, y - 1, pRows)) { + --y; + direction = 'U'; + } + + // Check if left position is white + else if (is_path(x - 1, y, pRows)) { + --x; + direction = 'L'; + } + + // Check if down position is white + else if (is_path(x, y + 1, pRows)) { + ++y; + direction = 'D'; + } + + // Turn 180 + else { + ++x; + direction = 'R'; + } + + break; + + case 'U': + + // Check if right position is white + if (is_path(x + 1, y, pRows)) { + ++x; + direction = 'R'; + } + + // Check if up position is white + else if (is_path(x, y - 1, pRows)) { + --y; + direction = 'U'; + } + + // Check if left position is white + else if (is_path(x - 1, y, pRows)) { + --x; + direction = 'L'; + } + + // Turn 180 + else { + ++y; + direction = 'D'; + } + + break; + + case 'D': + + // Check if left position is white + if (is_path(x - 1, y, pRows)) { + --x; + direction = 'L'; + } + + // Check if down position is white + else if (is_path(x, y + 1, pRows)) { + ++y; + direction = 'D'; + } + + // Check if right position is white + else if (is_path(x + 1, y, pRows)) { + ++x; + direction = 'R'; + } + + // Turn 180 + else { + --y; + direction = 'U'; + } + + break; + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/algos.h Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,12 @@ +// +// Created by Dennis Concepción Martín on 15/10/22. +// + +#ifndef MAZE_SOLVER_ALGOS_H +#define MAZE_SOLVER_ALGOS_H + +#include <png.h> + +void wall_follower(png_bytep* pRows, unsigned int width); + +#endif //MAZE_SOLVER_ALGOS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/handlers.c Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,10 @@ +// +// Created by Dennis Concepción Martín on 18/10/22. +// + +#include "handlers.h" + +void error() { + perror("Error: "); + exit(EXIT_FAILURE); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/handlers.h Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,13 @@ +// +// Created by Dennis Concepción Martín on 18/10/22. +// + +#ifndef MAZE_SOLVER_HANDLERS_H +#define MAZE_SOLVER_HANDLERS_H + +#include <stdlib.h> +#include <stdio.h> + +void error(); + +#endif //MAZE_SOLVER_HANDLERS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.c Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,28 @@ +#include <time.h> +#include "process.h" +#include "algos.h" + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("Incorrect arguments\n"); + error(); + } + + char* filename = argv[1]; + struct PngInfo png_info = read_png(filename); + + printf("Filename: %s\n", png_info.filename); + printf("Width: %d\n", png_info.width); + printf("Height: %d\n", png_info.height); + + clock_t start = clock(); + wall_follower(png_info.rows, png_info.width); + clock_t end = clock(); + + double time_taken = ((double) (end - start)) / CLOCKS_PER_SEC; + printf("Algorithm duration: %f seconds\n", time_taken); + + write_png(png_info); + + return 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/process.c Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,139 @@ +// +// Created by Dennis Concepción Martín on 18/10/22. +// + +#include "process.h" + +struct PngInfo read_png(char* filename) { + struct PngInfo png_info; + png_info.filename = filename; + + asprintf(&filename, "mazes/%s", filename); + FILE* fp = fopen(filename, "rb"); + + if (!fp) { + error(); + } + + // Allocate and initialize read struct + png_structp read_struct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!read_struct) { + error(); + } + + // Allocate and initialize info struct + png_infop info_struct = png_create_info_struct(read_struct); + + if (!info_struct) { + error(); + } + + /* + * When libpng encounters an error, it expects to longjmp back to your routine. + * Therefore, you will need to call setjmp and pass your png_jmpbuf(unsolvedPngStruct). + * More about setjmp -> https://es.wikipedia.org/wiki/Setjmp.h + */ + + if (setjmp(png_jmpbuf(read_struct))) { + error(); + } + + png_init_io(read_struct, fp); // Init default input/output functions + png_set_sig_bytes(read_struct, 0); // Set signature bytes + png_read_info(read_struct, info_struct); // Read info + + // Set struct variables + png_info.width = png_get_image_width(read_struct, info_struct); + png_info.height = png_get_image_height(read_struct, info_struct); + png_info.byte_depth = png_get_bit_depth(read_struct, info_struct); + png_info.color_type = png_get_color_type(read_struct, info_struct); + + png_read_update_info(read_struct, info_struct); + + // Read file + if (setjmp(png_jmpbuf(read_struct))) { + error(); + } + + // Allocate memory dynamically + png_bytep* rows = (png_bytep*) malloc(sizeof(png_bytep) * png_info.height); + png_info.rows = rows; + + for (int y = 0; y < png_info.height; y++) { + rows[y] = (png_byte *) malloc(png_get_rowbytes(read_struct, info_struct)); + } + + // Read image into memory + png_read_image(read_struct, rows); + fclose(fp); + + return png_info; +} + +void write_png(struct PngInfo png_info) { + char* solved_filename = png_info.filename; + asprintf(&solved_filename, "sols/%s", solved_filename); + FILE* fp = fopen(solved_filename, "wb"); + + if (!fp) { + error(); + } + + // Allocate and initialize write struct + png_structp write_struct = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!write_struct) { + error(); + } + + // Allocate and initialize infor struct + png_infop info_struct = png_create_info_struct(write_struct); + + if (!info_struct) { + error(); + } + + if (setjmp(png_jmpbuf(write_struct))) { + error(); + } + + png_init_io(write_struct, fp); + + // Write header + if (setjmp(png_jmpbuf(write_struct))) { + printf("Error writing header"); + abort(); + } + + png_set_IHDR( + write_struct, info_struct, png_info.width, png_info.height, png_info.byte_depth, png_info.color_type, + PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE + ); + + png_write_info(write_struct, info_struct); + + // Write bytes + if (setjmp(png_jmpbuf(write_struct))) { + printf("Error writing bytes"); + abort(); + } + + png_write_image(write_struct, png_info.rows); + + // End write + if (setjmp(png_jmpbuf(write_struct))) { + printf("Error during end of write"); + abort(); + } + + png_write_end(write_struct, NULL); + + // Cleanup heap allocation + for (int y = 0; y < png_info.height; y++) { + free(png_info.rows[y]); + } + + free(png_info.rows); + fclose(fp); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/process.h Sun Oct 30 17:00:56 2022 +0100 @@ -0,0 +1,21 @@ +// +// Created by Dennis Concepción Martín on 18/10/22. +// + +#ifndef MAZE_SOLVER_PROCESS_H +#define MAZE_SOLVER_PROCESS_H + +#include <png.h> +#include "handlers.h" + +struct PngInfo { + char* filename; + unsigned int width, height; + png_bytep* rows; + png_byte byte_depth, color_type; +}; + +struct PngInfo read_png(char* filename); +void write_png(struct PngInfo); + +#endif //MAZE_SOLVER_PROCESS_H