From 0f8e61797f0acec556e0dec454b00659d9cead75 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Sun, 18 May 2025 14:37:43 -0400 Subject: [PATCH] Now using a hunt-and-kill maze algorithm. --- maze.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++-- maze.hpp | 2 + tests/mazes.cpp | 16 +++++- worldbuilder.cpp | 5 +- 4 files changed, 138 insertions(+), 10 deletions(-) diff --git a/maze.cpp b/maze.cpp index ec5b069..0711e57 100644 --- a/maze.cpp +++ b/maze.cpp @@ -107,11 +107,11 @@ void divide(Matrix& map, std::vector &rooms, } if(punch_room) { - for(size_t j = jCoords.x; j <= jCoords.y; j++) { - for(size_t i = iCoords.x; i <= iCoords.y; i++) { - map[j][i] = 0; - } - } + // for(size_t j = jCoords.x; j <= jCoords.y; j++) { + // for(size_t i = iCoords.x; i <= iCoords.y; i++) { + // map[j][i] = 0; + // } + // } Room room{iCoords.x, jCoords.x, iCoords.y - iCoords.x + 1, jCoords.y - jCoords.x + 1}; @@ -143,3 +143,118 @@ void maze::recursive_div(Matrix& map, std::vector& rooms) { divide(map, rooms, {1, height - 2}, {1, width - 2}, split_dir(1, 1)); } + + +bool complete(Matrix& maze) { + size_t width = matrix::width(maze); + size_t height = matrix::height(maze); + + for(size_t row = 1; row < height; row += 2) { + for(size_t col = 1; col < width; col += 2) { + if(maze[row][col] != 0) return false; + } + } + + // dbc::sentinel("LOL it's complete eh?"); + return true; +} + +std::vector neighborsAB(Matrix& maze, Point on) { + std::vector result; + + std::array points{{ + {on.x, on.y - 2}, + {on.x, on.y + 2}, + {on.x - 2, on.y}, + {on.x + 2, on.y} + }}; + + for(auto point : points) { + if(matrix::inbounds(maze, point.x, point.y)) { + result.push_back(point); + } + } + + return result; +} + +std::vector neighbors(Matrix& maze, Point on) { + std::vector result; + + std::array points{{ + {on.x, on.y - 2}, + {on.x, on.y + 2}, + {on.x - 2, on.y}, + {on.x + 2, on.y} + }}; + + for(auto point : points) { + if(matrix::inbounds(maze, point.x, point.y)) { + if(maze[point.y][point.x] == WALL_PATH_LIMIT) { + result.push_back(point); + } + } + } + + return result; +} + +std::pair findCoord(Matrix& maze) { + size_t width = matrix::width(maze); + size_t height = matrix::height(maze); + + for(size_t y = 1; y < height; y += 2) { + for(size_t x = 1; x < width; x += 2) { + if(maze[y][x] == WALL_PATH_LIMIT) { + auto found = neighborsAB(maze, {x, y}); + + for(auto point : found) { + if(maze[point.y][point.x] == 0) { + return {{x, y}, point}; + } + } + } + } + } + + matrix::dump("BAD MAZE", maze); + dbc::sentinel("failed to find coord?"); +} + +void maze::hunt_and_kill(Matrix& maze, std::vector& rooms) { + size_t width = matrix::width(maze); + size_t height = matrix::height(maze); + matrix::assign(maze, WALL_PATH_LIMIT); + + Room start{2, 2, 3, 3}; + rooms.push_back(start); + Room goal{width-4, height-4, 3, 3}; + rooms.push_back(goal); + + for(auto& room : rooms) { + for(matrix::box it{maze, room.x, room.y, 1}; it.next();) { + maze[it.y][it.x] = 0; + } + } + + Point on{1,1}; + while(!complete(maze)) { + auto n = neighbors(maze, on); + if(n.size() == 0) { + auto t = findCoord(maze); + on = t.first; + maze[on.y][on.x] = 0; + size_t row = (on.y + t.second.y) / 2; + size_t col = (on.x + t.second.x) / 2; + maze[row][col] = 0; + } else { + auto nb = n[Random::uniform(size_t(0), n.size() - 1)]; + maze[nb.y][nb.x] = 0; + + size_t row = (nb.y + on.y) / 2; + size_t col = (nb.x + on.x) / 2; + maze[row][col] = 0; + on = nb; + } + } +} diff --git a/maze.hpp b/maze.hpp index 2a4a8ef..6fdce07 100644 --- a/maze.hpp +++ b/maze.hpp @@ -4,4 +4,6 @@ namespace maze { void recursive_div(matrix::Matrix& map, std::vector& rooms); + + void hunt_and_kill(Matrix& maze, std::vector& rooms); } diff --git a/tests/mazes.cpp b/tests/mazes.cpp index 7d1cc1b..8332409 100644 --- a/tests/mazes.cpp +++ b/tests/mazes.cpp @@ -9,7 +9,8 @@ using std::string; using matrix::Matrix; -TEST_CASE("simple maze first attempt", "[maze-gen]") { + +TEST_CASE("recursive division (garbage)", "[mazes]") { auto map = matrix::make(21, 21); std::vector rooms; @@ -21,3 +22,16 @@ TEST_CASE("simple maze first attempt", "[maze-gen]") { room.x, room.y, room.width, room.height); } } + +TEST_CASE("hunt-and-kill", "[maze-gen]") { + auto map = matrix::make(21, 21); + std::vector rooms; + + maze::hunt_and_kill(map, rooms); + matrix::dump("MAZE?", map); + + for(auto& room : rooms) { + fmt::println("room: {},{}; {},{}", + room.x, room.y, room.width, room.height); + } +} diff --git a/worldbuilder.cpp b/worldbuilder.cpp index db412da..1bdd275 100644 --- a/worldbuilder.cpp +++ b/worldbuilder.cpp @@ -137,10 +137,7 @@ void WorldBuilder::generate_rooms() { } void WorldBuilder::generate_map() { - matrix::dump("BEFORE MAZE:", $map.$walls); - maze::recursive_div($map.$walls, $map.$rooms); - matrix::dump("AFTER MAZE:", $map.$walls); - + maze::hunt_and_kill($map.$walls, $map.$rooms); $map.expand(); $map.load_tiles();