Actually my implementation is not working very well for big areas (I don't know why) I already created a question on Stackoverflow. But I figured out how to do it to work with an O(n) implementation (you can see what I mean here (see the fiddle I attached)).
But for some reason as I said it is not working very well on big areas.
/// <summary>
/// Floods the fill.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target.</param>
/// <param name="replacement">The replacement.</param>
public static void FloodFill<T>(this T[] source, int x, int y, int width, int height, T target, T replacement)
where T : IEquatable<T>
{
int i;
source.FloodFill(x, y, width, height, target, replacement, out i);
}
/// <summary>
/// Floods the array following Flood Fill algorithm
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">The source.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="target">The target to replace.</param>
/// <param name="replacement">The replacement.</param>
/// <param name="i">The i.</param>
// This was generic
public static void FloodFill<T>(this T[] source, int x, int y, int width, int height, T target, T replacement, out int i)
where T : IEquatable<T>
{
i = 0;
HashSet<int> queue = new HashSet<int>();
queue.Add(P(x, y, width, height));
while (queue.Count > 0)
{
int _i = queue.First(),
_x = _i % width,
_y = _i / width;
queue.Remove(_i);
if (source[_i].Equals(target))
source[_i] = replacement;
for (int offsetX = -1; offsetX < 2; offsetX++)
for (int offsetY = -1; offsetY < 2; offsetY++)
{
// do not check origin or diagonal neighbours
if (offsetX == 0 && offsetY == 0 || offsetX == offsetY || offsetX == -offsetY || -offsetX == offsetY)
continue;
int targetIndex = Pn(_x + offsetX, _y + offsetY, width); // This is already inverted that's why we don't use F.P(...)
int _tx = targetIndex % width,
_ty = targetIndex / width;
// skip out of bounds point
if (_tx < 0 || _ty < 0 || _tx >= width || _ty >= height)
continue;
if (!queue.Contains(targetIndex) && source[targetIndex].Equals(target))
{
queue.Add(targetIndex);
if (Monitor.IsEntered(i))
++i;
else
Interlocked.Increment(ref i);
}
}
if (i > 100000)
break;
}
}
My main concerns are the following:
- I don't know if there is a better way to debug how many iterations has the algorithm done (and if I'm getting them correctly).
- I don't like to use
Monitor.IsEntered
(I'm not sure if this is needed). - I would like to speed-up it, but I don't know how (I think this is slow) (you can compare it with ms-paint to see differences, I know it's written on C++, but... I would like to get a significant perfomance).
- Also, I don't know if there is a better way to do it (to avoid unnecesary memory consumption).
i
from a different thread for some reason? (e.g. to show a progress bar?) \$\endgroup\$