#include #include #include "rand.hpp" #include "constants.hpp" #include "maze.hpp" using std::string; using matrix::Matrix; inline size_t rand(size_t i, size_t j) { if(i < j) { return Random::uniform(i, j); } else if(j < i) { return Random::uniform(j, i); } else { return i; } } inline bool split_dir(size_t iDim, size_t jDim) { if(iDim < jDim) { return false; } else if(jDim < iDim) { return true; } else { return Random::uniform(0, 1); } } inline bool good_hole(Matrix &map, size_t split, size_t hole, bool horiz) { if(hole % 2 == 0) return false; size_t j = horiz ? split : hole; size_t i = horiz ? hole : split; if(map[j][i] == WALL_PATH_LIMIT) return false; return true; } void divide(Matrix& map, std::vector &rooms, Point iCoords, Point jCoords, bool horizontal) { int iDim = iCoords.y - iCoords.x; int jDim = jCoords.y - jCoords.x; bool punch_room = false; if(iDim <= 0 || jDim <= 0) { return; } else if(iDim <= 2 && jDim <= 2) { fmt::println("MADE ROOM! {},{}; {},{}", iCoords.x, iCoords.y, jCoords.x, jCoords.y); punch_room = true; } if(horizontal) { size_t split = 0; do { split = rand(iCoords.x, iCoords.x + iDim + 1); } while(split % 2); size_t hole = 0; do { hole = rand(jCoords.x, jCoords.x + jDim +1); } while(good_hole(map, split, hole, horizontal)); for(size_t j = jCoords.x; j <= jCoords.y; j++) { if(j != hole) { map[split][j] = WALL_PATH_LIMIT; } } divide(map, rooms, {iCoords.x, size_t(split - 1)}, jCoords, split_dir(split - iCoords.x - 1, jDim)); divide(map, rooms, {size_t(split + 1), iCoords.y}, jCoords, split_dir(iCoords.x - split - 1, jDim)); } else { size_t split = 0; do { split = rand(jCoords.x, jCoords.x + jDim + 1); } while(split % 2); size_t hole = 0; do { hole = rand(iCoords.x, iCoords.x + iDim + 1); } while(good_hole(map, split, hole, horizontal)); for(size_t i = iCoords.x; i <= iCoords.y; i++) { if(i != hole) { map[i][split] = WALL_PATH_LIMIT; } } divide(map, rooms, iCoords, {jCoords.x, size_t(split - 1)}, split_dir(iDim, split - jCoords.x - 1)); divide(map, rooms, iCoords, {size_t(split + 1), jCoords.y}, Random::uniform(0, 1)); } if(punch_room) { // for(size_t j = jCoords.x; j <= jCoords.y; j++) { // for(size_t i = iCoords.x; i <= iCoords.y; i++) { // map[j][i] = 0; // } // } Room room{iCoords.x, jCoords.x, iCoords.y - iCoords.x + 1, jCoords.y - jCoords.x + 1}; for(auto r : rooms) { if(r.x == room.x && r.y == room.y) { return; } } rooms.push_back(room); } } void maze::recursive_div(Matrix& map, std::vector& rooms) { size_t width = matrix::width(map); size_t height = matrix::height(map); for(size_t i = 0; i < height; i++) { for(size_t j = 0; j < width; j++) { int val = (i == 0 || j == 0 || i == height - 1 || j == width - 1); map[i][j] = val == 1 ? WALL_PATH_LIMIT : 0; } } divide(map, rooms, {1, height - 2}, {1, width - 2}, split_dir(1, 1)); } bool complete(Matrix& maze) { size_t width = matrix::width(maze); size_t height = matrix::height(maze); 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; } } // dbc::sentinel("LOL it's complete eh?"); return true; } std::vector neighborsAB(Matrix& maze, Point on) { std::vector result; std::array points{{ {on.x, on.y - 2}, {on.x, on.y + 2}, {on.x - 2, on.y}, {on.x + 2, on.y} }}; for(auto point : points) { if(matrix::inbounds(maze, point.x, point.y)) { result.push_back(point); } } return result; } std::vector neighbors(Matrix& maze, Point on) { std::vector result; std::array points{{ {on.x, on.y - 2}, {on.x, on.y + 2}, {on.x - 2, on.y}, {on.x + 2, on.y} }}; for(auto point : points) { if(matrix::inbounds(maze, point.x, point.y)) { if(maze[point.y][point.x] == WALL_PATH_LIMIT) { result.push_back(point); } } } return result; } std::pair findCoord(Matrix& maze) { size_t width = matrix::width(maze); size_t height = matrix::height(maze); for(size_t y = 1; y < height; y += 2) { for(size_t x = 1; x < width; x += 2) { if(maze[y][x] == WALL_PATH_LIMIT) { auto found = neighborsAB(maze, {x, y}); for(auto point : found) { if(maze[point.y][point.x] == 0) { return {{x, y}, point}; } } } } } matrix::dump("BAD MAZE", maze); dbc::sentinel("failed to find coord?"); } void maze::hunt_and_kill(Matrix& maze, std::vector& rooms) { size_t width = matrix::width(maze); size_t height = matrix::height(maze); matrix::assign(maze, WALL_PATH_LIMIT); Room start{2, 2, 3, 3}; rooms.push_back(start); Room goal{width-4, height-4, 3, 3}; rooms.push_back(goal); for(auto& room : rooms) { for(matrix::box it{maze, room.x, room.y, 1}; it.next();) { maze[it.y][it.x] = 0; } } Point on{1,1}; while(!complete(maze)) { auto n = neighbors(maze, on); if(n.size() == 0) { auto t = findCoord(maze); on = t.first; maze[on.y][on.x] = 0; size_t row = (on.y + t.second.y) / 2; size_t col = (on.x + t.second.x) / 2; maze[row][col] = 0; } else { auto nb = n[Random::uniform(size_t(0), n.size() - 1)]; maze[nb.y][nb.x] = 0; size_t row = (nb.y + on.y) / 2; size_t col = (nb.x + on.x) / 2; maze[row][col] = 0; on = nb; } } }