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.
253 lines
5.1 KiB
253 lines
5.1 KiB
#include "matrix.hpp"
|
|
#include "constants.hpp"
|
|
#include "dbc.hpp"
|
|
#include <fmt/core.h>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
|
|
using namespace fmt;
|
|
using std::min, std::max;
|
|
|
|
inline size_t next_x(size_t x, size_t width) {
|
|
return (x + 1) * ((x + 1) < width);
|
|
}
|
|
|
|
inline size_t next_y(size_t x, size_t y) {
|
|
return y + (x == 0);
|
|
}
|
|
|
|
inline bool at_end(size_t y, size_t height) {
|
|
return y < height;
|
|
}
|
|
|
|
inline bool end_row(size_t x, size_t width) {
|
|
return x == width - 1;
|
|
}
|
|
|
|
|
|
namespace matrix {
|
|
|
|
each_cell::each_cell(Matrix &mat)
|
|
{
|
|
height = mat.size();
|
|
width = mat[0].size();
|
|
}
|
|
|
|
bool each_cell::next() {
|
|
x = next_x(x, width);
|
|
y = next_y(x, y);
|
|
return at_end(y, height);
|
|
}
|
|
|
|
each_row::each_row(Matrix &mat) :
|
|
$mat(mat)
|
|
{
|
|
height = $mat.size();
|
|
width = $mat[0].size();
|
|
}
|
|
|
|
bool each_row::next() {
|
|
x = next_x(x, width);
|
|
y = next_y(x, y);
|
|
row = end_row(x, width);
|
|
return at_end(y, height);
|
|
}
|
|
|
|
in_box::in_box(Matrix &mat, size_t from_x, size_t from_y, size_t size) {
|
|
size_t h = mat.size();
|
|
size_t w = mat[0].size();
|
|
|
|
// keeps it from going below zero
|
|
// need extra -1 to compensate for the first next()
|
|
left = max(from_x, size) - size;
|
|
x = left - 1; // must be -1 for next()
|
|
// keeps it from going above width
|
|
right = min(from_x + size + 1, w);
|
|
|
|
// same for these two
|
|
top = max(from_y, size) - size;
|
|
y = top - (left == 0);
|
|
bottom = min(from_y + size + 1, h);
|
|
}
|
|
|
|
bool in_box::next() {
|
|
// calc next but allow to go to 0 for next
|
|
x = next_x(x, right);
|
|
// x will go to 0, which signals new line
|
|
y = next_y(x, y); // this must go here
|
|
// if x==0 then this moves it to min_x
|
|
x = max(x, left);
|
|
// and done
|
|
return at_end(y, bottom);
|
|
}
|
|
|
|
void in_box::dump() {
|
|
println("BOX: x={},y={}; left={},right={}; top={},bottom={}",
|
|
x, y, left, right, top, bottom);
|
|
}
|
|
|
|
compass::compass(Matrix &mat, size_t x, size_t y) :
|
|
x(x), y(y)
|
|
{
|
|
array<int, 4> x_in{0, 1, 0, -1};
|
|
array<int, 4> y_in{-1, 0, 1, 0};
|
|
|
|
for(size_t i = 0; i < 4; i++) {
|
|
int nx = x + x_in[i];
|
|
int ny = y + y_in[i];
|
|
if(matrix::inbounds(mat, nx, ny)) {
|
|
x_dirs[max_dirs] = nx;
|
|
y_dirs[max_dirs] = ny;
|
|
max_dirs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool compass::next() {
|
|
dir++;
|
|
if(dir < max_dirs) {
|
|
x = x_dirs[dir];
|
|
y = y_dirs[dir];
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
flood::flood(Matrix &mat, Point start, int old_val, int new_val) :
|
|
mat(mat), start(start), old_val(old_val), new_val(new_val),
|
|
x(start.x), y(start.y), dirs{mat, start.x, start.y}
|
|
{
|
|
dbc::check(old_val != new_val, "what you doing?");
|
|
current_loc = start;
|
|
q.push(start);
|
|
}
|
|
|
|
bool flood::next() {
|
|
if(!q.empty()) {
|
|
if(!dirs.next()) {
|
|
// box is done reset it
|
|
auto current_loc = q.front();
|
|
q.pop();
|
|
|
|
dirs = matrix::compass{mat, current_loc.x, current_loc.y};
|
|
dirs.next();
|
|
}
|
|
|
|
// get the next thing
|
|
if(mat[dirs.y][dirs.x] <= old_val) {
|
|
mat[dirs.y][dirs.x] = new_val;
|
|
x = dirs.x;
|
|
y = dirs.y;
|
|
|
|
q.push({.x=dirs.x, .y=dirs.y});
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
line::line(Point start, Point end) :
|
|
x(start.x), y(start.y),
|
|
x1(end.x), y1(end.y)
|
|
{
|
|
dx = std::abs(x1 - x);
|
|
sx = x < x1 ? 1 : -1;
|
|
dy = std::abs(y1 - y) * -1;
|
|
sy = y < y1 ? 1 : -1;
|
|
error = dx + dy;
|
|
}
|
|
|
|
bool line::next() {
|
|
if(x != x1 || y != y1) {
|
|
int e2 = 2 * error;
|
|
|
|
if(e2 >= dy) {
|
|
error = error + dy;
|
|
x = x + sx;
|
|
}
|
|
|
|
if(e2 <= dx) {
|
|
error = error + dx;
|
|
y = y + sy;
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
circle::circle(Point center, int radius) :
|
|
center(center), radius(radius)
|
|
{
|
|
xi = 0;
|
|
yi = radius;
|
|
m = 5 - 4 * radius;
|
|
step = 0;
|
|
}
|
|
|
|
void circle::update() {
|
|
if(m > 0) {
|
|
yi--;
|
|
m -= 8 * yi;
|
|
}
|
|
xi++;
|
|
m += 8 * xi + 4;
|
|
}
|
|
|
|
bool circle::next() {
|
|
if(xi <= yi) {
|
|
switch(step % 4) {
|
|
case 0:
|
|
x0 = center.x - xi;
|
|
y = center.y - yi;
|
|
x1 = center.x + xi;
|
|
break;
|
|
case 1:
|
|
x0 = center.x - yi;
|
|
y = center.y - xi;
|
|
x1 = center.x + yi;
|
|
break;
|
|
case 2:
|
|
x0 = center.x - yi;
|
|
y = center.y + xi;
|
|
x1 = center.x + yi;
|
|
break;
|
|
case 3:
|
|
x0 = center.x - xi;
|
|
y = center.y + yi;
|
|
x1 = center.x + xi;
|
|
update();
|
|
break;
|
|
}
|
|
|
|
step++;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void dump(const std::string &msg, Matrix &map, int show_x, int show_y) {
|
|
println("----------------- {}", msg);
|
|
|
|
for(each_row it{map}; it.next();) {
|
|
int cell = map[it.y][it.x];
|
|
|
|
if(int(it.x) == show_x && int(it.y) == show_y) {
|
|
print("{:x}<", cell);
|
|
} else if(cell == WALL_PATH_LIMIT) {
|
|
print("# ");
|
|
} else if(cell > 15) {
|
|
print("* ");
|
|
} else {
|
|
print("{:x} ", cell);
|
|
}
|
|
|
|
if(it.row) print("\n");
|
|
}
|
|
}
|
|
}
|
|
|