Skip to content

Commit aba2fd1

Browse files
authored
Add flood fill (#224)
* add FloodFill.cs * add FloodFillTest.cs * update DIRECTORY.md * update README.md
1 parent 57a6cbc commit aba2fd1

File tree

4 files changed

+218
-0
lines changed

4 files changed

+218
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using System;
2+
using NUnit.Framework;
3+
using FluentAssertions;
4+
using System.Drawing;
5+
6+
namespace FloodFillTest
7+
{
8+
public static class Tests
9+
{
10+
private static Color black = Color.FromArgb(255, 0, 0, 0);
11+
private static Color green = Color.FromArgb(255, 0, 255, 0);
12+
private static Color violet = Color.FromArgb(255, 255, 0, 255);
13+
private static Color white = Color.FromArgb(255, 255, 255, 255);
14+
private static Color orange = Color.FromArgb(255, 255, 128, 0);
15+
16+
[Test]
17+
public static void BreadthFirstSearch_ThrowsArgumentOutOfRangeException()
18+
{
19+
Action act = () => Algorithms.Other.FloodFill.BreadthFirstSearch(GenerateTestBitmap(), (10, 10), black, white);
20+
act.Should().Throw<ArgumentOutOfRangeException>();
21+
}
22+
23+
[Test]
24+
public static void DepthFirstSearch_ThrowsArgumentOutOfRangeException()
25+
{
26+
Action act = () => Algorithms.Other.FloodFill.DepthFirstSearch(GenerateTestBitmap(), (-1, -1), black, white);
27+
act.Should().Throw<ArgumentOutOfRangeException>();
28+
}
29+
30+
[Test]
31+
public static void BreadthFirstSearch_Test1()
32+
{
33+
TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), green, orange, (1, 1), orange);
34+
}
35+
36+
[Test]
37+
public static void BreadthFirstSearch_Test2()
38+
{
39+
TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), green, orange, (0, 1), violet);
40+
}
41+
42+
[Test]
43+
public static void BreadthFirstSearch_Test3()
44+
{
45+
TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), green, orange, (0, 1), violet);
46+
}
47+
48+
[Test]
49+
public static void BreadthFirstSearch_Test4()
50+
{
51+
TestAlgorithm(Algorithms.Other.FloodFill.BreadthFirstSearch, (1, 1), green, orange, (6, 4), white);
52+
}
53+
54+
[Test]
55+
public static void DepthFirstSearch_Test1()
56+
{
57+
TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), green, orange, (1, 1), orange);
58+
}
59+
60+
[Test]
61+
public static void DepthFirstSearch_Test2()
62+
{
63+
TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), green, orange, (0, 1), violet);
64+
}
65+
66+
[Test]
67+
public static void DepthFirstSearch_Test3()
68+
{
69+
TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), green, orange, (0, 1), violet);
70+
}
71+
72+
[Test]
73+
public static void DepthFirstSearch_Test4()
74+
{
75+
TestAlgorithm(Algorithms.Other.FloodFill.DepthFirstSearch, (1, 1), green, orange, (6, 4), white);
76+
}
77+
78+
private static Bitmap GenerateTestBitmap()
79+
{
80+
Color[,] layout =
81+
{
82+
{violet, violet, green, green, black, green, green},
83+
{violet, green, green, black, green, green, green},
84+
{green, green, green, black, green, green, green},
85+
{black, black, green, black, white, white, green},
86+
{violet, violet, black, violet, violet, white, white},
87+
{green, green, green, violet, violet, violet, violet},
88+
{violet, violet, violet, violet, violet, violet, violet}
89+
};
90+
91+
Bitmap bitmap = new Bitmap(7, 7);
92+
for (int x = 0; x < layout.GetLength(0); x++)
93+
{
94+
for (int y = 0; y < layout.GetLength(1); y++)
95+
{
96+
bitmap.SetPixel(x, y, layout[y, x]);
97+
}
98+
}
99+
100+
return bitmap;
101+
}
102+
103+
private static void TestAlgorithm(
104+
Action<Bitmap, ValueTuple<int, int>, Color, Color> algorithm,
105+
ValueTuple<int, int> fillLocation,
106+
Color targetColor,
107+
Color replacementColor,
108+
ValueTuple<int, int> testLocation,
109+
Color expectedColor)
110+
{
111+
Bitmap bitmap = GenerateTestBitmap();
112+
algorithm(bitmap, fillLocation, targetColor, replacementColor);
113+
Color actualColor = bitmap.GetPixel(testLocation.Item1, testLocation.Item2);
114+
actualColor.Should().Be(expectedColor);
115+
}
116+
}
117+
}

Algorithms/Other/FloodFill.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Drawing;
4+
using System.Numerics;
5+
6+
namespace Algorithms.Other
7+
{
8+
/// <summary>
9+
/// Flood fill, also called seed fill, is an algorithm that determines and
10+
/// alters the area connected to a given node in a multi-dimensional array with
11+
/// some matching attribute. It is used in the "bucket" fill tool of paint
12+
/// programs to fill connected, similarly-colored areas with a different color.
13+
/// (description adapted from https://en.wikipedia.org/wiki/Flood_fill)
14+
/// (see also: https://www.techiedelight.com/flood-fill-algorithm/).
15+
/// </summary>
16+
public static class FloodFill
17+
{
18+
private static List<(int xOffset, int yOffset)> neighbors = new List<(int xOffset, int yOffset)> { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) };
19+
20+
/// <summary>
21+
/// Implements the flood fill algorithm through a breadth-first approach using a queue.
22+
/// </summary>
23+
/// <param name="bitmap">The bitmap to which the algorithm is applied.</param>
24+
/// <param name="location">The start location on the bitmap.</param>
25+
/// <param name="targetColor">The old color to be replaced.</param>
26+
/// <param name="replacementColor">The new color to replace the old one.</param>
27+
public static void BreadthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor)
28+
{
29+
if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height)
30+
{
31+
throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap");
32+
}
33+
34+
var queue = new List<(int x, int y)>();
35+
queue.Add(location);
36+
37+
while (queue.Count > 0)
38+
{
39+
BreadthFirstFill(bitmap, location, targetColor, replacementColor, queue);
40+
}
41+
}
42+
43+
/// <summary>
44+
/// Implements the flood fill algorithm through a depth-first approach through recursion.
45+
/// </summary>
46+
/// <param name="bitmap">The bitmap to which the algorithm is applied.</param>
47+
/// <param name="location">The start location on the bitmap.</param>
48+
/// <param name="targetColor">The old color to be replaced.</param>
49+
/// <param name="replacementColor">The new color to replace the old one.</param>
50+
public static void DepthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor)
51+
{
52+
if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height)
53+
{
54+
throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap");
55+
}
56+
57+
DepthFirstFill(bitmap, location, targetColor, replacementColor);
58+
}
59+
60+
private static void BreadthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor, List<(int x, int y)> queue)
61+
{
62+
(int x, int y) currentLocation = queue[0];
63+
queue.RemoveAt(0);
64+
65+
if (bitmap.GetPixel(currentLocation.x, currentLocation.y) == targetColor)
66+
{
67+
bitmap.SetPixel(currentLocation.x, currentLocation.y, replacementColor);
68+
69+
for (int i = 0; i < neighbors.Count; i++)
70+
{
71+
int x = currentLocation.x + neighbors[i].xOffset;
72+
int y = currentLocation.y + neighbors[i].yOffset;
73+
if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height)
74+
{
75+
queue.Add((x, y));
76+
}
77+
}
78+
}
79+
}
80+
81+
private static void DepthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor)
82+
{
83+
if (bitmap.GetPixel(location.x, location.y) == targetColor)
84+
{
85+
bitmap.SetPixel(location.x, location.y, replacementColor);
86+
87+
for (int i = 0; i < neighbors.Count; i++)
88+
{
89+
int x = location.x + neighbors[i].xOffset;
90+
int y = location.y + neighbors[i].yOffset;
91+
if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height)
92+
{
93+
DepthFirstFill(bitmap, (x, y), targetColor, replacementColor);
94+
}
95+
}
96+
}
97+
}
98+
}
99+
}

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
* [Mandelbrot](https://github.com/TheAlgorithms/C-Sharp/blob/master/Algorithms/Other/Mandelbrot.cs)
8787
* [Koch Snowflake](https://github.com/TheAlgorithms/C-Sharp/blob/master/Algorithms/Other/KochSnowflake.cs)
8888
* [RGB-HSV Conversion](https://github.com/TheAlgorithms/C-Sharp/blob/master/Algorithms/Other/RGBHSVConversion.cs)
89+
* [Flood Fill](https://github.com/TheAlgorithms/C-Sharp/blob/master/Algorithms/Other/FloodFill.cs)
8990
## Problems
9091
* [Stable Marriage](https://github.com/TheAlgorithms/C-Sharp/blob/master/Algorithms/Problems/StableMarriage/GaleShapley.cs)
9192
* [N-Queens](https://github.com/TheAlgorithms/C-Sharp/blob/master/Algorithms/Problems/NQueens/BacktrackingNQueensSolver.cs)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ This repository contains algorithms and data structures implemented in C# for ed
9595
* [Mandelbrot](./Algorithms/Other/Mandelbrot.cs)
9696
* [Koch Snowflake](./Algorithms/Other/KochSnowflake.cs)
9797
* [RGB-HSV Conversion](./Algorithms/Other/RGBHSVConversion.cs)
98+
* [Flood Fill](./Algorithms/Other/FloodFill.cs)
9899
* [Problems](./Algorithms/Problems)
99100
* [Stable Marriage](./Algorithms/Problems/StableMarriage)
100101
* [Gale-Shapley](./Algorithms/Problems/StableMarriage/GaleShapley.cs)

0 commit comments

Comments
 (0)