Tests now run the repair() step.
This commit is contained in:
parent
e6fcbd8dcf
commit
a71d6340db
3 changed files with 43 additions and 45 deletions
|
|
@ -3,6 +3,7 @@
|
|||
#include "algos/rand.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "algos/maze.hpp"
|
||||
#include <ranges>
|
||||
|
||||
using std::string;
|
||||
using matrix::Matrix;
|
||||
|
|
@ -18,10 +19,7 @@ namespace maze {
|
|||
}
|
||||
}
|
||||
|
||||
inline bool complete(Matrix& maze) {
|
||||
size_t width = matrix::width(maze);
|
||||
size_t height = matrix::height(maze);
|
||||
|
||||
inline bool complete(Matrix& maze, size_t width, size_t height) {
|
||||
for(size_t row = 1; row < height; row += 2) {
|
||||
for(size_t col = 1; col < width; col += 2) {
|
||||
if(maze[row][col] != 0) return false;
|
||||
|
|
@ -71,10 +69,7 @@ namespace maze {
|
|||
return result;
|
||||
}
|
||||
|
||||
inline std::pair<Point, Point> find_coord(Matrix& maze) {
|
||||
size_t width = matrix::width(maze);
|
||||
size_t height = matrix::height(maze);
|
||||
|
||||
inline std::pair<Point, Point> find_coord(Matrix& maze, size_t width, size_t height) {
|
||||
for(size_t y = 1; y < height; y += 2) {
|
||||
for(size_t x = 1; x < width; x += 2) {
|
||||
if(maze[y][x] == WALL_VALUE) {
|
||||
|
|
@ -161,13 +156,13 @@ namespace maze {
|
|||
void Builder::hunt_and_kill(Point on) {
|
||||
if($rooms.size() > 0) place_rooms();
|
||||
|
||||
while(!complete($walls)) {
|
||||
while(!complete($walls, $width, $height)) {
|
||||
auto n = neighbors($walls, on);
|
||||
|
||||
if(n.size() == 0) {
|
||||
// no neighbors, must be dead end
|
||||
add_dead_end(on);
|
||||
auto t = find_coord($walls);
|
||||
auto t = find_coord($walls, $width, $height);
|
||||
on = t.first;
|
||||
$walls[on.y][on.x] = 0;
|
||||
size_t row = (on.y + t.second.y) / 2;
|
||||
|
|
@ -195,8 +190,8 @@ namespace maze {
|
|||
}
|
||||
|
||||
void Builder::inner_donut(float outer_rad, float inner_rad) {
|
||||
size_t x = matrix::width($walls) / 2;
|
||||
size_t y = matrix::height($walls) / 2;
|
||||
size_t x = $width / 2;
|
||||
size_t y = $height / 2;
|
||||
|
||||
for(matrix::circle it{$walls, {x, y}, outer_rad}; it.next();)
|
||||
{
|
||||
|
|
@ -254,10 +249,7 @@ namespace maze {
|
|||
}
|
||||
|
||||
void Builder::enclose() {
|
||||
size_t width = matrix::width($walls);
|
||||
size_t height = matrix::height($walls);
|
||||
|
||||
for(matrix::perimeter it{0, 0, width, height}; it.next();) {
|
||||
for(matrix::perimeter it{0, 0, $width, $height}; it.next();) {
|
||||
$walls[it.y][it.x] = WALL_VALUE;
|
||||
Point at{it.x,it.y};
|
||||
if($doors.contains(at)) $doors.erase(at);
|
||||
|
|
@ -265,8 +257,8 @@ namespace maze {
|
|||
}
|
||||
|
||||
void Builder::open_box(size_t outer_size) {
|
||||
size_t center_x = matrix::width($walls) / 2;
|
||||
size_t center_y = matrix::height($walls) / 2;
|
||||
size_t center_x = $width / 2;
|
||||
size_t center_y = $height / 2;
|
||||
|
||||
// compensate for the box's border now
|
||||
outer_size++;
|
||||
|
|
@ -381,9 +373,10 @@ namespace maze {
|
|||
for(matrix::perimeter it{0, 0, width, height}; it.next();) {
|
||||
if($ends_map.contains({it.x, it.y})) return false;
|
||||
if($doors.contains({it.x, it.y})) return false;
|
||||
if($walls[it.y][it.x] != WALL_VALUE) return false;
|
||||
}
|
||||
|
||||
if($rooms.size() == 1) return true;
|
||||
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
|
||||
|
|
@ -404,6 +397,12 @@ namespace maze {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Builder::in_bounds(size_t x, size_t y) {
|
||||
if(x > $width) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::punch_dead_end(size_t at_x, size_t at_y, size_t x, size_t y) {
|
||||
int diff_x = at_x - x;
|
||||
int diff_y = at_y - y;
|
||||
|
|
@ -411,11 +410,10 @@ namespace maze {
|
|||
}
|
||||
|
||||
bool Builder::repair() {
|
||||
// possible fixes
|
||||
// go through each dead end and remove until it works
|
||||
// go through each room and add a door until it works
|
||||
// only find rooms that are unpathable and fix them
|
||||
// walk the path deleting dead ends at the end of the path
|
||||
enclose();
|
||||
// if it's already valid then done
|
||||
if(validate()) return true;
|
||||
|
||||
std::vector<Point> removed_ends;
|
||||
bool now_valid = false;
|
||||
|
||||
|
|
@ -432,9 +430,6 @@ namespace maze {
|
|||
// if that validates it then done
|
||||
if(validate()) {
|
||||
now_valid = true;
|
||||
fmt::println("MID dead_end removed={}, total={}, %={}",
|
||||
removed_ends.size(), $dead_ends.size(),
|
||||
float(removed_ends.size()) / float($dead_ends.size()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -454,10 +449,6 @@ namespace maze {
|
|||
enclose();
|
||||
now_valid = validate();
|
||||
|
||||
fmt::println("FINAL now_valid={} added_back={} removed={}, total={}, %={}",
|
||||
now_valid, added_back, removed_ends.size() - added_back, $dead_ends.size(),
|
||||
float(removed_ends.size() - added_back) / float($dead_ends.size()));
|
||||
|
||||
// didn't find a way to make it valid
|
||||
return now_valid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
namespace maze {
|
||||
|
||||
struct Builder {
|
||||
size_t $width = 0;
|
||||
size_t $height = 0;
|
||||
Matrix& $walls;
|
||||
std::vector<Room>& $rooms;
|
||||
std::vector<Point>& $dead_ends;
|
||||
|
|
@ -16,11 +18,11 @@ namespace maze {
|
|||
Pathing $paths;
|
||||
|
||||
Builder(Map& map) :
|
||||
$walls(map.$walls), $rooms(map.$rooms), $dead_ends(map.$dead_ends),
|
||||
$paths{matrix::width(map.$walls), matrix::height(map.$walls)}
|
||||
$width(map.$width), $height(map.$height), $walls(map.$walls),
|
||||
$rooms(map.$rooms), $dead_ends(map.$dead_ends), $paths{$width, $height}
|
||||
{
|
||||
dbc::check(map.$width % 2 == 1, "map width not an ODD number (perimter dead ends bug)");
|
||||
dbc::check(map.$height % 2 == 1, "map height not an ODD number (perimter dead ends bug)");
|
||||
dbc::check($width % 2 == 1, "map width not an ODD number (perimter dead ends bug)");
|
||||
dbc::check($height % 2 == 1, "map height not an ODD number (perimter dead ends bug)");
|
||||
|
||||
clear();
|
||||
}
|
||||
|
|
@ -42,5 +44,6 @@ namespace maze {
|
|||
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);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include "algos/maze.hpp"
|
||||
#include "algos/stats.hpp"
|
||||
|
||||
#define DUMP 0
|
||||
#define DUMP 1
|
||||
|
||||
using std::string;
|
||||
using matrix::Matrix;
|
||||
|
|
@ -17,11 +17,15 @@ TEST_CASE("hunt-and-kill", "[mazes]") {
|
|||
maze::Builder maze(map);
|
||||
|
||||
maze.hunt_and_kill();
|
||||
REQUIRE(maze.repair() == true);
|
||||
|
||||
if(DUMP) maze.dump("BASIC MAZE");
|
||||
|
||||
maze.randomize_rooms(ROOM_SIZE);
|
||||
maze.hunt_and_kill();
|
||||
maze.make_doors();
|
||||
REQUIRE(maze.repair() == true);
|
||||
|
||||
if(DUMP) maze.dump("ROOM MAZE");
|
||||
|
||||
REQUIRE(map.$dead_ends.size() > 0);
|
||||
|
|
@ -36,14 +40,15 @@ TEST_CASE("hunt-and-kill box", "[mazes]") {
|
|||
maze.hunt_and_kill();
|
||||
maze.clear();
|
||||
maze.inner_box(6, 4);
|
||||
maze.randomize_rooms(ROOM_SIZE+2);
|
||||
maze.randomize_rooms(ROOM_SIZE);
|
||||
|
||||
maze.hunt_and_kill();
|
||||
maze.open_box(6);
|
||||
maze.make_doors();
|
||||
auto valid = maze.repair();
|
||||
|
||||
if(i == 41 && DUMP) {
|
||||
maze.dump("INNER BOX");
|
||||
maze.dump(valid ? "INNER BOX" : "FAILED BOX");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,6 +59,7 @@ TEST_CASE("hunt-and-kill ring", "[mazes]") {
|
|||
|
||||
maze.inner_donut(5.5, 3.5);
|
||||
maze.hunt_and_kill();
|
||||
REQUIRE(maze.repair() == true);
|
||||
|
||||
if(DUMP) maze.dump("INNER RING");
|
||||
|
||||
|
|
@ -66,6 +72,7 @@ TEST_CASE("hunt-and-kill fissure", "[mazes]") {
|
|||
|
||||
maze.divide({3,3}, {19,18});
|
||||
maze.hunt_and_kill();
|
||||
REQUIRE(maze.repair() == true);
|
||||
|
||||
if(DUMP) maze.dump("FISSURE MAZE");
|
||||
|
||||
|
|
@ -78,7 +85,7 @@ TEST_CASE("hunt-and-kill no-dead-ends", "[mazes]") {
|
|||
|
||||
maze.hunt_and_kill();
|
||||
maze.remove_dead_ends();
|
||||
maze.enclose();
|
||||
REQUIRE(maze.repair() == true);
|
||||
|
||||
if(DUMP) maze.dump("NO DEAD ENDS");
|
||||
}
|
||||
|
|
@ -95,8 +102,9 @@ TEST_CASE("hunt-and-kill too much", "[mazes]") {
|
|||
maze.divide({3,3}, {15,16});
|
||||
maze.hunt_and_kill();
|
||||
maze.make_doors();
|
||||
auto valid = maze.repair();
|
||||
|
||||
if(i == 41 && DUMP) {
|
||||
if(i == 41 && DUMP && valid) {
|
||||
maze.dump("COMBINED");
|
||||
}
|
||||
}
|
||||
|
|
@ -120,10 +128,7 @@ TEST_CASE("hunt-and-kill validator", "[mazes]") {
|
|||
maze.hunt_and_kill();
|
||||
maze.open_box(6);
|
||||
maze.make_doors();
|
||||
maze.enclose();
|
||||
|
||||
valid = maze.validate();
|
||||
if(!valid) valid = maze.repair();
|
||||
valid = maze.repair();
|
||||
|
||||
if(i == 9) {
|
||||
if(valid) {
|
||||
|
|
@ -132,7 +137,6 @@ TEST_CASE("hunt-and-kill validator", "[mazes]") {
|
|||
matrix::dump("PATHING", maze.$paths.$paths);
|
||||
}
|
||||
}
|
||||
|
||||
door_prob.sample(valid);
|
||||
} while(!valid);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue