More refinement of the maps. Now the inner box won't have rooms in it and I can mark a region free of rooms. Rooms also have a guaranteed door.

This commit is contained in:
Zed A. Shaw 2026-03-08 12:25:40 -04:00
parent 87a1193a4a
commit 8b129aea6b
4 changed files with 40 additions and 33 deletions

View file

@ -101,6 +101,10 @@ namespace maze {
return false; return false;
} }
if(room.overlaps($no_rooms_region)) {
return false;
}
for(auto& other : $rooms) { for(auto& other : $rooms) {
if(room.overlaps(other)) return false; if(room.overlaps(other)) return false;
} }
@ -113,8 +117,7 @@ namespace maze {
// use those dead ends to randomly place rooms // use those dead ends to randomly place rooms
for(auto at : $dead_ends) { for(auto at : $dead_ends) {
// moving by +1 can randomly surround rooms with walls or not // moving by +1 can randomly surround rooms with walls or not
size_t offset = Random::uniform(0,1); Room cur{at.x, at.y, room_size, room_size};
Room cur{at.x+offset, at.y+offset, room_size, room_size};
bool selected = Random::uniform(0,1) == 0; bool selected = Random::uniform(0,1) == 0;
// if it's out of bounds skip it // if it's out of bounds skip it
@ -184,16 +187,14 @@ namespace maze {
size_t x = matrix::width($walls) / 2; size_t x = matrix::width($walls) / 2;
size_t y = matrix::height($walls) / 2; size_t y = matrix::height($walls) / 2;
for(matrix::circle it{$walls, {x, y}, outer_rad}; for(matrix::circle it{$walls, {x, y}, outer_rad}; it.next();)
it.next();)
{ {
for(int x = it.left; x < it.right; x++) { for(int x = it.left; x < it.right; x++) {
$walls[it.y][x] = 0; $walls[it.y][x] = 0;
} }
} }
for(matrix::circle it{$walls, {x, y}, inner_rad}; for(matrix::circle it{$walls, {x, y}, inner_rad}; it.next();)
it.next();)
{ {
for(int x = it.left; x < it.right; x++) { for(int x = it.left; x < it.right; x++) {
$walls[it.y][x] = 1; $walls[it.y][x] = 1;
@ -288,6 +289,23 @@ namespace maze {
}); });
} }
void Builder::make_doors() {
for(auto room : $rooms) {
perimeter(room.x, room.y, room.width, room.height, [&](auto x, auto 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;
break;
}
}
}
});
}
enclose();
}
void Builder::inner_box(size_t outer_size, size_t inner_size) { void Builder::inner_box(size_t outer_size, size_t inner_size) {
size_t x = matrix::width($walls) / 2; size_t x = matrix::width($walls) / 2;
size_t y = matrix::height($walls) / 2; size_t y = matrix::height($walls) / 2;
@ -301,6 +319,9 @@ namespace maze {
{ {
$walls[it.y][it.x] = 1; $walls[it.y][it.x] = 1;
} }
// make a fake room that blocks others
$no_rooms_region = {x - outer_size, y - outer_size, outer_size * 2 + 1, outer_size * 2 + 1};
} }
void Builder::add_dead_end(Point at) { void Builder::add_dead_end(Point at) {

View file

@ -10,6 +10,7 @@ namespace maze {
std::vector<Room>& $rooms; std::vector<Room>& $rooms;
std::vector<Point>& $dead_ends; std::vector<Point>& $dead_ends;
std::unordered_map<Point, bool> $ends_map; std::unordered_map<Point, bool> $ends_map;
Room $no_rooms_region{0,0,0,0};
Builder(Map& map) : Builder(Map& map) :
$walls(map.$walls), $rooms(map.$rooms), $dead_ends(map.$dead_ends) $walls(map.$walls), $rooms(map.$rooms), $dead_ends(map.$dead_ends)
@ -32,5 +33,6 @@ namespace maze {
void open_box(size_t outer_size); void open_box(size_t outer_size);
void add_dead_end(Point at); void add_dead_end(Point at);
bool room_should_exist(Room& room); bool room_should_exist(Room& room);
void make_doors();
}; };
} }

View file

@ -14,25 +14,6 @@
using lighting::LightSource; using lighting::LightSource;
/*
struct Point {
double x;
double y;
};
struct Rect {
Point p1, p2, p3, p4;
// four corners (any order)
bool contains(const Point& pt) const {
double minX = std::min({p1.x, p2.x, p3.x, p4.x});
double maxX = std::max({p1.x, p2.x, p3.x, p4.x});
double minY = std::min({p1.y, p2.y, p3.y, p4.y});
double maxY = std::max({p1.y, p2.y, p3.y, p4.y});
return pt.x >= minX && pt.x <= maxX && pt.y >= minY && pt.y <= maxY;
}
};
*/
struct Room { struct Room {
size_t x = 0; size_t x = 0;
size_t y = 0; size_t y = 0;

View file

@ -18,6 +18,7 @@ TEST_CASE("hunt-and-kill", "[mazes]") {
maze.randomize_rooms(ROOM_SIZE); maze.randomize_rooms(ROOM_SIZE);
maze.hunt_and_kill(); maze.hunt_and_kill();
maze.make_doors();
// maze.dump("ROOM MAZE"); // maze.dump("ROOM MAZE");
REQUIRE(map.$dead_ends.size() > 0); REQUIRE(map.$dead_ends.size() > 0);
@ -30,15 +31,16 @@ TEST_CASE("hunt-and-kill box", "[mazes]") {
maze::Builder maze(map); maze::Builder maze(map);
maze.hunt_and_kill(); maze.hunt_and_kill();
maze.randomize_rooms(ROOM_SIZE+1);
maze.clear(); maze.clear();
maze.inner_box(6, 4);
maze.randomize_rooms(ROOM_SIZE+2);
maze.inner_box(6, 3);
maze.hunt_and_kill(); maze.hunt_and_kill();
maze.open_box(6); maze.open_box(6);
maze.make_doors();
if(maze.$rooms.size() == 0) { if(i == 42) {
maze.dump("NO ROOMS"); maze.dump("INNER BOX");
} }
} }
} }
@ -67,8 +69,6 @@ TEST_CASE("hunt-and-kill fissure", "[mazes]") {
REQUIRE(maze.$rooms.size() == 0); REQUIRE(maze.$rooms.size() == 0);
} }
TEST_CASE("hunt-and-kill no-dead-ends", "[mazes]") { TEST_CASE("hunt-and-kill no-dead-ends", "[mazes]") {
Map map(21, 21); Map map(21, 21);
maze::Builder maze(map); maze::Builder maze(map);
@ -88,10 +88,13 @@ TEST_CASE("hunt-and-kill too much", "[mazes]") {
maze.hunt_and_kill(); maze.hunt_and_kill();
maze.randomize_rooms(ROOM_SIZE); maze.randomize_rooms(ROOM_SIZE);
maze.clear(); maze.clear();
maze.inner_donut(4, 2); maze.inner_donut(9, 4);
maze.divide({3,3}, {15,16}); maze.divide({3,3}, {15,16});
maze.hunt_and_kill(); maze.hunt_and_kill();
maze.make_doors();
// maze.dump("COMBINED"); // if(i == 41) {
// maze.dump("COMBINED");
// }
} }
} }