Minesweeper in Javascript and Canvas

Game state and Starting a new level

Our checkState method, which is called every time a hidden tile is revealed, begins by checking every tile in the grid array. If a tile is found which does not have a mine (hasMine equals false) and does not have the currentState visible, we leave the function immediately:

function checkState()
{
	for(var i in grid)
	{
		if(grid[i].hasMine==false && grid[i].currentState!='visible')
		{
			return;
		}
	}

If the check is passed, the game has been won. We set the gameState.timeTaken to the current gameTime, and create a reference to the current difficulty level called cDiff.

	gameState.timeTaken = gameTime;
	var cDiff = difficulties[gameState.difficulty];

If there isn't currently a bestTime for the difficulty level, or the time the player has taken is better than the bestTime, update the bestTime accordingly and set the gameState.newBest flag to true.

	if(cDiff.bestTime==0 ||
		gameTime < cDiff.bestTime)
	{
		gameState.newBest = true;
		cDiff.bestTime = gameTime;
	}

The current screen is changed to the won screen, and the method is complete:

	gameState.screen = 'won';
}

Game Over

If the gameOver method is called in our game, we're just going to change to the lost screen:

function gameOver()
{
	gameState.screen = 'lost';
}

Starting a new level

When a new level is started with the startLevel method, it is passed the difficulty level which will be played (diff), and begins by resetting the gameState newBest and timeTaken properties, changing the screen to playing, and the difficulty to the provided diff. We also set the gameTime and lastFrameTime to 0 and empty the grid array.

function startLevel(diff)
{
	gameState.newBest		= false;
	gameState.timeTaken		= 0;
	gameState.difficulty		= diff;
	gameState.screen		= 'playing';
	
	gameTime			= 0;
	lastFrameTime			= 0;
	
	grid.length			= 0;

A temporary reference to the information for the current difficulty level called cDiff is also created:

	var cDiff = difficulties[diff];

The offsetX, offsetY values for drawing the game grid are also calculated by subtracting the total width or height of the grid (gameState.tileW x cDiff.width and gameState.tileH x cDiff.height) from the Canvas elements width or height, and dividing the result by 2:

	offsetX = Math.floor((document.getElementById('game').width -
			(cDiff.width * gameState.tileW)) / 2);
	
	offsetY = Math.floor((document.getElementById('game').height -
			(cDiff.height * gameState.tileH)) / 2);

After, we loop through each column and each row and create a new Tile object for the current px, py position and add it to the grid array:

	for(var py = 0; py < cDiff.height; py++)
	{
		for(var px = 0; px < cDiff.width; px++)
		{
			var idx = ((py * cDiff.width) + px);
			
			grid.push(new Tile(px, py));
		}
	}

A counter for the number of minesPlaced is created, and we then begin a loop that will continue until we've placed the number of mines the current difficulty requires:

	var minesPlaced = 0;
	
	while(minesPlaced < cDiff.mines)
	{

A random grid index is selected. If the position already has a mine, we jump back to the start of the loop and try again. Otherwise, we place a mine at the target index and increase the minesPlaced counter. Afterwards we close this loop.

		var idx = Math.floor(Math.random() * grid.length);
		
		if(grid[idx].hasMine) { continue; }
		
		grid[idx].hasMine = true;
		minesPlaced++;
	}

Finally, for each grid entry we call the calcDanger method, and the function can be closed.

	for(var i in grid) { grid[i].calcDanger(); }
}
Page loaded in 0.012 second(s).