1

I'm creating a minesweeper game and by wishing to reveal buttons around blank button, I've got into a problem. I have the following function:

function l_click(event, coordinate_i = event.target.i, coordinate_j = event.target.j)
{
    if(block[coordinate_i][coordinate_j].isBomb === true)
    {
        // lots of irrelevant cocde
    }
    else {
        block[coordinate_i][coordinate_j].src = "blank.png";
        for (var i = coordinate_i - 1; i < coordinate_i + 2; i++) {
            for (var j = coordinate_j - 1; j < coordinate_j + 2; j++) {
                if (coordinate_i < 9 && coordinate_j < 9 && !(block[i][j].isBomb) && !(coordinate_i === i && coordinate_j === j) && block[i][j].src ==="empty-block.png") {
                    if (block[i][j].nearBombsNum === 0) {
                        l_click(event, i, j)
                    }
                    else {
                        block[i][j].src = block[i][j].nearBombsNum + ".png";
                    }
                }
            }
        }
    }
}

What I try to do here is to turn images to blank by the buttons of the board. The result I wish for is a recursion in which function is being called 8 times from father function's nested loop (a call for each button around the original button, that will work the same as the original and call the buttons around itself). The result I get is that the first call stop or continues the recursion, but after the first call produced, the loop won't keep going.

I want the father function call to continue the loop run, and to keep on calling for itself by continuing the loop's iteration.

The current situation is that once the button "falls" into the first 'if' statement, the loop from the father function doesn't continue.

4
  • I think your recursion will have maximum call stack error, you need to check if block[i][j] has already marked with 'black.png' instead of checking (coordinate_i === i && coordinate_j === j) != true. Or you can use another 2d array to check which cell has already been visited. And you don't need to pass event to your function, coordinates are enough and you don't need to set default value for your coordinates. Commented Apr 26, 2020 at 23:40
  • Does (coordinate_i === i && coordinate_j === j) != true need parenthesis around it? Commented Apr 26, 2020 at 23:40
  • Right now each stack checks all neighbor cells even they are visited already. Commented Apr 26, 2020 at 23:47
  • @AnthonyMcGrath That's meaningless here. This statement appears only because I don't want to send a call once more for the block[i][j] button itself. Commented Apr 26, 2020 at 23:48

4 Answers 4

3

You don't really need to pass event in your recursive function and you don't need to set default parameter value for your function. Use your event handler and pass the event.target values to l_click function

Instead of a nested loop, you can create a direction array dirs and you can use it to iterate 8 neighbors in 8 direction in one loop.

Check neighbor coordinates to see if it is within boundaries. In your code, you don't check boundaries. Assume you start from coordinates[1,1], each time you call your function, your i starting from coordinate_i - 1, coordinate_j -1, after 1 call stack the coordinates goes to [0,0] if the cell is empty, the function gets called again, and then it starts from [-1,-1], which will breaks your code, because block[-1] is undefined.

For the demo, it won't check nearBombsNum, it will keep checking empty cells and mark them as visited cells.

const dirs = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]

function l_click(coordinate_i, coordinate_j)
{
    if(block[coordinate_i][coordinate_j].isBomb)
    {
        // lots of irrelevant cocde
    }
    else {
        block[coordinate_i][coordinate_j].src = "blank.png";
        //iterate 8 neibors
        for(const [x,y] of dirs){
          //i1,j1 are neibor coordinates
          const i1 = coordinate_i + x, j1 = coordinate_j + y;
          
          //check i1,j1 boundary, proceeds only if cell is not a bomb and empty
          if(i1>=0&&i1<block.length&&j1>=0&&j1<block[i1].length&&!block[i1][j1].isBomb&&block[i1][j1].src === 'empty-block.png'){
            if(block[i1][j1].nearBombsNum === 0)
              l_click(i1, j1)
            else
              block[i1][j1].src = block[i1][j1].nearBombsNum + ".png";
          }
        }
    }
}

//1 is bomb, 2 is visited or clicked cell, 0 is empty
function l_clickDemo(coordinate_i, coordinate_j)
{
    if(demo[coordinate_i][coordinate_j] === 1)
    {
        // lots of irrelevant cocde
    }
    else {
        demo[coordinate_i][coordinate_j] = 2;
        //iterate 8 neibors
        for(const [x,y] of dirs){
          //i1,j1 are neibor coordinates
          const i1 = coordinate_i + x, j1 = coordinate_j + y;
          
          //check i1,j1 boundary, proceeds only if cell is not a bomb and empty
          if(i1>=0&&i1<demo.length&&j1>=0&&j1<demo[i1].length&&demo[i1][j1]!==1&&demo[i1][j1] === 0){
              l_clickDemo(i1, j1)
          }
        }
    }
}

const demo = [[0,1,0,0,0],[0,0,0,1,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,1]]


l_clickDemo(0,0)

console.log(demo)

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, it worked. But have you understood why the nested loop recursion didn't work? Why did it call itself once and when stuck it has stopped?
depends on which coordinates you clicked, if you didn't check boundaries, I think maybe somewhere it goes out of bound and has something undefined which breaks your code.
0

Imagine a minesweeper board with just two cells on it, where neither is a mine. Assuming you have code to handle going off the edges (which I don't see here), this code would recurse. Clicking one cell would call l_click on the other. Which would call l_click on the first, etc.

You're not excluding cells that have already been examined in your recursive process. You'll need to find some way to do that.

1 Comment

I removed from the question the going off the edges handle part of the code. It seemed irrelevant to the current issue. I took your advice and added a statement that the called cell has not been clicked. That is still doesn't fix my issue, whereas the father's loop doesn't call for other children except the first.
0

Try replacing:

if (block[i][j].isBomb === false && (coordinate_i === i && coordinate_j === j) != true) {
    l_click(event, i, j)
}

With:

if (!block[i][j].isBomb && !(coordinate_i === i && coordinate_j === j) && block[i][j].src !== "blank.png") {
    l_click(event, i, j)
}

1 Comment

Check up the edit. That's a good syntax comment, but it doesn't answer my question.
0

If you only want this to be executed 8 times, you shouldn't make it recursive. For each neighbouring button, it's going to do exactly the same as it did for the original button. So you click a button, and it's going to click all the buttons around it. And for each those, if they're not a bomb, it's going to click all the buttons around them, including the original one. So there's a risk of infinite recursion here.

Also, it's going to recurse depth-first. So after processing the button you clicked, this is going to click the button to the top-left of that, the button top-left of that one, top-left of that one, etc, all the way until you encounter a bomb or you run into one that's undefined in your block.

Is that your intention? If not, maybe recursion is not what you're looking for here. If it is, please check first whether block[i][j] exists, and whether block[i][j].src is already "blank.png".

2 Comments

I don't want it to get executed only 8 times, I want the father function to call the buttons around it 8 times, and for each button, it will happen the same until no more 0 near bombs linked buttons will be covered. Check up the edit because I've changed my code by your suggestion. My issue is as you described with the top-left call, that doesn't keep on from the father function to the other buttons.
That could be because your depth-first search runs outside your boundaries and breaks the loop. If you don't see the exception, perhaps you're catching all exceptions at a higher level while you were originally expecting only a different type of exception there. You might want to make sure you log your exceptions there.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.