Exploring raycasters and possibly make a little "doom like" game based on it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
raycaster/maze.cpp

222 lines
5.0 KiB

#include <fmt/core.h>
#include <string>
#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 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;
}
}
return true;
}
std::vector<Point> neighborsAB(Matrix& maze, Point on) {
std::vector<Point> result;
std::array<Point, 4> 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<Point> neighbors(Matrix& maze, Point on) {
std::vector<Point> result;
std::array<Point, 4> 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_VALUE) {
result.push_back(point);
}
}
}
return result;
}
inline std::pair<Point, Point> find_coord(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_VALUE) {
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::randomize_rooms(std::vector<Room>& rooms_out, std::vector<Point>& maybe_here) {
dbc::check(maybe_here.size() >= 2, "must have at least two possible points to place rooms");
while(rooms_out.size() < 2) {
// use those dead ends to randomly place rooms
for(auto at : maybe_here) {
if(Random::uniform(0,1)) {
size_t offset = Random::uniform(0,1);
Room cur{at.x+offset, at.y+offset, 1, 1};
rooms_out.push_back(cur);
}
}
}
}
void maze::init(Matrix& maze) {
matrix::assign(maze, WALL_VALUE);
}
void maze::divide(Matrix& maze, Point start, Point end) {
for(matrix::line it{start, end}; it.next();) {
maze[it.y][it.x] = 0;
maze[it.y+1][it.x] = 0;
}
}
void maze::hunt_and_kill(Matrix& maze, std::vector<Room>& rooms, std::vector<Point>& dead_ends) {
for(auto& room : rooms) {
for(matrix::box it{maze, room.x, room.y, room.width}; it.next();) {
maze[it.y][it.x] = 0;
}
}
Point on{1,1};
while(!complete(maze)) {
auto n = neighbors(maze, on);
if(n.size() == 0) {
dead_ends.push_back(on);
auto t = find_coord(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[rand(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;
}
}
for(auto at : dead_ends) {
for(auto& room : rooms) {
Point room_ul{room.x - room.width - 1, room.y - room.height - 1};
Point room_lr{room.x + room.width - 1, room.y + room.height - 1};
if(at.x >= room_ul.x && at.y >= room_ul.y &&
at.x <= room_lr.x && at.y <= room_lr.y)
{
for(matrix::compass it{maze, at.x, at.y}; it.next();) {
if(maze[it.y][it.x] == 1) {
maze[it.y][it.x] = 0;
break;
}
}
}
}
}
}
void maze::inner_donut(Matrix& maze, float outer_rad, float inner_rad) {
size_t x = matrix::width(maze) / 2;
size_t y = matrix::height(maze) / 2;
for(matrix::circle it{maze, {x, y}, outer_rad};
it.next();)
{
for(int x = it.left; x < it.right; x++) {
maze[it.y][x] = 0;
}
}
for(matrix::circle it{maze, {x, y}, inner_rad};
it.next();)
{
for(int x = it.left; x < it.right; x++) {
maze[it.y][x] = 1;
}
}
}
void maze::inner_box(Matrix& maze, size_t outer_size, size_t inner_size) {
size_t x = matrix::width(maze) / 2;
size_t y = matrix::height(maze) / 2;
for(matrix::box it{maze, x, y, outer_size};
it.next();)
{
maze[it.y][it.x] = 0;
}
for(matrix::box it{maze, x, y, inner_size};
it.next();)
{
maze[it.y][it.x] = 1;
}
}
void maze::remove_dead_ends(Matrix& maze, std::vector<Point>& dead_ends) {
for(auto at : dead_ends) {
for(matrix::compass it{maze, at.x, at.y}; it.next();) {
if(maze[it.y][it.x] == 0) {
int diff_x = at.x - it.x;
int diff_y = at.y - it.y;
maze[at.y + diff_y][at.x + diff_x] = 0;
}
}
}
}