Recursive function to check 2d Array

偶尔善良 提交于 2020-01-24 20:04:59

问题


I am creating a minesweeper game for a javascript project and have run into a problem that I can't get my head round. When you click on an empty cell (one which does not have any mines around it and so does not display a number) in the minesweeper game for those who don't know, this will reveal the whole block of empty cells that are neighbouring eachother, stopping when the "wall of numbers" containing these empty blocks is found. Example below:

[1]http://datagenetics.com/blog/june12012/hole.png

This requires a recursive function to figure out which blocks are to be revealed. My code at the moment only reveals the block that is clicked on:

 function revealGridContents()
    {
    switch (positionClickContents)
    {
    case 0:
            ctx.drawImage(clickedImage, (xClick*20), (yClick*20));
            break;
    case 1:
            ctx.drawImage(num1Image, (xClick*20), (yClick*20));
            break;
    case 2:
            ctx.drawImage(num2Image, (xClick*20), (yClick*20));
            break;
    case 3:
            ctx.drawImage(num3Image, (xClick*20), (yClick*20));
            break;
    case 4:
            ctx.drawImage(num4Image, (xClick*20), (yClick*20));
            break;
    case 5:
            ctx.drawImage(num5Image, (xClick*20), (yClick*20));
            break;
    case 6:
            ctx.drawImage(num6Image, (xClick*20), (yClick*20));
            break;
    case 7:
            ctx.drawImage(num7Image, (xClick*20), (yClick*20));
            break;
    case 8:
            ctx.drawImage(num8Image, (xClick*20), (yClick*20));
            break;
    };
    };

The number passed into the switch statement is the value of the data in the array grid[xClick][yClick]; eg a 4 symbolises a block with 4 mines around it, so the image for 4 will be displayed.

Case 0 is the case that a blank block is clicked and so the code for this needs modifying but I really can't think what to do.

From what I can understand, I will need to call the revealGridContents(); function from case 0, but passing in new values for xClick and yClick (the x and y values of the array position) for each square that I want to check.

Any help shedding the light on what I need to do next would be greatly appreciated!


回答1:


Without knowing slightly more of your program it's hard to give you an exact solution. You'll probably need a separate function to do this, as just using the same function will reveal everything (which is obviously not how the game works). You'll also need some way of keeping track of revealed cells, otherwise you'll get into a loop (I'm assuming this is stored in another 2d array revealed[x][y]).

You probably want to do something like this (I haven't tested this so there may be errors in it - apologies):

function revealGridContents(){
    switch (positionClickContents){
        case 0:
            ctx.drawImage(clickedImage, (xClick*20), (yClick*20));
            checkAdjacentCells(xClick, yClick);
            break;
        ...
    }
}

function checkAdjacentCells(x,y){
    var cellsToCheck = [ 
        [x,y+1],
        [x,y-1],
        [x+1,y],
        [x-1,y]];
    var x,y;
    for(var i=0; i<=cellsToCheck.length; i++){
        x = cellsToCheck[i][0];
        y = cellsToCheck[i][1];
        if(!revealed[x][y] && grid[x][y] == 0){
             ctx.drawImage(clickedImage, x*20, y*20);
             checkAdjacentCells(x,y);
        }    
    }
}



回答2:


Just as a general advice, you need a better separation between the model of your game and the UI.

Here is the begining of my interpretation of the minesweeper game:

function init() {
  var i,j; // indexes  
  map = []; // global map, because i'm lazy

  for (i=0; i<10; i++) {
    var row = [];
    for (j=0; j<10; j++)
      row.push({
        bomb : Math.round(Math.random()-0.4), // set bombs randomly, change to your correct ratio
        revealed : false, // nothing is visible at start
        count : 0 // counts will be computed after all the map is created
      });
    map.push(row);
  }

  // set adjacent bomb counts
  for (i=0; i<10; i++) 
    for (j=0; j<10; j++) {
      if (map[i-1] && map[i-1][j-1] && map[i-1][j-1].bomb) map[i][j].count++;
      if (map[i-1] && map[i-1][j] && map[i-1][j].bomb) map[i][j].count++;
      if (map[i-1] && map[i-1][j+1] && map[i-1][j+1].bomb) map[i][j].count++;
      if (map[i] && map[i][j-1] && map[i][j-1].bomb) map[i][j].count++;
      if (map[i] && map[i][j+1] && map[i][j+1].bomb) map[i][j].count++;
      if (map[i+1] && map[i+1][j-1] && map[i+1][j-1].bomb) map[i][j].count++;
      if (map[i+1] && map[i+1][j] && map[i+1][j].bomb) map[i][j].count++;
      if (map[i+1] && map[i+1][j+1] && map[i+1][j+1].bomb) map[i][j].count++;
  }

}

function print() { // uses console to display instead of canvas
  var output = '\n';
  for (var i=0; i<10; i++) {
    for (var j=0; j<10; j++) {
      var item = map[i][j];
      output += (item.revealed ? item.count : 'x') + ' ';
    }
    output += '\n';
  }
  console.log(output);
}

function click(x,y) {
  reveal(x,y);  
  print(map);  
}

function reveal(x,y) {
  // break early if click is invalid (invalid clicks are generated)
  if (x < 0 || x > 9 || y < 0 || y > 9 || map[x][y].revealed) return;

  // mark the square as clicked
  map[x][y].revealed = true;

  if (map[x][y].bomb) { // losing click
    console.log('You lost');    
  } else if (map[x][y].count === 0) { // click on 0 adjacent bombs
      reveal(x-1, y);
      reveal(x, y-1);
      reveal(x, y+1);
      reveal(x+1, y);   
  }
}   


init();
console.log('First print');
print();
console.log('Click 1,3');
click(1,3);

The difficult part is in the click() function.

Try this demo (click 'run with JS' several times until you don't lose and hit a 0): http://jsbin.com/iqeganU/1/edit



来源:https://stackoverflow.com/questions/19686176/recursive-function-to-check-2d-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!