#pragma once #include #include #include #include #include #include "point.hpp" namespace matrix { using std::vector, std::queue, std::array; using std::min, std::max, std::floor; typedef vector Row; typedef vector Matrix; /* * 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_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 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; 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_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; template 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; 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}; array 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 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 next() { dir++; if(dir < max_dirs) { x = x_dirs[dir]; y = y_dirs[dir]; return true; } else { return false; } } }; using compass = compass_t; struct flood { Matrix &mat; Point start; int old_val; int new_val; queue 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 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; }