Now using a hunt-and-kill maze algorithm.

master
Zed A. Shaw 2 weeks ago
parent 7a0b2f988d
commit 0f8e61797f
  1. 125
      maze.cpp
  2. 2
      maze.hpp
  3. 16
      tests/mazes.cpp
  4. 5
      worldbuilder.cpp

@ -107,11 +107,11 @@ void divide(Matrix& map, std::vector<Room> &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<Room>& 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<Point> neighborsAB(Matrix& maze, Point on) {
std::vector<Point> result;
std::array<Point, 4> 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<Point> neighbors(Matrix& maze, Point on) {
std::vector<Point> result;
std::array<Point, 4> 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<Point, Point> 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<Room>& 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;
}
}
}

@ -4,4 +4,6 @@
namespace maze {
void recursive_div(matrix::Matrix& map, std::vector<Room>& rooms);
void hunt_and_kill(Matrix& maze, std::vector<Room>& rooms);
}

@ -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<Room> 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<Room> 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);
}
}

@ -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();

Loading…
Cancel
Save