Filling a 2D grid recursively

Hi all,

I’ve been battling with a filling function for the last couple of days and am at my wits end.

I have a 2d grid that I’m manipulating through an array. For example:

[ 0 0 0 0 0 0 0 0 0 0 ]
[ 0 0 1 1 1 1 1 1 0 0 ]
[ 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 0 0 1 0 0 ]
[ 0 0 1 1 1 1 1 1 0 0 ]
[ 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 0 0 1 0 0 ]
[ 0 0 1 0 0 0 0 1 0 0 ]
[ 0 0 1 1 1 1 1 1 0 0 ]
[ 0 0 0 0 0 0 0 0 0 0 ]

In reality, the grid is a lot bigger (about 1000x3000) and the formation of 1s is a lot more complex. So I’ve tried implementing some way of recursively filling in the 0s contiguously (so that the fill is blocked by the 1s).

I am using scan lines to fill it in as quickly as possible, but have run into troubles when picking the next scan line. My solutions either involve the fill seeping into areas it shouldn’t be or randomly stopping and thinking it’s done.

If anyone has any experience with this I would appreciate any help you can give.

I could post my code if anyone is interested, but right now it is quite messy and a lot of the variables aren’t self explanatory. If anyone wants to see it I can clean it up and post it. For now thought, it is pretty useless.

Basic Grid:

var grid : int[,];

function Start(){
	grid=new int[1000, 3000]; // 1000 tall, 3000 wide
	for(var i=0; i<1000; i++){
		for(var j=0; j<3000; j++){
			grid[i, j]=0;
		}
	}
}

How you fill it, and your checks on it all depend on what you are doing. It can get pretty intense though. Without code to tell us what you are doing its kind of hard to figure out what all you are trying to do with the grid.

Sorry BigMisterB I wasn’t too clear on that. I already have a grid (already populated with 0s and 1s). I want to be able to take a point and fill in the area. Similar to how paint would fill it in if it were a series of black and white pixels.

Taking a look at Flood fill - Wikipedia gives you a quick overview of what I’m trying to do. I’m trying to implement the scanline method. It’s done by taking rows and filling in the necessary pixels.

I am not looking for someone to fix my code, nor give me it. I’m looking more for the correct approach. Right now I’m just implementing how I think it should work. I reckon, however, there is a much more efficient way of detecting when and where to insert pixels.

Couldn’t you just check the 4 directions, and if they are 0, set them to 1 and recurse, else ignore?

i.e.

public void fill(int xIndex, int yIndex)
{
tiles[xIndex][yIndex] = 1;
if(tiles[xIndex + 1][yIndex] == 0)
{
fill(xIndex + 1, yIndex);
} //Do nothing if it's already set, because you've either found a wall, or don't want to fill from a tile that's already checked.
//Repeat for [x - 1, y],[x, y + 1], and [x, y - 1]
}

This logic would break at all walls and make sure to check he neighbours of every single tile modified. You can add diagonal checks if you want flood fill to get those as well.

Edit: this logic looks to be the same as the Wikipedia link

You’re right Ntero, and that was the first thing I implimented. However it is extremely slow. Each pixel gets checked about 4 times (only less if they are blocked by walls/edges). Although it works perfectly, to fill and recursively go through a grid 1000x3000 big takes a long time. I stopped the simulation after about 2 minutes.

I think the wiki also talks about this, which is why I attempted the scanline method.

The current code I’m testing:

Things to note:

The variable City is an int[,] already predefined.
The number 1 signifies a ‘wall’ i don’t want to cross.
The number 0 is an empty space.
I am trying to fill with the number 10.

function FillCity(){

	var stack:List.<Vector2> = new List.<Vector2>();
	var x:int;
	var y:int;
	
	var counter:uint = 1;
	
	//Starting point
	stack.Add(new Vector2(0,0));
	
	while(stack.Count != 0){
	
		var point:Vector2 = stack[0];
	
		y = point[1];
		
		//If line is going right
		if(point[0]-1<0 || City[point[0]-1,y]==1){
			print("Going right ->");
						
			for(x=point[0]; x<City.GetLength(0);x++){
				
				if(City[x,y]==10){
					break;
				} else if (City[x,y]==1 || x == City.GetLength(0)-1){
				
					if(x == City.GetLength(0)-1){
						City[x,y] = 10;
					}
				
					//Check up
					for(var x1:int = x; x1>-1;x1--){
						var y1:int = parseInt(Mathf.Clamp(y+1,0,City.GetLength(1)-1));
						
						if(City[x1,y1]==10){
							break;
						} else if(City[x1,y1]==0){
							stack.Add(new Vector2(x1,y1));
							print(point+" placed "+x1+" "+y1+" going right and up.");
							break;
						}
						print("Checking "+x1+" "+y1);
					}
					print("Done checking up.");
					
					//Check down
					for(x1 = x; x1>-1;x1--){
						y1 = parseInt(Mathf.Clamp(y-1,0,City.GetLength(1)-1));
						
						if(City[x1,y1]==10){
							
							break;
						} else if(City[x1,y1]==0){
							stack.Add(new Vector2(x1,y1));
							print(point+" placed "+x1+" "+y1+" going right and down.");
							break;
						}
					}
					print("Done checking down.");
					break;
				
				} else {
					City[x,y] = 10;
				}
				
			}
		}
		
		//If line is going left
		if(point[0]+1>City.GetLength(0)-1 || City[point[0]+1,y]==1){
			print("Going left <-");
			
			for(x=point[0]; x>-1;x--){
				
				if(City[x,y]==10){
					break;
				} else if (City[x,y]==1 || x == 0){
				
					if(x == 0){
						City[x,y] = 10;
					}
				
					//Check up
					for(x1 = x1; x<City.GetLength(0);x1++){
						y1 = parseInt(Mathf.Clamp(y+1,0,City.GetLength(1)-1));
						
						if(City[x1,y1]==10){
							break;
						} else if(City[x1,y1]==0){
							stack.Add(new Vector2(x1,y1));
							print(point+" placed "+x1+" "+y1+" going left and up.");
							break;
						}
					}
					print("Done checking up.");
					
					//Check down
					for(x1 = x; x1<City.GetLength(0);x1++){
						y1 = parseInt(Mathf.Clamp(y-1,0,City.GetLength(1)-1));
						
						if(City[x1,y1]==10){
							break;
						} else if(City[x1,y1]==0){
							stack.Add(new Vector2(x1,y1));
							print(point+" placed "+x1+" "+y1+" going left and down.");
							break;
						}
					}
					print("Done checking down.");
					break;
				
				} else {
					City[x,y] = 10;
				}
				
			}
		}
		
		print("Just did: "+point);
		
		if(counter%2000==0){
			print("Stopped");
			print(stack.Count+" left.");			
			return;
		}
		
		stack.RemoveAt(0);
		counter++;
	}
	
}

Excuse the mass amount of print() lines, I’m trying to find all the problems and it’s easier this way.

Currently my problem is that the fill is stopping prematurely as it fails to find any more lines to fill.

Again, any other approaches are welcomed!

I think you’re better off keeping things simple and not making special cases for going left or right (alternatively, up or and). Check out the last algorithm here. The first thing it does when filling a line is skip straight to the top and then works downwards.

Jasper! Words can’t describe how happy I am right now. I can’t say I fully understand his method, but literally minutes after rewriting it I got it to work exactly like it should. And it is is extremely fast!

Thank you :slight_smile:

:slight_smile: Glad it works for you man!