From 1295e9631dc338e463d7936e6868763a566f5db8 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Tue, 17 Dec 2024 17:32:27 -0500 Subject: [PATCH] A slightly working flood iterator and a working compass iterator. --- matrix.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ matrix.hpp | 46 ++++++++++++++++++++++++-- status.txt | 3 ++ systems.cpp | 1 - tests/matrix.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++- worldbuilder.cpp | 2 ++ 6 files changed, 214 insertions(+), 4 deletions(-) diff --git a/matrix.cpp b/matrix.cpp index cc28b3c..ec27ab8 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -1,5 +1,6 @@ #include "matrix.hpp" #include "constants.hpp" +#include "dbc.hpp" #include using namespace fmt; @@ -83,6 +84,89 @@ namespace matrix { 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), + 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; + } + } + + bool flood::next_working() { + if(!q.empty()) { + auto current_loc = q.front(); + q.pop(); + + for(matrix::in_box box{mat, current_loc.x, current_loc.y, 1}; + box.next();) + { + if(mat[box.y][box.x] == old_val) { + mat[box.y][box.x] += new_val; + q.push({.x=box.x, .y=box.y}); + } + } + + return true; + } else { + return false; + } + } + void dump(const std::string &msg, Matrix &map, int show_x, int show_y) { println("----------------- {}", msg); @@ -102,4 +186,5 @@ namespace matrix { if(it.row) print("\n"); } } + } diff --git a/matrix.hpp b/matrix.hpp index 061194e..83f6607 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -1,11 +1,18 @@ #pragma once #include +#include #include +#include +#include +#include "point.hpp" + +using fmt::println; namespace matrix { + using std::vector, std::queue, std::array; - typedef std::vector Row; - typedef std::vector Matrix; + typedef vector Row; + typedef vector Matrix; struct each_cell { size_t x = ~0; @@ -42,6 +49,18 @@ namespace matrix { void dump(); }; + struct compass { + 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(Matrix &mat, size_t x, size_t y); + bool next(); + }; + /* * Just a quick thing to reset a matrix to a value. */ @@ -51,5 +70,28 @@ namespace matrix { } } + 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; + } + void dump(const std::string &msg, Matrix &map, int show_x=-1, int show_y=-1); + + 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(); + }; + } diff --git a/status.txt b/status.txt index 27e2758..e7dcbf6 100644 --- a/status.txt +++ b/status.txt @@ -1,5 +1,8 @@ TODAY'S GOAL: +* Fire icon \u2034 +* Water icon \u224b +* Flame pillars icon \u2e3e * Room should always be found. * Change the test matrix to be irregular dimensions. diff --git a/systems.cpp b/systems.cpp index 21d975c..d88b6be 100644 --- a/systems.cpp +++ b/systems.cpp @@ -31,7 +31,6 @@ void System::lighting(DinkyECS::World &world, Map &game_map, LightRender &light, world.query([&](const auto &ent, auto &position, auto &lightsource) { light.render_light(lightsource, position.location); }); - } void System::enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player) { diff --git a/tests/matrix.cpp b/tests/matrix.cpp index 554c1d6..7115dd1 100644 --- a/tests/matrix.cpp +++ b/tests/matrix.cpp @@ -5,6 +5,7 @@ #include "matrix.hpp" #include "rand.hpp" #include "components.hpp" +#include "worldbuilder.hpp" #include #include @@ -13,7 +14,7 @@ using namespace fmt; using std::string; using matrix::Matrix; -TEST_CASE("basic matrix iterator", "[matrix]") { +TEST_CASE("basic matrix iterator", "[matrix:basic]") { std::ifstream infile("./tests/dijkstra.json"); json data = json::parse(infile); auto test = data[0]; @@ -61,6 +62,15 @@ TEST_CASE("basic matrix iterator", "[matrix]") { } REQUIRE(row_count == 3); } + + { + matrix::compass star{walls, 1, 1}; + while(star.next()) { + println("START IS {},{}=={}", star.x, star.y, walls[star.y][star.x]); + walls[star.y][star.x] = 11; + } + matrix::dump("STAR POINT", walls, 1,1); + } } inline void random_matrix(Matrix &out) { @@ -121,3 +131,72 @@ TEST_CASE("thrash box iterators", "[matrix]") { } } } + +TEST_CASE("thrash compass iterators", "[matrix:compass]") { + for(int count = 0; count < 2000; count++) { + size_t width = Random::uniform(1, 25); + size_t height = Random::uniform(1, 33); + + Matrix test(height, matrix::Row(width)); + random_matrix(test); + + // this will be greater than the random_matrix cells + int test_i = Random::uniform(20,30); + + // go through every cell + for(matrix::each_cell target{test}; target.next();) { + PointList result; + // make a random size box + matrix::compass compass{test, target.x, target.y}; + + while(compass.next()) { + test[compass.y][compass.x] = test_i; + result.push_back({compass.x, compass.y}); + } + + for(auto point : result) { + REQUIRE(test[point.y][point.x] == test_i); + test[point.y][point.x] = 10; // kind of reset it for another try + } + } + } +} + +TEST_CASE("prototype flood algorithm", "[matrix:flood]") { + for(int count = 0; count < 1; count++) { + size_t width = Random::uniform(10, 25); + size_t height = Random::uniform(10, 33); + + Map map(width,height); + WorldBuilder builder(map); + builder.generate(); + + REQUIRE(map.room_count() > 0); + + Point start = map.place_entity(map.room_count() / 2); + + // BUG: place_entity should not put things in walls + map.$walls[start.y][start.x] = 0; + + matrix::dump("WALLS BEFORE FLOOD", map.walls(), start.x, start.y); + + /* + for(matrix::flood it{map.$walls, start, 0, 10}; it.next_working(); tick++) { + println("TEST WORKING"); + } + */ + + for(matrix::flood it{map.$walls, start, 0, 15}; it.next();) { + REQUIRE(matrix::inbounds(map.$walls, it.x, it.y)); + map.$walls[it.y][it.x] = 15; + } + + matrix::dump("WALLS AFTER FLOOD", map.walls(), start.x, start.y); + + // confirm that everything is 1 or 2 which confirms + // every cell possible is visited and nothing is visited twice + for(matrix::each_cell it{map.$walls}; it.next();) { + REQUIRE(map.$walls[it.y][it.x] <= 15); + } + } +} diff --git a/worldbuilder.cpp b/worldbuilder.cpp index d78cd5d..18a4e6f 100644 --- a/worldbuilder.cpp +++ b/worldbuilder.cpp @@ -120,6 +120,8 @@ void WorldBuilder::generate() { place_rooms(); + dbc::check($map.room_count() > 0, "map generated zero rooms, map too small?"); + for(size_t i = 0; i < $map.$rooms.size() - 1; i++) { tunnel_doors(holes, $map.$rooms[i], $map.$rooms[i+1]); }