diff --git a/lights.cpp b/lights.cpp index f589f03..5af8181 100644 --- a/lights.cpp +++ b/lights.cpp @@ -6,7 +6,7 @@ using std::vector; namespace lighting { void LightRender::render_square_light(LightSource source, Point at, PointList &has_light) { - for(matrix::in_box it{$lightmap, at.x, at.y, (size_t)floor(source.radius)}; it.next();) { + for(matrix::box it{$lightmap, at.x, at.y, (size_t)floor(source.radius)}; it.next();) { if($paths.$paths[it.y][it.x] != WALL_PATH_LIMIT) { $lightmap[it.y][it.x] = light_level(source.strength, it.distance(), it.x, it.y); has_light.push_back({it.x, it.y}); diff --git a/matrix.cpp b/matrix.cpp index 1e9a748..0a6e0f5 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -8,122 +8,8 @@ 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 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 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); - } - - float in_box::distance() { - int dx = from_x - x; - int dy = from_y - y; - - return sqrt((dx * dx) + (dy * dy)); - } - - 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 x_in{0, 1, 0, -1}; - array 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} @@ -189,31 +75,6 @@ namespace matrix { } } - - circle::circle(Matrix &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 circle::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; - } - } - void dump(const std::string &msg, Matrix &map, int show_x, int show_y) { println("----------------- {}", msg); diff --git a/matrix.hpp b/matrix.hpp index 66335d6..52224c7 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -6,37 +6,105 @@ #include #include "point.hpp" -using fmt::println; - namespace matrix { using std::vector, std::queue, std::array; + using std::min, std::max, std::floor; typedef vector Row; typedef vector Matrix; - struct each_cell { + /* + * Just a quick thing to reset a matrix to a value. + */ + template + inline void assign(MAT &out, VAL new_value) { + for(auto &row : out) { + row.assign(row.size(), new_value); + } + } + + template + 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 + inline size_t width(MAT &mat) { + return mat[0].size(); + } + + template + 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 + 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; + + template + 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; + + template + 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; + + template + struct compass_t { size_t x = 0; // these are set in constructor size_t y = 0; // again, no fancy ~ trick needed array 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 x_in{0, 1, 0, -1}; + array 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; struct flood { Matrix &mat; @@ -120,7 +226,8 @@ namespace matrix { bool next(); }; - struct circle { + template + 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; } diff --git a/pathing.cpp b/pathing.cpp index d59e448..a56ee49 100644 --- a/pathing.cpp +++ b/pathing.cpp @@ -6,7 +6,7 @@ using std::vector; inline void add_neighbors(PointList &neighbors, Matrix &closed, size_t y, size_t x) { - for(matrix::in_box it{closed, x, y, 1}; it.next();) { + for(matrix::box it{closed, x, y, 1}; it.next();) { if(closed[it.y][it.x] == 0) { closed[it.y][it.x] = 1; neighbors.push_back({.x=it.x, .y=it.y}); diff --git a/tests/matrix.cpp b/tests/matrix.cpp index 4d57e67..770304e 100644 --- a/tests/matrix.cpp +++ b/tests/matrix.cpp @@ -39,7 +39,7 @@ TEST_CASE("basic matrix iterator", "[matrix:basic]") { { // test getting the correct height in the middle row_count = 0; - matrix::in_box box{walls, 2,2, 1}; + matrix::box box{walls, 2,2, 1}; while(box.next()) { row_count += box.x == box.left; @@ -55,7 +55,7 @@ TEST_CASE("basic matrix iterator", "[matrix:basic]") { // confirm boxes have the right number of rows // when x goes to 0 on first next call row_count = 0; - matrix::in_box box{walls, 1, 1, 1}; + matrix::box box{walls, 1, 1, 1}; while(box.next()) { row_count += box.x == box.left; @@ -81,7 +81,7 @@ inline void random_matrix(Matrix &out) { } } -TEST_CASE("thash matrix iterators", "[matrix]") { +TEST_CASE("thrash matrix iterators", "[matrix]") { for(int count = 0; count < Random::uniform(10,30); count++) { size_t width = Random::uniform(1, 100); size_t height = Random::uniform(1, 100); @@ -111,7 +111,7 @@ TEST_CASE("thrash box distance iterators", "[matrix:distance]") { size_t size = Random::uniform(4, 10); Point target{width/2, height/2}; - matrix::in_box box{result, target.x, target.y, size}; + matrix::box box{result, target.x, target.y, size}; while(box.next()) { result[box.y][box.x] = box.distance(); } @@ -138,7 +138,7 @@ TEST_CASE("thrash box iterators", "[matrix]") { PointList result; // make a random size box size_t size = Random::uniform(1, 33); - matrix::in_box box{test, target.x, target.y, size}; + matrix::box box{test, target.x, target.y, size}; while(box.next()) { test[box.y][box.x] = test_i; @@ -217,7 +217,7 @@ TEST_CASE("prototype line algorithm", "[matrix:line]") { // create a target for the paths Point start{.x=map.width() / 2, .y=map.height()/2}; - for(matrix::in_box box{map.walls(), start.x, start.y, 3}; + for(matrix::box box{map.walls(), start.x, start.y, 3}; box.next();) { Matrix result = map.walls();