From 908f5bfb3efbb8415bf030e8bee2ef761a971d40 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Sun, 15 Mar 2026 01:21:33 -0400 Subject: [PATCH] Slight better but I think place_doors can be even better. --- src/algos/maze.cpp | 57 ++++++++++++++++++++------------------- src/algos/maze.hpp | 4 +-- src/game/worldbuilder.cpp | 2 +- tests/mazes.cpp | 10 +++---- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/algos/maze.cpp b/src/algos/maze.cpp index e5f2ca8..71969bf 100644 --- a/src/algos/maze.cpp +++ b/src/algos/maze.cpp @@ -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,13 +241,15 @@ namespace maze { void Builder::dump(const std::string& msg, bool path_too) { auto wall_copy = $walls; - // mark the rooms 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) { - wall_copy[it.y][it.x] = ROOM_SPACE_VALUE; + // 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] = ROOM_SPACE_VALUE; + } } } } @@ -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 script(Map& map, nlohmann::json& config) { @@ -498,8 +499,8 @@ namespace maze { } else if(aname == "open_box") { std::vector 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 data = action["data"]; maze.divide({data[0], data[1]}, {data[2], data[3]}); diff --git a/src/algos/maze.hpp b/src/algos/maze.hpp index 4d7a347..247a564 100644 --- a/src/algos/maze.hpp +++ b/src/algos/maze.hpp @@ -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 script(Map& map, nlohmann::json& config); diff --git a/src/game/worldbuilder.cpp b/src/game/worldbuilder.cpp index 816cf23..2691831 100644 --- a/src/game/worldbuilder.cpp +++ b/src/game/worldbuilder.cpp @@ -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; diff --git a/tests/mazes.cpp b/tests/mazes.cpp index 031e3d1..d66a71b 100644 --- a/tests/mazes.cpp +++ b/tests/mazes.cpp @@ -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;