Slight better but I think place_doors can be even better.

This commit is contained in:
Zed A. Shaw 2026-03-15 01:21:33 -04:00
parent f304538325
commit 908f5bfb3e
4 changed files with 37 additions and 36 deletions

View file

@ -125,13 +125,12 @@ namespace maze {
void Builder::randomize_rooms(size_t room_size) {
std::shuffle($dead_ends.begin(), $dead_ends.end(), Random::GENERATOR);
size_t max_rooms = room_sweetspot($width, room_size);
// use those dead ends to randomly place rooms
for(auto at : $dead_ends) {
// skip 50% of them
// if(Random::uniform(0,1) == 0) continue;
// don't bother with dead ends near the edge
if(at.x < 2 || at.y < 2 || at.x > $width - 3 || at.y > $height - 3) continue;
// quit after we've hit the room max threshold
if($rooms.size() > max_rooms) break;
@ -242,16 +241,18 @@ namespace maze {
void Builder::dump(const std::string& msg, bool path_too) {
auto wall_copy = $walls;
// mark the rooms too
// mark the rooms too, but not if pathing
if(!path_too) {
for(auto& room : $rooms) {
for(matrix::rectangle it{wall_copy, room.x, room.y, room.width, room.height};
it.next();)
{
if(wall_copy[it.y][it.x] == 0 && wall_copy[it.y][it.x] != 3) {
if(wall_copy[it.y][it.x] == 0) {
wall_copy[it.y][it.x] = ROOM_SPACE_VALUE;
}
}
}
}
// mark dead ends
for(auto at : $dead_ends) {
@ -306,7 +307,7 @@ namespace maze {
}
}
void Builder::make_doors() {
void Builder::place_doors() {
for(auto room : $rooms) {
// walk the outer wall looking for an emergent door
int possible_doors = 0;
@ -315,7 +316,8 @@ namespace maze {
matrix::perimeter it{room.x - 1, room.y - 1, room.width + 2, room.height + 2};
while(it.next()) {
if(matrix::inbounds($walls, it.x, it.y) && $walls[it.y][it.x] == SPACE_VALUE) {
if(space_available(it.x, it.y)) {
// IN_BOUNDS CHECK, or maybe a can_place or is_available?
last_door = {it.x, it.y};
possible_doors++;
}
@ -335,11 +337,12 @@ namespace maze {
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(!space_available(near_door.x, near_door.y)) 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
// IN_BOUNDS_HERE
last_door = {it.x, it.y};
} else {
$walls[it.y][it.x] = SPACE_VALUE;
@ -406,7 +409,7 @@ namespace maze {
// 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);
Room test_room = $rooms.at(rand(0, $rooms.size() - 1));
Point test{test_room.x, test_room.y};
$paths.set_target(test);
$paths.compute_paths($walls);
@ -423,10 +426,13 @@ namespace maze {
return true;
}
void Builder::in_bounds(size_t x, size_t y) {
if(x > $width) {
}
bool Builder::space_available(size_t x, size_t y) {
bool in_bounds = matrix::inbounds($walls, x, y);
bool is_space = $walls[y][x] == SPACE_VALUE;
bool not_perimeter = x > 0 && y > 0 && x < $width - 2 && y < $height - 2;
dbc::check(x != $width, "bad x");
dbc::check(y != $height, "bad y");
return in_bounds && is_space && not_perimeter;
}
void Builder::punch_dead_end(size_t at_x, size_t at_y, size_t x, size_t y) {
@ -461,22 +467,17 @@ namespace maze {
}
// now go back and see if we can add any back
int added_back = 0;
for(auto& at : removed_ends) {
auto temp = $walls[at.y][at.x];
$walls[at.y][at.x] = WALL_VALUE;
if(!validate()) {
$walls[at.y][at.x] = SPACE_VALUE;
} else {
added_back++;
$walls[at.y][at.x] = temp;
}
}
enclose();
now_valid = validate();
// didn't find a way to make it valid
return now_valid;
return validate();
}
std::pair<Builder, bool> script(Map& map, nlohmann::json& config) {
@ -498,8 +499,8 @@ namespace maze {
} else if(aname == "open_box") {
std::vector<int> data = action["data"];
maze.open_box(data[0]);
} else if(aname == "make_doors") {
maze.make_doors();
} else if(aname == "place_doors") {
maze.place_doors();
} else if(aname == "divide") {
std::vector<size_t> data = action["data"];
maze.divide({data[0], data[1]}, {data[2], data[3]});

View file

@ -41,11 +41,11 @@ namespace maze {
void open_box(size_t outer_size);
void add_dead_end(Point at);
bool room_should_exist(Room& room, bool allow_dupes=false);
void make_doors();
void place_doors();
bool validate();
bool repair();
void punch_dead_end(size_t at_x, size_t at_y, size_t x, size_t y);
void in_bounds(size_t x, size_t y);
bool space_available(size_t x, size_t y);
};
std::pair<Builder, bool> script(Map& map, nlohmann::json& config);

View file

@ -48,7 +48,7 @@ void WorldBuilder::generate_map() {
{"action": "clear"},
{"action": "randomize_rooms", "data": [3]},
{"action": "hunt_and_kill"},
{"action": "make_doors"}
{"action": "place_doors"}
]
)"_json;

View file

@ -23,7 +23,7 @@ TEST_CASE("hunt-and-kill", "[mazes]") {
maze.randomize_rooms(ROOM_SIZE);
maze.hunt_and_kill();
maze.make_doors();
maze.place_doors();
REQUIRE(maze.repair() == true);
if(DUMP) maze.dump("ROOM MAZE");
@ -44,7 +44,7 @@ TEST_CASE("hunt-and-kill box", "[mazes]") {
maze.hunt_and_kill();
maze.open_box(6);
maze.make_doors();
maze.place_doors();
auto valid = maze.repair();
if(i == 41 && DUMP) {
@ -101,7 +101,7 @@ TEST_CASE("hunt-and-kill too much", "[mazes]") {
maze.inner_donut(9, 4);
maze.divide({3,3}, {15,16});
maze.hunt_and_kill();
maze.make_doors();
maze.place_doors();
auto valid = maze.repair();
if(i == 41 && DUMP && valid) {
@ -127,7 +127,7 @@ TEST_CASE("hunt-and-kill validator", "[mazes]") {
maze.randomize_rooms(ROOM_SIZE);
maze.hunt_and_kill();
maze.open_box(6);
maze.make_doors();
maze.place_doors();
valid = maze.repair();
if(i == 9 && DUMP) {
@ -165,7 +165,7 @@ TEST_CASE("hunt-and-kill scripting", "[mazes]") {
{"action": "hunt_and_kill"},
{"action": "open_box", "data": [6]},
{"action": "remove_dead_ends"},
{"action": "make_doors"}
{"action": "place_doors"}
]
)"_json;