Initial fix for large center rooms not having entry exit.

This commit is contained in:
Zed A. Shaw 2026-03-07 00:10:42 -05:00
parent da7f24c126
commit 47c0d4a5f0
8 changed files with 130 additions and 85 deletions

View file

@ -7,6 +7,8 @@
using std::string;
using matrix::Matrix;
constexpr const int ROOM_SIZE=1;
namespace maze {
inline size_t rand(size_t i, size_t j) {
if(i < j) {
@ -18,7 +20,6 @@ namespace maze {
}
}
inline bool complete(Matrix& maze) {
size_t width = matrix::width(maze);
size_t height = matrix::height(maze);
@ -97,9 +98,19 @@ namespace maze {
void Builder::randomize_rooms() {
// use those dead ends to randomly place rooms
for(auto at : $dead_ends) {
if(Random::uniform(0,1)) {
size_t offset = Random::uniform(0,1);
Room cur{at.x+offset, at.y+offset, 1, 1};
// moving by +1 can randomly surround rooms with walls or not
size_t offset = Random::uniform(0,1);
Room cur{at.x+offset, at.y+offset, ROOM_SIZE, ROOM_SIZE};
// if it's out of bounds skip it
if(!matrix::inbounds($walls, cur.x, cur.y)
|| !matrix::inbounds($walls, cur.x + cur.width, cur.y + cur.height))
{
continue;
}
// randomly select 2/3rd
if(Random::uniform(0,2) > 0) {
$rooms.push_back(cur);
}
}
@ -117,15 +128,13 @@ namespace maze {
}
void Builder::hunt_and_kill(Point on) {
for(auto& room : $rooms) {
for(matrix::box it{$walls, room.x, room.y, room.width}; it.next();) {
$walls[it.y][it.x] = 0;
}
}
if($rooms.size() > 0) place_rooms();
while(!complete($walls)) {
auto n = neighbors($walls, on);
if(n.size() == 0) {
// no neighbors, must be dead end
$dead_ends.push_back(on);
auto t = find_coord($walls);
on = t.first;
@ -134,6 +143,7 @@ namespace maze {
size_t col = (on.x + t.second.x) / 2;
$walls[row][col] = 0;
} else {
// found neighbors, pick random one
auto nb = n[rand(size_t(0), n.size() - 1)];
$walls[nb.y][nb.x] = 0;
@ -144,23 +154,22 @@ namespace maze {
}
}
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($rooms.size() > 0) ensure_doors();
enclose();
}
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{$walls, at.x, at.y}; it.next();) {
if($walls[it.y][it.x] == 1) {
$walls[it.y][it.x] = 0;
break;
}
}
}
void Builder::ensure_doors() {
// NEED TO REWRITE
}
void Builder::place_rooms() {
for(auto& room : $rooms) {
for(matrix::box it{$walls, room.x, room.y, room.width}; it.next();) {
$walls[it.y][it.x] = 0;
}
}
enclose();
}
void Builder::inner_donut(float outer_rad, float inner_rad) {
@ -184,24 +193,6 @@ namespace maze {
}
}
void Builder::inner_box(size_t outer_size, size_t inner_size) {
size_t x = matrix::width($walls) / 2;
size_t y = matrix::height($walls) / 2;
for(matrix::box it{$walls, x, y, outer_size};
it.next();)
{
$walls[it.y][it.x] = 0;
}
for(matrix::box it{$walls, x, y, inner_size};
it.next();)
{
$walls[it.y][it.x] = 1;
}
}
void Builder::remove_dead_ends() {
dbc::check($dead_ends.size() > 0, "you have to run an algo first, no dead_ends to remove");
for(auto at : $dead_ends) {
@ -216,6 +207,90 @@ namespace maze {
}
void Builder::dump(const std::string& msg) {
matrix::dump(msg, $walls);
auto wall_copy = $walls;
// mark the rooms too
for(auto& room : $rooms) {
for(matrix::box it{wall_copy, room.x, room.y, room.width};
it.next();)
{
if(wall_copy[it.y][it.x] == 0) {
wall_copy[it.y][it.x] = WALL_PATH_LIMIT;
}
}
}
// mark dead ends
for(auto at : $dead_ends) {
wall_copy[at.y][at.x]=32;
}
matrix::dump(msg, wall_copy);
}
void Builder::perimeter(size_t x, size_t y, size_t width, size_t height, std::function<void(size_t x, size_t y)> cb) {
std::array<Point, 4> starts{{
{x,y}, {x + width-1, y}, {x + width-1, y + height-1}, {x, y + height-1}
}};
std::array<Point, 4> ends{{
{x + width-1, y}, {x + width-1, y + height-1}, {x, y + height-1}, {x,y},
}};
for(size_t i = 0; i < starts.size(); i++) {
for(matrix::line it{starts[i], ends[i]}; it.next();) {
cb(it.x, it.y);
}
}
}
void Builder::enclose() {
size_t width = matrix::width($walls);
size_t height = matrix::height($walls);
perimeter(0, 0, width, height, [&](size_t x, size_t y) {
$walls[y][x] = 1;
});
}
void Builder::open_box(size_t outer_size, size_t inner_size) {
size_t center_x = matrix::width($walls) / 2;
size_t center_y = matrix::height($walls) / 2;
// this can't be right but for now it's working
size_t x = center_x - outer_size - 1;
size_t y = center_y - outer_size - 1;
size_t width = (outer_size + 1) * 2 + 1;
size_t height = (outer_size + 1) * 2 + 1;
std::unordered_map<Point, bool> ends;
for(auto& at : $dead_ends) {
ends.insert_or_assign(at, true);
}
perimeter(x, y, width, height, [&](size_t x, size_t y) {
for(matrix::compass it{$walls, x, y}; it.next();) {
if(ends.contains({it.x, it.y})) {
$walls[y][x] = 0;
break;
}
}
});
}
void Builder::inner_box(size_t outer_size, size_t inner_size) {
size_t x = matrix::width($walls) / 2;
size_t y = matrix::height($walls) / 2;
for(matrix::box it{$walls, x, y, outer_size}; it.next();)
{
$walls[it.y][it.x] = 0;
}
for(matrix::box it{$walls, x, y, inner_size}; it.next();)
{
$walls[it.y][it.x] = 1;
}
}
}