Search code examples
javascripthtmlminesweeper

javascript minesweeper expand messing up counter


I made a minesweeper game in javascript, which was finally running pretty smoothly, until i added the "expand()" function (see below). I have 3 issues:

  1. When it expands it adds too many to "flippedCount" ( see code below ) - in the image below the div to the right displays "flippedCount", and its 39 instead of 35.
  2. As a result, if a player exceeds 90 squares ( amount to win ) during a "expand()", the winning screen doesnt show.
  3. It also doesnt expand properly ( see images below ).

The relevant code and a link is below these 2 images

Image showing a partly completed minesweeper field

Image showing an 'empty' minesweeper field

var flippedCount = 0;
var alreadySetAsZero = [];
var columnAmount = 10;

function processClick(clicked) { //i use a "(this)" to pass as "(clicked)"
  nextToBombCheck( parseInt(clicked.id) );
  checkWin();
}

nextToBombCheck( boxNum ) { 
  flippedCount++;
  document.getElementById("flipped").innerHTML = flippedCount;  
  //long function setting "bombCount" to # bombs around clicked square goes here
  if ( bombCount !== 0 ) { 
    //blah blah blah
  } else {
    alreadySetAsZero[ boxNum ] = "yes";
    expand(boxNum);
  } 
}

function expand( emptyBoxId ) {
  checkRightOfEmpty( emptyBoxId + 1 );
  checkLeftOfEmpty( emptyBoxId - 1 );
  checkAboveEmpty( emptyBoxId - columnAmount );
  checkBelowEmpty( emptyBoxId + columnAmount );
} 

function checkRightOfEmpty( boxToTheRightId ) {
  //check if already marked as zero
  if ( alreadySetAsZero[ boxToTheRightId ] === "yes" )
    return;
  //if box is at the edge
  if ( boxToTheRightId % columnAmount === ( 0 ) ) {
    //do nothing
  } else {
    nextToBombCheck( boxToTheRightId );
  }
}

//and the rest are 3 similar functions

I was not able to find a pattern with the lack of expansion or numbers added to flipped count.

link here

p.s. sorry about the title i dont know what else to call it


Solution

  • You are getting an incorrect count because your algorithm doesn't take into account squares that have already been flipped - resulting is squares getting counted twice.

    The simplest way to keep an accurate count of the is to make use of that fact that 'getElementsByClassName' returns a live node list.

    Note: getElementsByClassName has pretty good browser support, but if your browser requirements are different, you will need to adjust this a bit.

    On entry, initialize the list (variable name just to differentiate from previous name):

    var newFlippedCount = document.getElementsByClassName('flipped');
    

    Each time you update a square with a bomb count class use this instead (adds the flipped class as well):

    document.getElementById(boxNum).className = classList[bombCount] + ' flipped';
    

    When you update the UI with the new flipped count use:

    document.getElementById("flipped").innerHTML = newFlippedCount.length;
    

    Your count is now magically correct :)

    Note: you could also solve this by checking to see if the box has already been flipped before incrementing flippedCount.

    You were also periodically getting an error in the console:

    Uncaught TypeError: Cannot set property 'className' of null
    

    at this line (around line: 298):

    document.getElementById(boxNum).className = classList[bombCount];

    You should protect that either by checking the bounds or just by checking the return value before using it:

    var ele = document.getElementById(boxNum);
    if(!ele) return;
    
    ele.className = classList[bombCount] + ' flipped';
    

    Demo

    Edit: If you are interested, here is a high level overview of the Minesweeper Cascade Algorithm

    Update - cascade bug found

    One of the reasons the cascade wasn't working correctly on successive replays is that the variable used to track cells that had already been set to zero wasn't getting reset in a new game. For a fix:

    function start() {
       …
       // Reset to empty array
       alreadySetAsZero = [];
       ...
    }
    

    Updated fiddle with additional debug statements to help find the problem:

    Demo