|
|
|
@ -6,37 +6,105 @@ |
|
|
|
|
#include <fmt/core.h> |
|
|
|
|
#include "point.hpp" |
|
|
|
|
|
|
|
|
|
using fmt::println; |
|
|
|
|
|
|
|
|
|
namespace matrix { |
|
|
|
|
using std::vector, std::queue, std::array; |
|
|
|
|
using std::min, std::max, std::floor; |
|
|
|
|
|
|
|
|
|
typedef vector<int> Row; |
|
|
|
|
typedef vector<Row> Matrix; |
|
|
|
|
|
|
|
|
|
struct each_cell { |
|
|
|
|
/*
|
|
|
|
|
* 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(Matrix &mat); |
|
|
|
|
bool next(); |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct each_row { |
|
|
|
|
Matrix &$mat; |
|
|
|
|
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(Matrix &mat); |
|
|
|
|
bool next(); |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct in_box { |
|
|
|
|
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
|
|
|
|
@ -46,13 +114,49 @@ namespace matrix { |
|
|
|
|
size_t right = 0; |
|
|
|
|
size_t bottom = 0; |
|
|
|
|
|
|
|
|
|
in_box(Matrix &mat, size_t x, size_t y, size_t size); |
|
|
|
|
float distance(); |
|
|
|
|
bool next(); |
|
|
|
|
void dump(); |
|
|
|
|
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)); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct compass { |
|
|
|
|
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}; |
|
|
|
@ -60,34 +164,36 @@ namespace matrix { |
|
|
|
|
size_t max_dirs=0; |
|
|
|
|
size_t dir = ~0; |
|
|
|
|
|
|
|
|
|
compass(Matrix &mat, size_t x, size_t y); |
|
|
|
|
bool next(); |
|
|
|
|
}; |
|
|
|
|
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}; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Just a quick thing to reset a matrix to a value. |
|
|
|
|
*/ |
|
|
|
|
inline void assign(Matrix &out, int new_value) { |
|
|
|
|
for(auto &row : out) { |
|
|
|
|
row.assign(row.size(), new_value); |
|
|
|
|
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++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline bool inbounds(Matrix &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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline size_t width(Matrix &mat) { |
|
|
|
|
return mat[0].size(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline size_t height(Matrix &mat) { |
|
|
|
|
return mat.size(); |
|
|
|
|
} |
|
|
|
|
bool next() { |
|
|
|
|
dir++; |
|
|
|
|
if(dir < max_dirs) { |
|
|
|
|
x = x_dirs[dir]; |
|
|
|
|
y = y_dirs[dir]; |
|
|
|
|
return true; |
|
|
|
|
} else { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
void dump(const std::string &msg, Matrix &map, int show_x=-1, int show_y=-1); |
|
|
|
|
using compass = compass_t<Matrix>; |
|
|
|
|
|
|
|
|
|
struct flood { |
|
|
|
|
Matrix &mat; |
|
|
|
@ -120,7 +226,8 @@ namespace matrix { |
|
|
|
|
bool next(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct circle { |
|
|
|
|
template<typename MAT> |
|
|
|
|
struct circle_t { |
|
|
|
|
float center_x; |
|
|
|
|
float center_y; |
|
|
|
|
float radius = 0.0f; |
|
|
|
@ -134,8 +241,30 @@ namespace matrix { |
|
|
|
|
int width = 0; |
|
|
|
|
int height = 0; |
|
|
|
|
|
|
|
|
|
circle(Matrix &mat, Point center, float radius); |
|
|
|
|
void update(); |
|
|
|
|
bool next(); |
|
|
|
|
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>; |
|
|
|
|
} |
|
|
|
|