#include "matrix.hpp" #include "constants.hpp" #include "dbc.hpp" #include #include #include 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 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} { 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; } } 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"); } } }