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

View file

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

View file

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