Reputation: 707
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.
Upvotes: 1
Views: 154
Reputation: 1215
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)
Upvotes: 3
Reputation: 4429
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"
.
Upvotes: 0
Reputation: 446
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)
}
Upvotes: 0
Reputation: 7278
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.
Upvotes: 0