Minesweeper in 5 minutes

About

Minesweeper is a logical game that is played on a rectangular field. Some mines are located in random cells and player does not know where they are. With every move player reveals additional information - empty cell contains a number of mines located around that cell.
Goal of the game is to deduce where all mines are located.

Link to Wikipedia: https://en.wikipedia.org/wiki/Minesweeper_(video_game)

Live coding

Here is a live coding session that shows how it can be done.

Duration: 4:45 (coding - 4:22)

Disclaimer: never use this code in production. It was created for fun.

Breakdown

Let's break down the solution and comment on some complex or interesting things.

0:14 - as usual starting with HTML template. This time we will use canvas to draw the game field.
The game field will be 9 by 9 cells and there will be 5 mines (or bombs - these names are used as synonyms). Each cell will be 50 by 50 pixels.
ctx object is a reference to canvas drawing context.

0:31 - define a Cell class - it will encapsulate all logic around the cell like drawing and interaction with it.
By default it marks as empty cell without a bomb inside.

0:40 - initialize the game field and store it in field variable.
The process is pretty simple - we need to create a two-dimensional array containing instances of Cell.
Additionally we place some mines on the field - generate pair of x and y coordinates and mark this cell as one containing a mine. Note that we are avoiding situations when placing several mines into the same cell.

1:10 - next thing we can do is to draw the cell.
To make things a bit more conventient it is possible to move the drawing context to a specific location - it simplifies calculation of coordinates. This is done using save, translate and restore combination.
Each cell should have some background - the color depends if cell is open or not.
Next we need to decide what to draw inside:

And, of course, we draw this character or number in the center of the cell.

1:55 - now we can calculate the number of mines around. To do it let's introduce supporting function called cellsAround that returns array of cells that are around current cell. It also deals with field boundary cases.
Once we have it - we can use it to calculate number of mines around. We just need to iterate cells around current one and find out how many of them have bomb flag set.

2:27 - with some building blocks in place we are in position to finally draw the game field. We can assume that we will have a number of places where we need to do something with all inidividual cells on the game field.
For this purpose we can introduce eachCell function that will iterate through all cells and execute fn function for each of cells. You will see that it will help in next steps.
For example - game field drawing is just calling Cell.draw for each cell.
This is the first time where we can check results in browser and see the 9 by 9 game field drawn with all cells closed.

2:44 - let's try to implement openAll function that will open whole game field. Here eachCell function comes handy.
And again we can check how it looks in browser.

2:54 - so far we cannot interact with cells, but let's fix it now.
Flagging is done using flag function - it just alters flag for open cell.
Clicking (see click) a cell has several flows:

But what happens if we clicked on a cell that does not have any mines around? This means that we can safely click all cells around. We can leave it player to do or we can do it on player's behalf - recursivly call click for all cells around. This will open an area without mines.
Note that if click returns false it would mean that game should be over.

3:18 - now we should somehow process click and flag.
Idea is that a player can do left-click or right-click on canvas - we will know x and y coordinates of the event. Then we can deduce which cell it is - and then do some action with it.
Now to actual implementation - processAction just converts x and y canvas coordinates to the cell and executes fn function on it.
Also it makes sense to redraw the game field after each action to see what it has lead to.
Now we can hook click and flag to canvas using event listeners.
Note that right-click is basically calling a context menu. To avoid side-effects of showing a popup we need to prevent the event propagation to the browser.
Finally we can check results in browser - for now it looks fine.

3:54 - we are approaching the end of the project and need to handle the game over situations.
If player has marked all bombs correctly - then the game is won (see gameWon function).
finishGame is a generic function that just ends the game with a text message and reloads the screen for a new game.
Do you remember that click function might return false when player has clicked on a mine? This is an indication that game is lost. Let's utilize it in processAction to finish the game.

4:22 - seems we are done with the coding and we can check out the project end-to-end in the browser.
We can see that basic functionality like

works fine and as expected!

This concludes this project! I think we achived a great result in just under 5 minutes. As usual there is room for improvement like:

Resources

Sources: https://github.com/5minute/minesweeper

See live results:https://jsfiddle.net/uo53nz78/