Outer grid in Mine Sweeper game bugged condition

76 Views Asked by At

I'm trying to replicate in Js the old Mine Sweeper game. But I'm stuck declaring conditions to the blue grid (that is distant 2 numbers from the bomb at the center of it); I have 2 bugged cells appearing on the other side when a bomb is on the grid left/right border.

(In the conditions you can see comments with numbers referring to 50 bomb position to help locate better which condition does what, hope it helps)

Thanks a lot for help me, I'm a student :)

let   gridLength = Math.sqrt(numbOfCells);
const cellNumb   = Number(singleCell.textContent);

const atRightSide = cellNumb % gridLength === 0;
const atLeftSide  = (cellNumb - 1) % gridLength === 0;

const twoRightSide = cellNumb % gridLength === 0 
                   || (cellNumb + 1) % gridLength === 0;

//check 9+10 nums and 10 multiplies
const twoLeftSide = (cellNumb - 1) % gridLength === 0 
                  || (cellNumb) % gridLength === 2;

// check 1+10 nums and 2+10 nums

if (bombsArray.includes(cellNumb)) {
    singleCell.classList.add('bomb')

   //  this create green cells
} else if ( !atLeftSide && bombsArray.includes(cellNumb - 1)
         || !atRightSide && bombsArray.includes(cellNumb + 1)
         || bombsArray.includes(cellNumb - gridLength)
         || bombsArray.includes(cellNumb + gridLength)
         || !atLeftSide && bombsArray.includes(cellNumb - gridLength - 1)
         || !atRightSide && bombsArray.includes(cellNumb - gridLength + 1)
         || !atLeftSide && bombsArray.includes(cellNumb + gridLength - 1)
         || !atRightSide && bombsArray.includes(cellNumb + gridLength + 1)
        ) {

    singleCell.classList.add('green');
    singleCell.addEventListener('click', function () {
         addGreenPoints()
    })

    //  this create blue cells (example 55)

        } else if (
            !twoLeftSide && bombsArray.includes(cellNumb - 2)
            // 53
            || !twoRightSide && bombsArray.includes(cellNumb + 2)
            // 57
            //left and right blue cell

            || bombsArray.includes(cellNumb - (gridLength * 2))
            || bombsArray.includes(cellNumb + (gridLength * 2))
            // these are the top/bottom blue cells

            || !twoLeftSide && bombsArray.includes(cellNumb - (gridLength * 2) - 2)
            // ↖↖  (33)

            // ----------- I think these are the bugged ones
            || bombsArray.includes(cellNumb - (gridLength * 2) - 1)
            //  34
            || bombsArray.includes(cellNumb - (gridLength * 2) + 1)
            // ↗ 36
            || bombsArray.includes(cellNumb + (gridLength * 2) + 1)
            // ➡  76
            || bombsArray.includes(cellNumb + (gridLength * 2) - 1)
            // ⬅ 74 
            // -----------

            || !twoRightSide && bombsArray.includes(cellNumb - (gridLength * 2) + 2)
            // ↗↗ 37
            || !twoRightSide && bombsArray.includes(cellNumb - gridLength + 2)
            // ➡ 47
            || !twoRightSide && bombsArray.includes(cellNumb + gridLength + 2)
            // ↘ 67
            || !twoRightSide && bombsArray.includes(cellNumb + (gridLength * 2) + 2)
            // ↘↘ 77
            || !twoLeftSide && bombsArray.includes(cellNumb + (gridLength * 2) - 2)
            // ↙↙ 73
            || !twoLeftSide && bombsArray.includes(cellNumb + gridLength - 2)
            // ⬅  63
            || !twoLeftSide && bombsArray.includes(cellNumb - gridLength - 2)
            // ⬅ 43

        ) {

            singleCell.classList.add('blue');
            singleCell.addEventListener('click', function () {
                addBluePoints()
            })

        }

I think I have these conditions that are useful when generating normal numbs cells, but at borders they create the bugged cells. I tried adding my condition !twoRightSide/!twoLeftSide at these, but I got removed also good cells, as you can see here: .

  || bombsArray.includes(cellNumb - (gridLength * 2) - 1)
  || bombsArray.includes(cellNumb - (gridLength * 2) + 1)
  || bombsArray.includes(cellNumb + (gridLength * 2) + 1)
  || bombsArray.includes(cellNumb + (gridLength * 2) - 1)        
2

There are 2 best solutions below

0
Kokodoko On

It seems you are creating a lot of complexity by trying to define and compare each cell individually. I would recommend using a two-dimensional array to represent the grid. Then you can use for loops to loop through the rows and columns. In this example I create a 5x5 grid. Each cell has a value of 0.

let grid = [
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
]

You can set one cell directly using

grid[2,2] = 1    // third row, third column is now 1

If you want to also set the surrounding cells to 1 you can create a for loop that loops through the rows and columns. You can use a clamp function to prevent selecting cells that are outside the grid.

For example:

function showCells(x, y) {
  // start to the left and end to the right of the selected cell
  let startrow = y - 1
  let endrow = y + 1
  let startcol = x - 1
  let endcol = x + 1

  // make sure the position cant be smaller than 0 or bigger than the grid
  startrow = clamp(startrow, 0, grid.length - 1)
  endrow = clamp(endrow, 0, grid.length - 1)
  startcol = clamp(startcol, 0, grid[0].length - 1)
  endcol = clamp(endcol, 0, grid[0].length - 1)

  // set the position and everything around it to 1
  for (let row = startrow; row <= endrow; row++) {
    for (let col = startcol; col <= endcol; col++) {
      grid[row][col] = 1
    }
  }
}

function clamp(num, min, max) {
  return Math.min(Math.max(num, min), max);
}

showCells(2, 2)
console.log(grid)
0
Mister Jojo On

the idea of colors is interesting, but your entire algorithmic approach needs to be reviewed.

I also use the marking of lines in single values as you did to indicate the mine "50", but your first mistake is to start your numbering from the value 1. You must start from the value 0.

So you can easily know the coordinates (x,y)
In the case of mine "50" it is actually in position 49
and the calculation of coordinates becomes:

const
  grid_columns = 10  // horizontals positions count
, grid_rows    = 10  // verticals  positions count
  ;
function getMinePosition( mine_position )
  {
  let
    x = mine_position % grid_columns        // horizontal  position 
  , y = (mine_position - x) / grid_columns  // vertical  position
    ;
  return ({x,y})
  }
function getMineAbsolutePosition ({x,y})
  {
  return x + (y * grid_colluns)
  }

console.log( getMinePosition(49) ),                 // -> {x:9,y:4}
console.log( getMineAbsolutePosition({x:9,y:4}) ),  // -> 49

to check the presence of a mine near a square, you must 1 check the 8 surrounding squares,
whose coordinates are:

const proxi1 =
  [ {h:-1,v:-1}, {h: 0,v:-1}, {h:+1,v:-1}, {h:-1,v: 0}
  , {h:+1,v: 0}, {h:-1,v:+1}, {h: 0,v:+1}, {h:+1,v:+1} ] 

for example {h:0,v:-1} gives the position above a box and {h:-1,v:-1} that below on the left.

if you use {h:+1,v:0} on the coordinates {x,y} returned by getMinePosition(19) --> {x:9,y:4} + {h:+1,v:0} = {x:10,y:4} does not exist because x:10 is >= grid_colluns

Which leads you to this kind of solution:

const
  minesArea = document.querySelector('table')
, gridSize  = { Rows:10, Cols:10 }
, getXY = pos =>
  {
  let
    x = pos % gridSize.Cols       // horizontal  position 
  , y = (pos - x) / gridSize.Cols // vertical  position
    ;
  return ({x,y})
  }
, proxi1_green =
  [ {h:-1,v:-1}, {h: 0,v:-1}, {h:+1,v:-1}, {h:-1,v: 0}
  , {h:+1,v: 0}, {h:-1,v:+1}, {h: 0,v:+1}, {h:+1,v:+1} ] 
, proxi2_blue =
  [ {h:-2,v:-2}, {h:-1,v:-2}, {h: 0,v:-2}, {h:+1,v:-2}, {h:+2,v:-2} 
  , {h:-2,v:-1}, {h:-2,v: 0}, {h:-2,v:+1}
  , {h:+2,v:-1}, {h:+2,v: 0}, {h:+2,v:+1}
  , {h:-2,v:+2}, {h:-1,v:+2}, {h: 0,v:+2}, {h:+1,v:+2}, {h:+2,v:+2}  ]
  ;
draw_Grid();
setColors( 49 );

function draw_Grid()
  {
  let rx;
  for(let r = gridSize.Rows; r--;)
    {
    rx = minesArea.insertRow();
    for(let c = gridSize.Cols; c--;)
      rx.insertCell();
    }    
  }
function setColors( posM )
  {
  let {x,y} = getXY(posM);
  minesArea.rows[y].cells[x].className = 'red';

  setProxiColor( proxi1_green, 'green' );
  setProxiColor( proxi2_blue, 'blue' );

  function setProxiColor( proxi, color )
    {
    let _x,_y;
    for (let {h,v} of proxi )
      {
      _x = x + h;
      _y = y + v;
      if ( _x < 0 || _x >= gridSize.Cols
        || _y < 0 || _y >= gridSize.rows 
        ) 
        continue;
      minesArea.rows[_y].cells[_x].className = color;
      };
    }
  }
table {
  --szCellsWH   : 16px;
  margin           : 0 auto;
  font-size        : var(--szCellsWH);
  border-collapse  : separate;
  border-spacing   : 1px;
  background-color : #494b4d ; /*   var(--cSubText);  */
  }
td {
  width      : var(--szCellsWH);
  min-width  : var(--szCellsWH);
  height     : var(--szCellsWH);
  min-height : var(--szCellsWH);
  background : #808080;
  }
.blue  { background-color: #87cefa; }
.green { background-color: #adff2f; }
.red   { background-color: #ff0000; }
<table><tbody></tbody></table>

see my solution here (for a "classic" minesweeper game)