Maze gen can now more efficiently produce an interesting map that is fully pathable.
This commit is contained in:
parent
f85ae8a6c6
commit
e6fcbd8dcf
3 changed files with 75 additions and 8 deletions
|
|
@ -215,12 +215,11 @@ namespace maze {
|
||||||
|
|
||||||
void Builder::remove_dead_ends() {
|
void Builder::remove_dead_ends() {
|
||||||
dbc::check($dead_ends.size() > 0, "you have to run an algo first, no dead_ends to remove");
|
dbc::check($dead_ends.size() > 0, "you have to run an algo first, no dead_ends to remove");
|
||||||
|
|
||||||
for(auto at : $dead_ends) {
|
for(auto at : $dead_ends) {
|
||||||
for(matrix::compass it{$walls, at.x, at.y}; it.next();) {
|
for(matrix::compass it{$walls, at.x, at.y}; it.next();) {
|
||||||
if($walls[it.y][it.x] == 0) {
|
if($walls[it.y][it.x] == SPACE_VALUE) {
|
||||||
int diff_x = at.x - it.x;
|
punch_dead_end(at.x, at.y, it.x, it.y);
|
||||||
int diff_y = at.y - it.y;
|
|
||||||
$walls[at.y + diff_y][at.x + diff_x] = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -404,4 +403,62 @@ namespace maze {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
$walls[at_y + diff_y][at_x + diff_x] = SPACE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
std::vector<Point> removed_ends;
|
||||||
|
bool now_valid = false;
|
||||||
|
|
||||||
|
for(auto& at : $dead_ends) {
|
||||||
|
// punch a hole for this dead end
|
||||||
|
for(matrix::compass it{$walls, at.x, at.y}; it.next();) {
|
||||||
|
if($walls[it.y][it.x] == SPACE_VALUE) {
|
||||||
|
punch_dead_end(at.x, at.y, it.x, it.y);
|
||||||
|
removed_ends.push_back({it.x, it.y});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go back and see if we can add any back
|
||||||
|
int added_back = 0;
|
||||||
|
for(auto& at : removed_ends) {
|
||||||
|
$walls[at.y][at.x] = WALL_VALUE;
|
||||||
|
|
||||||
|
if(!validate()) {
|
||||||
|
$walls[at.y][at.x] = SPACE_VALUE;
|
||||||
|
} else {
|
||||||
|
added_back++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,5 +40,7 @@ namespace maze {
|
||||||
bool room_should_exist(Room& room, bool allow_dupes=false);
|
bool room_should_exist(Room& room, bool allow_dupes=false);
|
||||||
void make_doors();
|
void make_doors();
|
||||||
bool validate();
|
bool validate();
|
||||||
|
bool repair();
|
||||||
|
void punch_dead_end(size_t at_x, size_t at_y, size_t x, size_t y);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include "algos/maze.hpp"
|
#include "algos/maze.hpp"
|
||||||
#include "algos/stats.hpp"
|
#include "algos/stats.hpp"
|
||||||
|
|
||||||
#define DUMP 1
|
#define DUMP 0
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using matrix::Matrix;
|
using matrix::Matrix;
|
||||||
|
|
@ -106,7 +106,7 @@ TEST_CASE("hunt-and-kill validator", "[mazes]") {
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
Stats mofm;
|
Stats mofm;
|
||||||
|
|
||||||
for(int i = 0; i < 100; i++) {
|
for(int i = 0; i < 10; i++) {
|
||||||
Stats door_prob;
|
Stats door_prob;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
@ -123,16 +123,24 @@ TEST_CASE("hunt-and-kill validator", "[mazes]") {
|
||||||
maze.enclose();
|
maze.enclose();
|
||||||
|
|
||||||
valid = maze.validate();
|
valid = maze.validate();
|
||||||
if(valid && i == 99) {
|
if(!valid) valid = maze.repair();
|
||||||
maze.dump("VALIDATED");
|
|
||||||
|
if(i == 9) {
|
||||||
|
if(valid) {
|
||||||
|
maze.dump("VALIDATED");
|
||||||
|
} else {
|
||||||
|
matrix::dump("PATHING", maze.$paths.$paths);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
door_prob.sample(valid);
|
door_prob.sample(valid);
|
||||||
} while(!valid);
|
} while(!valid);
|
||||||
|
|
||||||
|
door_prob.dump();
|
||||||
mofm.sample(door_prob.mean());
|
mofm.sample(door_prob.mean());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt::println("FINAL m-of-m");
|
||||||
mofm.dump();
|
mofm.dump();
|
||||||
REQUIRE(mofm.mean() > 0.20);
|
REQUIRE(mofm.mean() > 0.20);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue