I'm wanting to use Floodfill to uncover neighbouring cells in a Minesweeper game. I'm new to Floodfill and perhaps I'm misunderstanding it. It never stops when it reaches a cell that isn't surrounded by a mine.
Here is the code for the uncovering method:
public static void uncoverSurroundings(int x, int y, JButton[][] buttons)
{
queue.add(new Point(x,y));
int currentPnt = queue.size() - 1;
Point p = queue.get(currentPnt);
try
{
if (mineLayout[x][y+1].equals("Mine"))
queue.remove(p);
else if (mineLayout[x][y-1].equals("Mine"))
queue.remove(p);
else if (mineLayout[x+1][y+1].equals("Mine"))
queue.remove(p);
else if (mineLayout[x-1][y-1].equals("Mine"))
queue.remove(p);
else if (mineLayout[x-1][y].equals("Mine"))
queue.remove(p);
else if (mineLayout[x+1][y].equals("Mine"))
queue.remove(p);
else if (mineLayout[x-1][y+1].equals("Mine"))
queue.remove(p);
else if (mineLayout[x+1][y-1].equals("Mine"))
queue.remove(p);
}
catch (NullPointerException|ArrayIndexOutOfBoundsException e)
{
}
try
{
if (currentPnt + 1 == queue.size())
{
Point r = queue.get(currentPnt);
queue.remove(currentPnt);
buttons[r.x][r.y].setEnabled(false);
queue.add(new Point (x, y+1));
queue.add(new Point (x, y-1));
queue.add(new Point (x+1, y+1));
queue.add(new Point (x-1, y-1));
queue.add(new Point (x-1, y));
queue.add(new Point (x+1, y));
queue.add(new Point (x-1, y+1));
queue.add(new Point (x+1, y-1));
}
}
catch (NullPointerException|ArrayIndexOutOfBoundsException e)
{
}
if (!queue.isEmpty())
index = queue.size() - 1;
Point nextPnt = queue.get(index);
uncoverSurroundings(nextPnt.x, nextPnt.y, buttons);
}
}
There are a number of problems with your code that I can see.
Firstly, at the bottom of your code, you fetch the last point in the queue and recursively call your
uncoverSurroundingsmethod with this last point in the queue. This adds the point to the queue. If the point then gets removed from the queue using one of yourqueue.remove(p)calls, you then reach the bottom ofuncoverSurroundingswithout having changed the size of the queue. You then calluncoverSurroundingsagain with the same point and the same-size queue, which ends up callinguncoverSurroundingsagain with the same point and the same-size queue, which ends up callinguncoverSurroundingsagain with the same point and the same-size queue ....You need to remove the point from the queue at the end of
uncoverSurroundings.The second problem you have is that you appear to have no way of recording whether a square has been uncovered. Clearly, if you've uncovered a square, there's no point in trying to uncover it again. You need to keep track of what squares have been uncovered, and if
uncoverSurroundingsis called on a square that has already been uncovered, it should do nothing.After fixing these two problems, your code will no longer cause a stack overflow, but it still won't do what you want it to. In fact, it is possible for your
uncoverSurroundingsmethod to call itself on a square that contains a mine. The reason why it does this is due to the following block of code:If, say, square (
x,y-1) is off the grid (due toybeing zero, for instance), but square (x-1,y+1) contains a mine, then your pointpwill not get removed from the queue becausemineLayout[x][y-1]will cause anArrayIndexOutOfBoundsExceptionto be thrown and the remaining checks onmineLayoutwill be skipped.It's bad practice to catch exceptions such as
NullPointerExceptionorArrayIndexOutOfBoundsException. If one of these exceptions is thrown, that is normally because you have a bug in your code. Expecting such exceptions to be thrown and catching them when they are thrown is sloppy coding. However, to be fair to you, I suspect you were trying to avoid having to check your coordinate values were in-range for each of your eightmineLayoutcalls. It would be far better in this situation to have a method for checking whether a given square contains a mine, and you can put the logic for checking whether thexandyvalues are on the grid in there. For example, this method could look something like the following:(I'm assuming
widthandheightcontain the width and height of the grid here.)That way you can replace all of your
mineLayoutchecks with the following:You might also want to do something similar with the eight calls to
queue.add(new Point(...));. You could write a method that checks to see if thexandyvalues are on the grid before adding the point to the queue. You could also check whether the point you wish to add to the queue is already in the queue, and only add it if it isn't. I'll leave that as an exercise for you.