Web version of the classic Minesweeper
- Clone the repository with
git clone https://github.com/GuilhermeBalog/minesweeper.git
- Open the
index.html
file on your favorite browser!
The whole game works inside the Game object
const Game = {...}
There are some main attributes:
width: 10,
height: 8,
bombs: 10,
field: [],
gameOver: false,
I decided that the field array would be a one dimension array, so its length is width * height
.
Each cell has a value (0 is the default) that represents how many bombs there are around it and a boolean attribute to control if it's open
// snippet of the initField() method
for (let i = 0; i < this.field.length; i++) {
this.field[i] = { opened: false, value: 0 }
}
To place the bombs randomly, the value of field[0]
to field[bombs - 1]
is -1 (bomb!), and then the array is random sorted
// snippet of the placeBombs() method
for (let i = 0; i < this.bombs; i++) {
this.field[i].value = -1
}
this.field.sort((a, b) => {
return 0.5 - Math.random()
})
Now it's the magic time! how to place the numbers? The numbers represents how many bombs there around each cell, or -1 if its a bomb
There are 3 main main methods in this process:
getAroundIndexes()
countBombs()
placeNumbers()
getAroundIndexes
returns an array with the valid indexes of the around cellscountBombs
iterates thearoundIndexes
and returns the amount of-1
- And
placeNumbers
callscountBombs
for each cell that is not a bomb
When the player open a cell there are 3 basic options: its a bomb, or its a number between 1 and 8, or its a zero
- if its a bomb, all the others bombs are opened too and the game is ended
- if its a number between 1 and 8 just the selected cell is opened
- if its a zero all the non-bomb cells around are opened recursively
In any case opened
attribute of the cell is set to true
//snippet of the openCell(index) method
this.field[index].opened = true
if (this.hasBombAt(index)) {
this.openAllBombs()
this.gameOver = true
return
}
if (this.field[index].value == 0) {
const aroundIndexes = this.getAroundIndexes(index)
aroundIndexes.forEach(i => {
if (this.field[i].value != -1) {
this.openCell(i)
}
})
}
The game is finished when the player loses opening a bomb or wins when all the non-bomb cells are opened
checkWin: function () {
const closedCells = this.field.filter(cell => {
return cell.opened == false
})
if (closedCells.length == this.bombs) {
this.gameOver = true
}
}
I tried to make a low coupling program, splitting data methods and visual methods, so the visual methods doesn't change the data.
The main visual method is draw
. It render the controls and the field and it's called by many other methods.
createFieldElement
returns a HTML element with the rendered game field as a table.
The bombs are rendered as ⦿ characters and the zeros are rendered as white spaces
Check the index.js file and feel free to fork this repo and add your ideias!
That's all folks! Keep coding!