使用ArrayList的Floodfill不起作用

时间:2013-09-07 09:29:36

标签: java arraylist flood-fill minesweeper

我想在扫雷游戏中使用Floodfill来发现相邻的细胞。我是Floodfill的新手,也许我误解了它。当它到达一个没有被矿井包围的牢房时,它永远不会停止。

以下是揭露方法的代码:

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);
    }
}

1 个答案:

答案 0 :(得分:0)

我可以看到您的代码存在许多问题。

首先,在代码的底部,您获取队列中的最后一个点,并使用队列中的最后一个点递归调用uncoverSurroundings方法。这会将该点添加到队列中。如果使用您的queue.remove(p)个调用之一将该点从队列中删除,则可以在不更改队列大小的情况下到达uncoverSurroundings的底部。然后,您使用相同的点和相同大小的队列再次呼叫uncoverSurroundings,最终再次使用相同的点和相同大小的队列调用uncoverSurroundings,最终调用uncoverSurroundings再次使用相同的点和相同大小的队列......

您需要从uncoverSurroundings末尾的队列中删除该点。

您遇到的第二个问题是您似乎无法记录是否已发现方块。显然,如果你发现了一个正方形,试图再次揭开它是没有意义的。您需要跟踪已发现的方块,如果在已经被发现的方块上调用uncoverSurroundings,它将不执行任何操作。

修复这两个问题之后,你的代码将不再导致堆栈溢出,但它仍然无法完成你想要的操作。实际上,您的uncoverSurroundings方法可以在包含地雷的广场上调用自己。它之所以这样做是因为下面的代码块:

    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)
    {
    }

例如,如果方形(xy-1)不在网格中(例如,由于y为零),而是方形(x-1,{ {1}})包含一个我的,然后您的点y+1将不会从队列中删除,因为p将导致mineLayout[x][y-1]被抛出,而ArrayIndexOutOfBoundsException上的剩余检查将被跳过。

捕获mineLayoutNullPointerException等异常是不好的做法。如果抛出其中一个异常,通常是因为您的代码中存在错误。期望抛出这些异常并在抛出它们时捕获它们是邋coding的编码。但是,为了公平对待您,我怀疑您试图避免检查您的八个ArrayIndexOutOfBoundsException来电中的每一个的坐标值是否在范围内。在这种情况下,有一个方法可以检查给定方块是否包含一个矿井,并且你可以设置逻辑以检查mineLayoutx值是否在那里的网格上。例如,此方法可能如下所示:

y

(我假设 private static boolean isMineAt(int x, int y) { return 0 <= x && x < width && 0 <= y && y < height && mineLayout[x][y].equals("Mine"); } width包含网格的宽度和高度。)

这样您可以使用以下内容替换所有height支票:

mineLayout

您可能还希望对 if (isMineAt(x, y+1)) queue.remove(p); else if (isMineAt(x, y-1)) queue.remove(p); // and so on... 的八次调用执行类似操作。您可以编写一个方法,在将点添加到队列之前检查网格上是否有queue.add(new Point(...));x值。您还可以检查要添加到队列中的点是否已经在队列中,如果不是,则仅添加它。我会把它作为锻炼给你。