Hunt-and-kill algorithm rocks. It handles everything I need for map gen, including spawn points, room placement, and the maze like map.
This commit is contained in:
parent
0f8e61797f
commit
a0b785cb2a
8 changed files with 62 additions and 336 deletions
175
maze.cpp
175
maze.cpp
|
@ -18,134 +18,7 @@ inline size_t rand(size_t i, size_t j) {
|
|||
}
|
||||
|
||||
|
||||
inline bool split_dir(size_t iDim, size_t jDim) {
|
||||
if(iDim < jDim) {
|
||||
return false;
|
||||
} else if(jDim < iDim) {
|
||||
return true;
|
||||
} else {
|
||||
return Random::uniform(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool good_hole(Matrix &map, size_t split, size_t hole, bool horiz) {
|
||||
if(hole % 2 == 0) return false;
|
||||
|
||||
size_t j = horiz ? split : hole;
|
||||
size_t i = horiz ? hole : split;
|
||||
if(map[j][i] == WALL_PATH_LIMIT) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void divide(Matrix& map, std::vector<Room> &rooms,
|
||||
Point iCoords, Point jCoords, bool horizontal) {
|
||||
int iDim = iCoords.y - iCoords.x;
|
||||
int jDim = jCoords.y - jCoords.x;
|
||||
bool punch_room = false;
|
||||
|
||||
if(iDim <= 0 || jDim <= 0) {
|
||||
return;
|
||||
} else if(iDim <= 2 && jDim <= 2) {
|
||||
fmt::println("MADE ROOM! {},{}; {},{}",
|
||||
iCoords.x, iCoords.y, jCoords.x, jCoords.y);
|
||||
punch_room = true;
|
||||
}
|
||||
|
||||
if(horizontal) {
|
||||
size_t split = 0;
|
||||
do {
|
||||
split = rand(iCoords.x, iCoords.x + iDim + 1);
|
||||
} while(split % 2);
|
||||
|
||||
size_t hole = 0;
|
||||
do {
|
||||
hole = rand(jCoords.x, jCoords.x + jDim +1);
|
||||
} while(good_hole(map, split, hole, horizontal));
|
||||
|
||||
for(size_t j = jCoords.x; j <= jCoords.y; j++) {
|
||||
if(j != hole) {
|
||||
map[split][j] = WALL_PATH_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
divide(map, rooms,
|
||||
{iCoords.x, size_t(split - 1)},
|
||||
jCoords,
|
||||
split_dir(split - iCoords.x - 1, jDim));
|
||||
|
||||
divide(map, rooms,
|
||||
{size_t(split + 1), iCoords.y},
|
||||
jCoords,
|
||||
split_dir(iCoords.x - split - 1, jDim));
|
||||
} else {
|
||||
size_t split = 0;
|
||||
do {
|
||||
split = rand(jCoords.x, jCoords.x + jDim + 1);
|
||||
} while(split % 2);
|
||||
|
||||
size_t hole = 0;
|
||||
do {
|
||||
hole = rand(iCoords.x, iCoords.x + iDim + 1);
|
||||
} while(good_hole(map, split, hole, horizontal));
|
||||
|
||||
for(size_t i = iCoords.x; i <= iCoords.y; i++) {
|
||||
if(i != hole) {
|
||||
map[i][split] = WALL_PATH_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
divide(map, rooms,
|
||||
iCoords,
|
||||
{jCoords.x, size_t(split - 1)},
|
||||
split_dir(iDim, split - jCoords.x - 1));
|
||||
|
||||
divide(map, rooms,
|
||||
iCoords,
|
||||
{size_t(split + 1), jCoords.y},
|
||||
Random::uniform(0, 1));
|
||||
}
|
||||
|
||||
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;
|
||||
// }
|
||||
// }
|
||||
|
||||
Room room{iCoords.x, jCoords.x, iCoords.y - iCoords.x + 1, jCoords.y - jCoords.x + 1};
|
||||
|
||||
for(auto r : rooms) {
|
||||
if(r.x == room.x && r.y == room.y) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rooms.push_back(room);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void maze::recursive_div(Matrix& map, std::vector<Room>& rooms) {
|
||||
size_t width = matrix::width(map);
|
||||
size_t height = matrix::height(map);
|
||||
|
||||
for(size_t i = 0; i < height; i++) {
|
||||
for(size_t j = 0; j < width; j++) {
|
||||
int val = (i == 0 ||
|
||||
j == 0 ||
|
||||
i == height - 1 ||
|
||||
j == width - 1);
|
||||
|
||||
map[i][j] = val == 1 ? WALL_PATH_LIMIT : 0;
|
||||
}
|
||||
}
|
||||
|
||||
divide(map, rooms, {1, height - 2}, {1, width - 2}, split_dir(1, 1));
|
||||
}
|
||||
|
||||
|
||||
bool complete(Matrix& maze) {
|
||||
inline bool complete(Matrix& maze) {
|
||||
size_t width = matrix::width(maze);
|
||||
size_t height = matrix::height(maze);
|
||||
|
||||
|
@ -190,7 +63,7 @@ std::vector<Point> neighbors(Matrix& maze, Point on) {
|
|||
|
||||
for(auto point : points) {
|
||||
if(matrix::inbounds(maze, point.x, point.y)) {
|
||||
if(maze[point.y][point.x] == WALL_PATH_LIMIT) {
|
||||
if(maze[point.y][point.x] == WALL_VALUE) {
|
||||
result.push_back(point);
|
||||
}
|
||||
}
|
||||
|
@ -199,13 +72,13 @@ std::vector<Point> neighbors(Matrix& maze, Point on) {
|
|||
return result;
|
||||
}
|
||||
|
||||
std::pair<Point, Point> findCoord(Matrix& maze) {
|
||||
inline std::pair<Point, Point> find_coord(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) {
|
||||
if(maze[y][x] == WALL_VALUE) {
|
||||
auto found = neighborsAB(maze, {x, y});
|
||||
|
||||
for(auto point : found) {
|
||||
|
@ -221,34 +94,35 @@ std::pair<Point, Point> findCoord(Matrix& 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);
|
||||
void maze::hunt_and_kill(Matrix& maze, std::vector<Room>& rooms, std::vector<Point>& dead_ends) {
|
||||
matrix::assign(maze, WALL_VALUE);
|
||||
|
||||
Room start{2, 2, 3, 3};
|
||||
rooms.push_back(start);
|
||||
Room goal{width-4, height-4, 3, 3};
|
||||
rooms.push_back(goal);
|
||||
Point last_even{0,0};
|
||||
|
||||
for(auto& room : rooms) {
|
||||
for(matrix::box it{maze, room.x, room.y, 1}; it.next();) {
|
||||
if(room.x % 2 == 0 && room.y % 2 == 0) {
|
||||
last_even = {room.x, room.y};
|
||||
}
|
||||
|
||||
for(matrix::box it{maze, room.x, room.y, room.width}; 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);
|
||||
dead_ends.push_back(on);
|
||||
auto t = find_coord(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)];
|
||||
auto nb = n[rand(size_t(0), n.size() - 1)];
|
||||
maze[nb.y][nb.x] = 0;
|
||||
|
||||
size_t row = (nb.y + on.y) / 2;
|
||||
|
@ -257,4 +131,21 @@ void maze::hunt_and_kill(Matrix& maze, std::vector<Room>& rooms) {
|
|||
on = nb;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto at : dead_ends) {
|
||||
for(auto& room : rooms) {
|
||||
Point room_ul{room.x - room.width - 1, room.y - room.height - 1};
|
||||
Point room_lr{room.x + room.width - 1, room.y + room.height - 1};
|
||||
if(at.x >= room_ul.x && at.y >= room_ul.y &&
|
||||
at.x <= room_lr.x && at.y <= room_lr.y)
|
||||
{
|
||||
for(matrix::compass it{maze, at.x, at.y}; it.next();) {
|
||||
if(maze[it.y][it.x] == 1) {
|
||||
maze[it.y][it.x] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue