Better map generation and a test that re-rolls maps that aren't valid to figure out the stats of map gen failures.

This commit is contained in:
Zed A. Shaw 2026-03-11 12:31:51 -04:00
parent 8090251a71
commit f85ae8a6c6
12 changed files with 131 additions and 76 deletions

View file

@ -254,32 +254,15 @@ namespace maze {
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) {
// BUG: is the -1 on these an off-by-one
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] = WALL_VALUE;
Point at{x,y};
for(matrix::perimeter it{0, 0, width, height}; it.next();) {
$walls[it.y][it.x] = WALL_VALUE;
Point at{it.x,it.y};
if($doors.contains(at)) $doors.erase(at);
});
}
}
void Builder::open_box(size_t outer_size) {
@ -296,46 +279,66 @@ namespace maze {
size_t width = (outer_size * 2) + 1;
size_t height = (outer_size * 2) + 1;
perimeter(x, y, width, height, [&](size_t x, size_t y) {
for(matrix::compass it{$walls, x, y}; it.next();) {
for(matrix::perimeter p{x, y, width, height}; p.next();) {
for(matrix::compass it{$walls, p.x, p.y}; it.next();) {
if($ends_map.contains({it.x, it.y})) {
$walls[y][x] = 0;
break;
}
}
});
}
}
void Builder::make_doors() {
for(auto room : $rooms) {
// walk the outer wall looking for an emergent door
int has_door = 0;
int possible_doors = 0;
Point last_door{0,0};
perimeter(room.x - 1, room.y - 1, room.width + 2, room.height + 2, [&](size_t x, size_t y) {
if($walls[y][x] == SPACE_VALUE) {
last_door = {x, y};
has_door++;
}
});
matrix::perimeter it{room.x - 1, room.y - 1, room.width + 2, room.height + 2};
// if only found one then make that an actual door
if(has_door == 1) {
$doors.insert_or_assign(last_door, true);
while(it.next()) {
if($walls[it.y][it.x] == SPACE_VALUE) {
last_door = {it.x, it.y};
possible_doors++;
}
}
// no emergent door found, punch out one
perimeter(room.x, room.y, room.width, room.height, [&](size_t x, size_t y) {
if($ends_map.contains({x, y})) {
for(matrix::compass door_at{$walls, x, y}; door_at.next();) {
if($walls[door_at.y][door_at.x] == WALL_VALUE) {
$walls[door_at.y][door_at.x] = SPACE_VALUE;
$doors.insert_or_assign({size_t(door_at.x), size_t(door_at.y)}, true);
// if only found one then make that an actual door
if(possible_doors == 1) {
$doors.insert_or_assign(last_door, true);
continue;
}
// no natural door found, need to make one
it = {room.x - 1, room.y - 1, room.width + 2, room.height + 2};
last_door = {0,0};
bool found_door = false;
while(it.next()) {
for(matrix::compass near_door{$walls, it.x, it.y}; near_door.next();) {
// skip the wall parts
if($walls[near_door.y][near_door.x] == WALL_VALUE) continue;
if($ends_map.contains({near_door.x, near_door.y})) {
if(room.contains({near_door.x, near_door.y})) {
// last ditch effort is use the internal dead end
last_door = {it.x, it.y};
} else {
$walls[it.y][it.x] = SPACE_VALUE;
$doors.insert_or_assign({it.x, it.y}, true);
found_door = true;
break;
}
}
}
});
}
if(!found_door && last_door.x != 0) {
// didn't find an external door so punch one at the dead end
$walls[last_door.y][last_door.x] = SPACE_VALUE;
$doors.insert_or_assign({last_door.x, last_door.y}, true);
}
}
}
@ -376,14 +379,10 @@ namespace maze {
if(!room_should_exist(room)) return false;
}
bool bad_perimeter = false;
// BUG: this is dogshit, get rid of perimeter, I can't even spell it right it's so bad
perimeter(0, 0, width, height, [&](size_t x, size_t y) {
if($ends_map.contains({x, y})) bad_perimeter = true;
if($doors.contains({x, y})) bad_perimeter = true;
});
if(bad_perimeter) return false;
for(matrix::perimeter it{0, 0, width, height}; it.next();) {
if($ends_map.contains({it.x, it.y})) return false;
if($doors.contains({it.x, it.y})) return false;
}
if($rooms.size() == 1) return true;
@ -393,7 +392,7 @@ namespace maze {
Point test{test_room.x, test_room.y};
$paths.set_target(test);
$paths.compute_paths($walls);
$paths.dump("AFTER COMPUTE");
// $paths.dump("AFTER COMPUTE");
$paths.clear_target(test);
for(matrix::each_cell it{$walls}; it.next();) {