简体   繁体   中英

recursive stackoverflow minesweeper c#

I am writing a game of minesweeper. Below is code for 3 methods in minesweeper. The first method is to check all the spaces around the button pressed and to count how many bombs are around it. The next method is to be called recursively, in order that if the user pressed a button with 0 buttons around it, it will open all of the squares that also indicate 0 squares around it. The third method is to check that it will be in bound the check. The empty space recursive call is getting me a stackoverflow error, what am I doing wrong?

Thanks!

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

For k = 0 and l = 0, you are calling yourself again and again and again...


Thanks to @BenVoigt for pointing out that two zeroes adjacent to each other will also lead to infinite recursion. So, in order to solve that one method is to create a boolean grid too and set a particular cell's value to true if it has been run through once. Assuming the grid is called Explored , I've added the condition for it in the code below.


If you insist on your current code, try changing the condition to:

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

Here is another answer for you, rewriting your methods one-by-one following better coding practices. Like in the other answer, a boolean grid called Explored[SizeX, SizeY] has been assumed.


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

What's better? Quicker returning from the method for special case. Reduced nesting in If(...) blocks.


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

What's better? Properly named indexing variables in both loops. Properly written condition ( += 2 instead of ++ ). Reduced nesting in If(...) . Easier to read method call in the If(...) instead of three predicates. Useful temporary variables added which make it clear what x + k and y + l were in the code written earlier.


3. CheckBounds() is written fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM