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)
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.
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:
9873
. It looks like this - ⚑
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:
click
for all cells around. This will open an area without mines.
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
This concludes this project! I think we achived a great result in just under 5 minutes. As usual there is room for improvement like:
Sources: https://github.com/5minute/minesweeper
See live results:https://jsfiddle.net/uo53nz78/