I can validate that a map is pathable, but can't fix it.

This commit is contained in:
Zed A. Shaw 2026-03-10 00:42:58 -04:00
parent 74f92dfe2c
commit 8090251a71
7 changed files with 116 additions and 21 deletions

View file

@ -7,7 +7,6 @@
using std::string;
using matrix::Matrix;
namespace maze {
inline size_t rand(size_t i, size_t j) {
if(i < j) {
@ -94,7 +93,7 @@ namespace maze {
dbc::sentinel("failed to find coord?");
}
bool Builder::room_should_exist(Room& room) {
bool Builder::room_should_exist(Room& room, bool allow_dupes) {
if(!matrix::inbounds($walls, room.x, room.y) ||
!matrix::inbounds($walls, room.x + room.width, room.y + room.height))
{
@ -106,7 +105,11 @@ namespace maze {
}
for(auto& other : $rooms) {
if(room.overlaps(other)) return false;
bool is_duped = allow_dupes ? room == other : room != other;
if(is_duped && room.overlaps(other)) {
return false;
}
}
// it's in the map and doesn't collide with another room
@ -181,8 +184,6 @@ namespace maze {
on = nb;
}
}
enclose();
}
void Builder::place_rooms() {
@ -191,8 +192,6 @@ namespace maze {
$walls[it.y][it.x] = 0;
}
}
enclose();
}
void Builder::inner_donut(float outer_rad, float inner_rad) {
@ -245,7 +244,11 @@ namespace maze {
// mark dead ends
for(auto at : $dead_ends) {
// don't mark dead ends if there's something else there
wall_copy[at.y][at.x]=32;
wall_copy[at.y][at.x] = 32;
}
for(auto [at, _] : $doors) {
wall_copy[at.y][at.x] = 0xd;
}
matrix::dump(msg, wall_copy);
@ -273,7 +276,9 @@ namespace maze {
size_t height = matrix::height($walls);
perimeter(0, 0, width, height, [&](size_t x, size_t y) {
$walls[y][x] = 1;
$walls[y][x] = WALL_VALUE;
Point at{x,y};
if($doors.contains(at)) $doors.erase(at);
});
}
@ -303,20 +308,35 @@ namespace maze {
void Builder::make_doors() {
for(auto room : $rooms) {
// BUG: still makes rooms without doors, so detect if no door added and brute force one in
perimeter(room.x, room.y, room.width, room.height, [&](auto x, auto y) {
// walk the outer wall looking for an emergent door
int has_door = 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++;
}
});
// if only found one then make that an actual door
if(has_door == 1) {
$doors.insert_or_assign(last_door, true);
}
// 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);
break;
}
}
}
});
}
enclose();
}
void Builder::inner_box(size_t outer_size, size_t inner_size) {
@ -338,10 +358,51 @@ namespace maze {
}
void Builder::add_dead_end(Point at) {
// doing this ensures no dupes, if it's !inserted then it already existed
auto [_, inserted] = $ends_map.insert_or_assign(at, true);
// so skip it, it isn't new
if(inserted) {
$dead_ends.push_back(at);
}
}
bool Builder::validate() {
size_t width = matrix::width($walls);
size_t height = matrix::height($walls);
// no rooms can overlap
for(auto& room : $rooms) {
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;
if($rooms.size() == 1) return true;
// initial path test can just use one room then look for
// any cells that are empty in the walls map but unpathed in the paths
Room test_room = $rooms.at(0);
Point test{test_room.x, test_room.y};
$paths.set_target(test);
$paths.compute_paths($walls);
$paths.dump("AFTER COMPUTE");
$paths.clear_target(test);
for(matrix::each_cell it{$walls}; it.next();) {
if($walls[it.y][it.x] == SPACE_VALUE &&
$paths.$paths[it.y][it.x] == WALL_PATH_LIMIT) {
return false;
}
}
return true;
}
}