|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#include <queue>
|
|
|
|
#include <string>
|
|
|
|
#include <array>
|
|
|
|
#include <fmt/core.h>
|
|
|
|
#include "point.hpp"
|
|
|
|
|
|
|
|
namespace matrix {
|
|
|
|
using std::vector, std::queue, std::array;
|
|
|
|
using std::min, std::max, std::floor;
|
|
|
|
|
|
|
|
typedef vector<int> Row;
|
|
|
|
typedef vector<Row> Matrix;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Just a quick thing to reset a matrix to a value.
|
|
|
|
*/
|
|
|
|
template<typename MAT, typename VAL>
|
|
|
|
inline void assign(MAT &out, VAL new_value) {
|
|
|
|
for(auto &row : out) {
|
|
|
|
row.assign(row.size(), new_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
inline bool inbounds(MAT &mat, size_t x, size_t y) {
|
|
|
|
// since Point.x and Point.y are size_t any negatives are massive
|
|
|
|
bool res = (y < mat.size()) && (x < mat[0].size());
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
inline size_t width(MAT &mat) {
|
|
|
|
return mat[0].size();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
inline size_t height(MAT &mat) {
|
|
|
|
return mat.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dump(const std::string &msg, Matrix &map, int show_x=-1, int show_y=-1);
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
struct each_cell_t {
|
|
|
|
size_t x = ~0;
|
|
|
|
size_t y = ~0;
|
|
|
|
size_t width = 0;
|
|
|
|
size_t height = 0;
|
|
|
|
|
|
|
|
each_cell_t(MAT &mat)
|
|
|
|
{
|
|
|
|
height = matrix::height(mat);
|
|
|
|
width = matrix::width(mat);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool next() {
|
|
|
|
x = next_x(x, width);
|
|
|
|
y = next_y(x, y);
|
|
|
|
return at_end(y, height);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
struct viewport_t {
|
|
|
|
Point start;
|
|
|
|
// this is the point in the map
|
|
|
|
size_t x;
|
|
|
|
size_t y;
|
|
|
|
// this is the point inside the box, start at 0
|
|
|
|
size_t view_x = ~0;
|
|
|
|
size_t view_y = ~0;
|
|
|
|
// viewport width/height
|
|
|
|
size_t width;
|
|
|
|
size_t height;
|
|
|
|
|
|
|
|
viewport_t(MAT &mat, Point start, int max_x, int max_y) :
|
|
|
|
start(start),
|
|
|
|
x(start.x-1),
|
|
|
|
y(start.y-1)
|
|
|
|
{
|
|
|
|
width = std::min(size_t(max_x), matrix::width(mat) - start.x);
|
|
|
|
height = std::min(size_t(max_y), matrix::height(mat) - start.y);
|
|
|
|
fmt::println("viewport_t max_x, max_y {},{} vs matrix {},{}, x={}, y={}",
|
|
|
|
max_x, max_y, matrix::width(mat), matrix::height(mat), x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool next() {
|
|
|
|
y = next_y(x, y);
|
|
|
|
x = next_x(x, width);
|
|
|
|
view_x = next_x(view_x, width);
|
|
|
|
view_y = next_y(view_x, view_y);
|
|
|
|
return at_end(y, height);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using viewport = viewport_t<Matrix>;
|
|
|
|
|
|
|
|
using each_cell = each_cell_t<Matrix>;
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
struct each_row_t {
|
|
|
|
size_t x = ~0;
|
|
|
|
size_t y = ~0;
|
|
|
|
size_t width = 0;
|
|
|
|
size_t height = 0;
|
|
|
|
bool row = false;
|
|
|
|
|
|
|
|
each_row_t(MAT &mat) {
|
|
|
|
height = matrix::height(mat);
|
|
|
|
width = matrix::width(mat);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool next() {
|
|
|
|
x = next_x(x, width);
|
|
|
|
y = next_y(x, y);
|
|
|
|
row = end_row(x, width);
|
|
|
|
return at_end(y, height);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using each_row = each_row_t<Matrix>;
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
struct box_t {
|
|
|
|
size_t from_x;
|
|
|
|
size_t from_y;
|
|
|
|
size_t x = 0; // these are set in constructor
|
|
|
|
size_t y = 0; // again, no fancy ~ trick needed
|
|
|
|
size_t left = 0;
|
|
|
|
size_t top = 0;
|
|
|
|
size_t right = 0;
|
|
|
|
size_t bottom = 0;
|
|
|
|
|
|
|
|
box_t(MAT &mat, size_t at_x, size_t at_y, size_t size) :
|
|
|
|
from_x(at_x), from_y(at_y)
|
|
|
|
{
|
|
|
|
size_t h = matrix::height(mat);
|
|
|
|
size_t w = matrix::width(mat);
|
|
|
|
|
|
|
|
// 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 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
float distance() {
|
|
|
|
int dx = from_x - x;
|
|
|
|
int dy = from_y - y;
|
|
|
|
|
|
|
|
return sqrt((dx * dx) + (dy * dy));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using box = box_t<Matrix>;
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
struct compass_t {
|
|
|
|
size_t x = 0; // these are set in constructor
|
|
|
|
size_t y = 0; // again, no fancy ~ trick needed
|
|
|
|
array<int, 4> x_dirs{0, 1, 0, -1};
|
|
|
|
array<int, 4> y_dirs{-1, 0, 1, 0};
|
|
|
|
size_t max_dirs=0;
|
|
|
|
size_t dir = ~0;
|
|
|
|
|
|
|
|
compass_t(MAT &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 next() {
|
|
|
|
dir++;
|
|
|
|
if(dir < max_dirs) {
|
|
|
|
x = x_dirs[dir];
|
|
|
|
y = y_dirs[dir];
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using compass = compass_t<Matrix>;
|
|
|
|
|
|
|
|
struct flood {
|
|
|
|
Matrix &mat;
|
|
|
|
Point start;
|
|
|
|
int old_val;
|
|
|
|
int new_val;
|
|
|
|
queue<Point> q;
|
|
|
|
Point current_loc;
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
matrix::compass dirs;
|
|
|
|
|
|
|
|
flood(Matrix &mat, Point start, int old_val, int new_val);
|
|
|
|
bool next();
|
|
|
|
bool next_working();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct line {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
int x1;
|
|
|
|
int y1;
|
|
|
|
int sx;
|
|
|
|
int sy;
|
|
|
|
int dx;
|
|
|
|
int dy;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
line(Point start, Point end);
|
|
|
|
bool next();
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename MAT>
|
|
|
|
struct circle_t {
|
|
|
|
float center_x;
|
|
|
|
float center_y;
|
|
|
|
float radius = 0.0f;
|
|
|
|
int y = 0;
|
|
|
|
int dx = 0;
|
|
|
|
int dy = 0;
|
|
|
|
int left = 0;
|
|
|
|
int right = 0;
|
|
|
|
int top = 0;
|
|
|
|
int bottom = 0;
|
|
|
|
int width = 0;
|
|
|
|
int height = 0;
|
|
|
|
|
|
|
|
circle_t(MAT &mat, Point center, float radius) :
|
|
|
|
center_x(center.x), center_y(center.y), radius(radius)
|
|
|
|
{
|
|
|
|
width = matrix::width(mat);
|
|
|
|
height = matrix::height(mat);
|
|
|
|
top = max(int(floor(center_y - radius)), 0);
|
|
|
|
bottom = min(int(floor(center_y + radius)), height - 1);
|
|
|
|
|
|
|
|
y = top;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool next() {
|
|
|
|
y++;
|
|
|
|
if(y <= bottom) {
|
|
|
|
dy = y - center_y;
|
|
|
|
dx = floor(sqrt(radius * radius - dy * dy));
|
|
|
|
left = max(0, int(center_x) - dx);
|
|
|
|
right = min(width, int(center_x) + dx + 1);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using circle = circle_t<Matrix>;
|
|
|
|
}
|