Circle iterator now compensates for the matrix size and won't overflow.

main
Zed A. Shaw 4 days ago
parent 35f2defc11
commit 857cd2f910
  1. 6
      lights.cpp
  2. 15
      matrix.cpp
  3. 4
      matrix.hpp
  4. 11
      tests/matrix.cpp
  5. 4
      worldbuilder.cpp

@ -7,17 +7,13 @@ using std::vector;
namespace lighting {
void LightRender::render_circle_light(LightSource source, Point at, PointList &has_light) {
for(matrix::circle it{at, source.distance + 1}; it.next();) {
for(matrix::circle it{$lightmap, at, source.distance + 1}; it.next();) {
for(int x = it.left; x < it.right; x++) {
if(matrix::inbounds($paths.$paths, x, it.y) &&
$paths.$paths[it.y][x] != WALL_PATH_LIMIT)
{
$lightmap[it.y][x] = light_level(source.strength, x, it.y);
has_light.push_back({(size_t)x, (size_t)it.y});
}
}
}
}
void LightRender::render_compass_light(LightSource source, Point at, PointList &has_light) {
for(matrix::compass it{$lightmap, at.x, at.y}; it.next();) {

@ -180,21 +180,24 @@ namespace matrix {
}
circle::circle(Point center, int radius) :
circle::circle(Matrix &mat, Point center, int radius) :
center(center), radius(radius)
{
top = max(center.y - radius, size_t(0));
bottom = center.y + radius;
width = matrix::width(mat);
height = matrix::height(mat);
top = max(int(center.y - radius), 0);
bottom = min(int(center.y + radius), height);
y = top;
}
bool circle::next() {
y++;
if(y <= bottom) {
if(y < bottom) {
dy = y - center.y;
dx = floor(sqrt(radius * radius - dy * dy));
left = center.x - dx;
right = center.x + dx;
left = max(0, int(center.x - dx));
right = min(width, int(center.x + dx));
return true;
} else {
return false;

@ -127,8 +127,10 @@ namespace matrix {
int right = 0;
int top = 0;
int bottom = 0;
int width = 0;
int height = 0;
circle(Point center, int radius);
circle(Matrix &mat, Point center, int radius);
void update();
bool next();
};

@ -226,7 +226,7 @@ TEST_CASE("prototype line algorithm", "[matrix:line]") {
}
TEST_CASE("prototype circle algorithm", "[matrix:circle]") {
for(int count = 0; count < 20; count++) {
for(int count = 0; count < 2000; count++) {
size_t width = Random::uniform<size_t>(10, 13);
size_t height = Random::uniform<size_t>(10, 15);
int pos_mod = Random::uniform<int>(-3,3);
@ -238,14 +238,17 @@ TEST_CASE("prototype circle algorithm", "[matrix:circle]") {
// use an empty map
Matrix result = map.walls();
for(matrix::circle it{start, radius}; it.next();) {
for(matrix::circle it{result, start, radius}; it.next();) {
for(int x = it.left; x < it.right; x++) {
// println("top={}, bottom={}, center.y={}, dy={}, left={}, right={}, x={}, y={}", it.top, it.bottom, it.center.y, it.dy, it.left, it.right, x, it.y);
if(matrix::inbounds(result, x, it.y)) {
// println("RESULT {},{}", matrix::width(result), matrix::height(result));
REQUIRE(it.y >= 0);
REQUIRE(x >= 0);
REQUIRE(it.y < int(matrix::height(result)));
REQUIRE(x < int(matrix::width(result)));
result[it.y][x] += 1;
}
}
}
// matrix::dump("RESULT AFTER CIRCLE", result, start.x, start.y);
}

@ -142,13 +142,11 @@ void WorldBuilder::generate() {
$map.load_tiles();
Point center = $map.place_entity(1);
for(matrix::circle it{center, 3}; it.next();) {
for(matrix::circle it{$map.$walls, center, 3}; it.next();) {
for(int x = it.left; x < it.right; x++) {
if($map.inmap(x, it.y) && !$map.iswall(x, it.y)) {
$map.$tiles.set_tile(x, it.y, "WATER_TILE");
}
}
}
}
void WorldBuilder::make_room(size_t origin_x, size_t origin_y, size_t w, size_t h) {

Loading…
Cancel
Save