递归stackoverflow扫雷c#

时间:2015-12-18 19:31:46

标签: c# recursion stack-overflow minesweeper

我正在写一个扫雷游戏。以下是扫雷中3种方法的代码。第一种方法是检查按下的按钮周围的所有空间,并计算它周围有多少炸弹。下一个方法是递归调用,以便如果用户按下一个带有0个按钮的按钮,它将打开所有的方块,这些方块也指示它周围的0个方块。第三种方法是检查它是否会受到检查的约束。空的空间递归调用给我一个stackoverflow错误,我做错了什么?

谢谢!

   private int GameLogicChecker(int x, int y)
    {
        int count = 0;
        if (_grid[x, y] != -1)
        {
            if (x + 1 < SizeX)
            {   //Right
                if (_grid[x + 1, y] == -1)
                    count++;
            }
            if (x - 1 > 0)
            {   //Left
                if (_grid[x - 1, y] == -1)
                    count++;
            }
            if (y + 1 < SizeY)
            {   //Upper
                if (_grid[x, y + 1] == -1)
                    count++;
            }
            if (y - 1 > 0)
            {   //Lower
                if (_grid[x, y - 1] == -1)
                    count++;
            }
            if (x + 1 < SizeX && y + 1 < SizeY)
            {   //Right-Upper
                if (_grid[x + 1, y + 1] == -1)
                    count++;
            }
            if (x + 1 < SizeX && y - 1 > 0)
            {   //Right-Lower
                if (_grid[x + 1, y - 1] == -1)
                    count++;
            }
            if (x - 1 > 0 && y + 1 < SizeY)
            {   //Left-Upper
                if (_grid[x - 1, y + 1] == -1)
                    count++;
            }
            if (x - 1 > 0 && y - 1 > 0)
            {   //Left-Lower
                if (_grid[x - 1, y - 1] == -1)
                    count++;
            }
        }
        return count;
    }

    void OpenEmptySpace(int x, int y)
    {
        for (var k = -1; k <= 1; k++)
        {
            for (var l = -1; l <= 1; l++)
            {
                if (CheckBounds(x + k, y + l) && GameLogicChecker(x + k, y + l) == 0)
                {
                    _buttons[x + k, y + l].Text = "0";
                    OpenEmptySpace(x + k, y + l);
                }
            }
        }
    }

    private bool CheckBounds(int x, int y)
    {
        return x >= 0 && x < SizeX && y >= 0 && y < SizeY;
    }

2 个答案:

答案 0 :(得分:3)

对于k = 0和l = 0,你一次又一次地给自己打电话......

感谢@BenVoigt指出彼此相邻的两个零也会导致无限递归。因此,为了解决这个问题,一种方法是创建一个布尔网格,如果已经运行了一次,则将特定单元格的值设置为true。假设网格被称为Explored,我在下面的代码中添加了它的条件。

如果您坚持使用当前代码,请尝试将条件更改为:

if (CheckBounds(x + k, y + l) 
    && GameLogicChecker(x + k, y + l) == 0 
    && !(k == 0 && l == 0)
    && !Explored[x + k, y + l])
{
    Explored[x + k, y + l] = true;
    _buttons[x + k, y + l].Text = "0";
    OpenEmptySpace(x + k, y + l);
}

答案 1 :(得分:1)

这是另一个答案,在更好的编码实践后逐个重写您的方法。与其他答案一样,假定了一个名为Explored[SizeX, SizeY]的布尔网格。

<强> 1。 GameLogicChecker()

private int GameLogicChecker(int x, int y)
{
    if (_grid[x, y] == -1) return 0;
    int count = 0;
    if (x + 1 < SizeX && _grid[x + 1, y] == -1) //Right
    {
        count++;
    }
    if (x - 1 > 0 && _grid[x - 1, y] == -1) //Left
    {
        count++;
    }
    if (y + 1 < SizeY && _grid[x, y + 1] == -1) //Upper
    {
        count++;
    }
    if (y - 1 > 0 && _grid[x, y - 1] == -1) //Lower
    {
        count++;
    }
    if (x + 1 < SizeX && y + 1 < SizeY && _grid[x + 1, y + 1] == -1) //Right-Upper
    {
        count++;
    }
    if (x + 1 < SizeX && y - 1 > 0 && _grid[x + 1, y - 1] == -1) //Right-Lower
    {
        count++;
    }
    if (x - 1 > 0 && y + 1 < SizeY && _grid[x - 1, y + 1] == -1) //Left-Upper
    {
        count++;
    }
    if (x - 1 > 0 && y - 1 > 0 && _grid[x - 1, y - 1] == -1) //Left-Lower
    {
        count++;
    }
    return count;
}

更好的是什么?从特殊情况的方法更快地返回。减少 If(...)块中的嵌套。

<强> 2。 OpenEmptySpace()

public/private void OpenEmptySpace(int x, int y)
{
    for (var deltaX = -1; deltaX <= 1; deltaX += 2)
    {
        for (var deltaY = -1; deltaY <= 1; deltaY += 2)
        {
            var thisX = x + deltaX;
            var thisY = y + deltaY;
            if (OpeningNotNeeded(thisX, thisY)) 
            {
                continue;
            }
            Explored[thisX, thisY] = true;
            _buttons[thisX, thisY].Text = "0";
            OpenEmptySpace(thisX, thisY);
        }
    }
}

private bool OpeningNotNeeded(int x, int y)
{
    return !CheckBounds(x, y)
           || GameLogicChecker(x, y) != 0 
           || Explored[x, y];
}

更好的是什么?在两个循环中正确命名索引变量。正确写入条件(+= 2而不是++)。减少 If(...)中的嵌套。更容易在 If(...)而不是三个谓词中读取方法调用。添加了有用的临时变量,清楚地说明了前面编写的代码中x + ky + l的内容。

第3。 CheckBounds()写得很好。