Skip to content

Commit

Permalink
Add C++ code for Flood Fill algorithm (#860)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowMitia authored Oct 18, 2021
1 parent d631070 commit 7f814fa
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 0 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ This file lists everyone, who contributed to this repo and wanted to show up her
- Mahdi Sarikhani
- Ridham177
- Hugo Salou
- Dimitri Belopopsky
156 changes: 156 additions & 0 deletions contents/flood_fill/code/cpp/flood_fill.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#include <array>
#include <cassert>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>

using CartesianIndex = std::array<int, 2>;

auto inbounds(CartesianIndex size, CartesianIndex loc) {
if (loc[0] < 0 || loc[1] < 0) {
return false;
} else if (loc[0] >= size[0] || loc[1] >= size[1]) {
return false;
}
return true;
}

auto find_neighbors(
std::vector<std::vector<float>> const& grid,
CartesianIndex loc,
float old_value,
float /* new_value */) {

const std::vector<CartesianIndex> possible_neighbors{
{loc[0], loc[1] + 1},
{loc[0] + 1, loc[1]},
{loc[0], loc[1] - 1},
{loc[0] - 1, loc[1]}};

std::vector<CartesianIndex> neighbors;

for (auto const& possible_neighbor : possible_neighbors) {
const auto size = CartesianIndex{
static_cast<int>(grid[0].size()), static_cast<int>(grid.size())};
const auto x = static_cast<std::size_t>(possible_neighbor[0]);
const auto y = static_cast<std::size_t>(possible_neighbor[1]);
if (inbounds(size, possible_neighbor) && grid[x][y] == old_value) {
neighbors.push_back(possible_neighbor);
}
}

return neighbors;
}

void recursive_fill(
std::vector<std::vector<float>>& grid,
CartesianIndex loc,
float old_value,
float new_value) {
if (old_value == new_value) {
return;
}

const auto x = static_cast<std::size_t>(loc[0]);
const auto y = static_cast<std::size_t>(loc[1]);

grid[x][y] = new_value;

const auto possible_neighbors = find_neighbors(grid, loc, old_value, new_value);
for (auto const& possible_neighbor : possible_neighbors) {
recursive_fill(grid, possible_neighbor, old_value, new_value);
}
}

void queue_fill(
std::vector<std::vector<float>>& grid,
CartesianIndex loc,
float old_value,
float new_value) {
if (old_value == new_value) {
return;
}

auto q = std::queue<CartesianIndex>{};
q.push(loc);
const auto x = static_cast<std::size_t>(loc[0]);
const auto y = static_cast<std::size_t>(loc[1]);
grid[x][y] = new_value;

while (q.size() > 0) {
const auto current_loc = q.front();
q.pop();
const auto possible_neighbors =
find_neighbors(grid, current_loc, old_value, new_value);
for (auto const& neighbor : possible_neighbors) {
const auto neighbor_x = static_cast<std::size_t>(neighbor[0]);
const auto neighbor_y = static_cast<std::size_t>(neighbor[1]);
grid[neighbor_x][neighbor_y] = new_value;
q.push(neighbor);
}
}
}

void stack_fill(
std::vector<std::vector<float>>& grid,
CartesianIndex loc,
float old_value,
float new_value) {
if (old_value == new_value) {
return;
}

auto s = std::stack<CartesianIndex>{};
s.push(loc);

while (s.size() > 0) {
const auto current_loc = s.top();
s.pop();

const auto x = static_cast<std::size_t>(current_loc[0]);
const auto y = static_cast<std::size_t>(current_loc[1]);

if (grid[x][y] == old_value) {
grid[x][y] = new_value;
const auto possible_neighbors =
find_neighbors(grid, current_loc, old_value, new_value);
for (auto const& neighbor : possible_neighbors) {
s.push(neighbor);
}
}
}
}

int main() {

const std::vector<std::vector<float>> grid{
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0},
{0, 0, 1, 0, 0}};

const std::vector<std::vector<float>> solution_grid{
{1, 1, 1, 0, 0},
{1, 1, 1, 0, 0},
{1, 1, 1, 0, 0},
{1, 1, 1, 0, 0},
{1, 1, 1, 0, 0}};

const CartesianIndex start_loc{1, 1};

auto test_grid = grid;
recursive_fill(test_grid, start_loc, 0.0, 1.0);
assert(test_grid == solution_grid);

test_grid = grid;
queue_fill(test_grid, start_loc, 0.0, 1.0);
assert(test_grid == solution_grid);

test_grid = grid;
stack_fill(test_grid, start_loc, 0.0, 1.0);
assert(test_grid == solution_grid);

return EXIT_SUCCESS;
}
10 changes: 10 additions & 0 deletions contents/flood_fill/flood_fill.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ In code, this might look like this:
[import:23-41, lang:"julia"](code/julia/flood_fill.jl)
{% sample lang="c" %}
[import:28-46, lang:"c"](code/c/flood_fill.c)
{% sample lang="cpp" %}
[import:19-44, lang:"cpp"](code/cpp/flood_fill.cpp)
{% sample lang="py" %}
[import:10-25, lang="python"](code/python/flood_fill.py)
{% sample lang="coco" %}
Expand All @@ -110,6 +112,8 @@ In code, it might look like this:
[import:92-104, lang:"julia"](code/julia/flood_fill.jl)
{% sample lang="c" %}
[import:174-189, lang:"c"](code/c/flood_fill.c)
{% sample lang="cpp" %}
[import:46-64, lang:"cpp"](code/cpp/flood_fill.cpp)
{% sample lang="py" %}
[import:55-63, lang="python"](code/python/flood_fill.py)
{% sample lang="coco" %}
Expand All @@ -125,6 +129,8 @@ Additionally, it is possible to do the same type of traversal by managing a stac
[import:43-63, lang:"julia"](code/julia/flood_fill.jl)
{% sample lang="c" %}
[import:79-102, lang:"c"](code/c/flood_fill.c)
{% sample lang="cpp" %}
[import:95-123, lang:"cpp"](code/cpp/flood_fill.cpp)
{% sample lang="py" %}
[import:27-36, lang="python"](code/python/flood_fill.py)
{% sample lang="coco" %}
Expand Down Expand Up @@ -168,6 +174,8 @@ The code would look something like this:
[import:66-90, lang:"julia"](code/julia/flood_fill.jl)
{% sample lang="c" %}
[import:149-172, lang:"c"](code/c/flood_fill.c)
{% sample lang="cpp" %}
[import:66-93, lang:"cpp"](code/cpp/flood_fill.cpp)
{% sample lang="py" %}
[import:38-53, lang="python"](code/python/flood_fill.py)
{% sample lang="coco" %}
Expand Down Expand Up @@ -250,6 +258,8 @@ After, we will fill in the left-hand side of the array to be all ones by choosin
[import, lang:"julia"](code/julia/flood_fill.jl)
{% sample lang="c" %}
[import, lang:"c"](code/c/flood_fill.c)
{% sample lang="cpp" %}
[import, lang:"cpp"](code/cpp/flood_fill.cpp)
{% sample lang="py" %}
[import:, lang="python"](code/python/flood_fill.py)
{% sample lang="coco" %}
Expand Down

0 comments on commit 7f814fa

Please sign in to comment.