A bit of late night work designing the little iterators.

main
Zed A. Shaw 1 week ago
parent da0b941dfd
commit 8e470df554
  1. 2
      lights.hpp
  2. 6
      map.cpp
  3. 53
      matrix.cpp
  4. 49
      matrix.hpp
  5. 22
      pathing.cpp
  6. 5
      pathing.hpp
  7. 4
      tests/map.cpp
  8. 199
      tests/matrix.cpp
  9. 4
      tests/pathing.cpp
  10. 2
      tests/worldbuilder.cpp
  11. 8
      worldbuilder.cpp

@ -40,7 +40,7 @@ namespace lighting {
LightRender(size_t width, size_t height) : LightRender(size_t width, size_t height) :
$width(width), $width(width),
$height(height), $height(height),
$lightmap(height, MatrixRow(width, 0)), $lightmap(height, matrix::Row(width, 0)),
$paths(width, height) $paths(width, height)
{} {}

@ -13,7 +13,7 @@ using namespace fmt;
Map::Map(size_t width, size_t height) : Map::Map(size_t width, size_t height) :
$width(width), $width(width),
$height(height), $height(height),
$walls(height, MatrixRow(width, INV_WALL)), $walls(height, matrix::Row(width, INV_WALL)),
$paths(height, width) $paths(height, width)
{} {}
@ -54,8 +54,8 @@ bool Map::iswall(size_t x, size_t y) {
} }
void Map::dump(int show_x, int show_y) { void Map::dump(int show_x, int show_y) {
matrix_dump("WALLS", walls(), show_x, show_y); matrix::dump("WALLS", walls(), show_x, show_y);
matrix_dump("PATHS", paths(), show_x, show_y); matrix::dump("PATHS", paths(), show_x, show_y);
} }
bool Map::can_move(Point move_to) { bool Map::can_move(Point move_to) {

@ -3,23 +3,54 @@
#include <fmt/core.h> #include <fmt/core.h>
using namespace fmt; using namespace fmt;
using matrix::Matrix;
void matrix_dump(const std::string &msg, Matrix &map, int show_x, int show_y) { namespace matrix {
println("----------------- {}", msg);
for(size_t y = 0; y < map.size(); y++) {
for(size_t x = 0; x < map[y].size(); x++) {
int col = map[y][x];
if(int(x) == show_x && int(y) == show_y) { each_cell::each_cell(Matrix &mat)
print("{:x}<", col); {
} else if(col == WALL_PATH_LIMIT) { height = mat.size();
width = mat[0].size();
}
bool each_cell::next() {
x++;
x *= (x < width);
y = y + (x == 0);
return y < height;
}
each_row::each_row(Matrix &mat) :
$mat(mat)
{
height = $mat.size();
width = $mat[0].size();
}
bool each_row::next() {
x++;
x *= (x < width);
y = y + (x == 0);
row = x == width - 1;
cell = y < height ? $mat[y][x] : -1;
return y < height;
}
void dump(const std::string &msg, Matrix &map, int show_x, int show_y) {
println("----------------- {}", msg);
for(each_row it{map}; it.next();) {
if(int(it.x) == show_x && int(it.y) == show_y) {
print("{:x}<", it.cell);
} else if(it.cell == WALL_PATH_LIMIT) {
print("# "); print("# ");
} else if(col > 15) { } else if(it.cell > 15) {
print("* "); print("* ");
} else { } else {
print("{:x} ", col); print("{:x} ", it.cell);
} }
if(it.row) print("\n");
} }
print("\n");
} }
} }

@ -2,16 +2,43 @@
#include <vector> #include <vector>
#include <string> #include <string>
typedef std::vector<int> MatrixRow; namespace matrix {
typedef std::vector<MatrixRow> Matrix;
typedef std::vector<int> Row;
/* typedef std::vector<Row> Matrix;
* Just a quick thing to reset a matrix to a value.
*/ struct each_cell {
inline void matrix_assign(Matrix &out, int new_value) { size_t x = ~0;
for(auto &row : out) { size_t y = ~0;
row.assign(row.size(), new_value); size_t width = 0;
size_t height = 0;
int cell = 0;
each_cell(Matrix &mat);
bool next();
};
struct each_row {
Matrix &$mat;
size_t x = ~0;
size_t y = ~0;
size_t width = 0;
size_t height = 0;
int cell = 0;
bool row = false;
each_row(Matrix &mat);
bool next();
};
/*
* 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);
}
} }
}
void matrix_dump(const std::string &msg, Matrix &map, int show_x=-1, int show_y=-1); void dump(const std::string &msg, Matrix &map, int show_x=-1, int show_y=-1);
}

@ -28,7 +28,7 @@ inline void add_neighbors(PointList &neighbors, Matrix &closed, size_t y, size_t
void Pathing::compute_paths(Matrix &walls) { void Pathing::compute_paths(Matrix &walls) {
INVARIANT(); INVARIANT();
// Initialize the new array with every pixel at limit distance // Initialize the new array with every pixel at limit distance
matrix_assign($paths, WALL_PATH_LIMIT); matrix::assign($paths, WALL_PATH_LIMIT);
Matrix closed = walls; Matrix closed = walls;
PointList starting_pixels; PointList starting_pixels;
@ -77,19 +77,13 @@ void Pathing::clear_target(const Point &at) {
} }
void Pathing::random_flood(const Point from, std::function<void(Point at, int dnum)> cb) { void Pathing::random_flood(const Point from, std::function<void(Point at, int dnum)> cb) {
int from_x = from.x; // quick hack to try the idea
int from_y = from.y; matrix::each_cell it{$paths};
int dnum = $paths[from.y][from.x]; it.x = from.x;
cb(from, dnum); it.y = from.y;
for(int y = from_y - 1; y <= from_y + 1; y++) { while(it.next()) {
if(y < 0 || y >= int($height)) continue; cb({it.x, it.y}, $paths[it.y][it.x]);
for(int x = from_x - 1; x <= from_x + 1; x++) {
if(x >= 0 && x <= int($width)) {
dnum = $paths[y][x];
cb({size_t(x), size_t(y)}, dnum);
}
}
} }
} }

@ -3,6 +3,7 @@
#include "matrix.hpp" #include "matrix.hpp"
#include <functional> #include <functional>
using matrix::Matrix;
class Pathing { class Pathing {
public: public:
@ -14,8 +15,8 @@ public:
Pathing(size_t width, size_t height) : Pathing(size_t width, size_t height) :
$width(width), $width(width),
$height(height), $height(height),
$paths(height, MatrixRow(width, 1)), $paths(height, matrix::Row(width, 1)),
$input(height, MatrixRow(width, 1)) $input(height, matrix::Row(width, 1))
{} {}
void compute_paths(Matrix &walls); void compute_paths(Matrix &walls);

@ -48,8 +48,8 @@ TEST_CASE("dijkstra algo test", "[map]") {
if(paths != expected) { if(paths != expected) {
println("ERROR! ------"); println("ERROR! ------");
matrix_dump("EXPECTED", expected); matrix::dump("EXPECTED", expected);
matrix_dump("RESULT", paths); matrix::dump("RESULT", paths);
} }
REQUIRE(map.INVARIANT()); REQUIRE(map.INVARIANT());

@ -10,117 +10,7 @@
using namespace nlohmann; using namespace nlohmann;
using namespace fmt; using namespace fmt;
using std::string; using std::string;
using matrix::Matrix;
#include <algorithm>
#include <iostream>
struct ItStep {
int cell;
size_t x;
size_t y;
bool row;
};
class MatrixIterator1 {
public:
class iterator
{
public:
Matrix &mat;
size_t x = 0;
size_t y = 0;
using iterator_category = std::input_iterator_tag;
using value_type = ItStep;
using difference_type = ItStep;
using pointer = ItStep *;
using reference = ItStep;
explicit iterator(Matrix &_mat)
: mat(_mat) {}
iterator& operator++() {
x++;
if(x < mat[0].size()) {
return *this;
} else {
x = 0;
y++;
return *this;
}
}
iterator operator++(int) {
iterator retval = *this;
++(*this);
return retval;
}
bool operator==(iterator other) const {
return x == other.x && y == other.y;
}
reference operator*() const {
return {
.cell = mat[y][x],
.x = x,
.y = y,
.row = x >= mat[0].size() - 1
};
}
};
Matrix &mat;
MatrixIterator1(Matrix &mat_) :
mat(mat_)
{
}
iterator begin() {
return iterator(mat);
}
iterator end() {
iterator it(mat);
it.y = mat.size();
it.x = 0;
return it;
}
};
struct MatrixIterator2 {
Matrix &$mat;
size_t x = ~0;
size_t y = ~0;
size_t width = 0;
size_t height = 0;
int cell = 0;
bool row = false;
MatrixIterator2(Matrix &mat) :
$mat(mat)
{
height = $mat.size();
width = $mat[0].size();
}
bool next() {
x++;
x *= (x < width);
y = y + (x == 0);
row = x == width - 1;
if(y < height) {
cell = $mat[y][x];
return true;
} else {
return false;
}
}
};
TEST_CASE("basic matrix iterator", "[matrix]") { TEST_CASE("basic matrix iterator", "[matrix]") {
std::ifstream infile("./tests/dijkstra.json"); std::ifstream infile("./tests/dijkstra.json");
@ -129,89 +19,30 @@ TEST_CASE("basic matrix iterator", "[matrix]") {
Matrix walls = test["walls"]; Matrix walls = test["walls"];
matrix_dump("ITERATOR DUMP", walls); matrix::dump("ITERATOR DUMP", walls);
println("VS Matrix1 ------"); println("VS matrix::each_row ------");
for(auto [cell, x, y, row] : MatrixIterator1(walls)) { for(matrix::each_row it{walls}; it.next();) {
REQUIRE(walls[y][x] == cell); REQUIRE(walls[it.y][it.x] == it.cell);
print("{} ", cell); print("{} ", it.cell);
if(row) print("\n"); if(it.row) print("\n");
} }
println("VS Matrix2------"); // tests going through straight cells but also
// using two iterators on one matrix (or two)
matrix::each_cell cells{walls};
cells.next(); // kick it off
for(MatrixIterator2 mit{walls}; mit.next();) { for(matrix::each_row it{walls};
REQUIRE(walls[mit.y][mit.x] == mit.cell); it.next(); cells.next())
print("{} ", mit.cell); {
if(mit.row) print("\n"); REQUIRE(walls[cells.y][cells.x] == it.cell);
} }
println("END TEST============="); println("END TEST=============");
} }
template<long FROM, long TO>
class Range {
public:
class iterator
{
long num = FROM;
public:
using iterator_category = std::input_iterator_tag;
using value_type = long;
using difference_type = long;
using pointer = const long *;
using reference = long;
explicit iterator(long _num = 0) : num(_num) {}
iterator& operator++() {
num = TO >= FROM ? num + 1 : num - 1;
return *this;
}
iterator operator++(int) {
iterator retval = *this;
++(*this);
return retval;
}
bool operator==(iterator other) const {
return num == other.num;
}
bool operator!=(iterator other) const {
return !(*this == other);
}
reference operator*() const {
return num;
}
};
iterator begin() {
return iterator(FROM);
}
iterator end() {
return iterator(TO >= FROM ? TO + 1 : TO - 1);
}
};
TEST_CASE("basic matrix example", "[matrix]") {
auto range = Range<15, 25>();
auto itr = std::find(range.begin(), range.end(), 18);
std::cout << *itr << '\n';
for(long l : Range<3, 5>()) {
std::cout << l << ' ';
}
std::cout << '\n';
}
TEST_CASE("matrix_assign works", "[matrix]") { TEST_CASE("matrix_assign works", "[matrix]") {
} }

@ -30,8 +30,8 @@ TEST_CASE("dijkstra algo test", "[pathing]") {
REQUIRE(pathing.INVARIANT()); REQUIRE(pathing.INVARIANT());
matrix_dump("PATHING RESULT", pathing.$paths); matrix::dump("PATHING RESULT", pathing.$paths);
matrix_dump("PATHING EXPECTED", expected); matrix::dump("PATHING EXPECTED", expected);
REQUIRE(pathing.$paths == expected); REQUIRE(pathing.$paths == expected);
} }
} }

@ -20,7 +20,7 @@ TEST_CASE("dumping and debugging", "[builder]") {
WorldBuilder builder(map); WorldBuilder builder(map);
builder.generate(); builder.generate();
matrix_dump("GENERATED", map.paths()); matrix::dump("GENERATED", map.paths());
map.dump(); map.dump();
} }

@ -131,12 +131,8 @@ void WorldBuilder::generate() {
$map.$walls[hole.y][hole.x] = INV_SPACE; $map.$walls[hole.y][hole.x] = INV_SPACE;
} }
// invert the whole map to finish it for(matrix::each_cell it{$map.$walls}; it.next();) {
for(size_t y = 0; y < $map.$height; ++y) { $map.$walls[it.y][it.x] = !$map.$walls[it.y][it.x];
for(size_t x = 0; x < $map.$width; ++x) {
// invert the map
$map.$walls[y][x] = !$map.$walls[y][x];
}
} }
} }

Loading…
Cancel
Save