by Alberto Cerrone
Timeline: 7 days
👉 Try Me 👈
This project is the representation of Minesweeper from Windows 95.
As simple as it sounds, this was my first project in General Assembly's Software Engineering Immersive course. It was an individual project assigned to us after three weeks of learning and built in less than a week.
As much as I would love to improve the code, I'm deciding to keep it as it is for two reasons:
- To show what I'm capable to build after just three weeks into coding
- Remind the future myself, that maybe will look back on those lines with nostalgia.
Talking about nostalgia, I decided to build Minesweeper from Windows 95 because take me back memories of my first computer my dad bought me when I was 6.
If you are going to play this game, I hope you will have a good jump into the past and have good fun.
Enjoy!
This game is a desktop-only website and requires the use of a mouse/trackpad.
Please, take advantage of full-screen mode for a better experience.
No installation is needed, just follow this link
The goal of the game is simple:
You have to find all the mines in the field!
To do so, you have two types of input:
- Left Click: Open the hidden block
- Right Click: Flag the hidden block to sign a probable mine
When you open a block, the game will show you a number between 1 to 8.
Those are the mines adjacent to that block; they will be helpful to you to discover more bombs and finish the game
From the menu Game, you can decide between 3 levels of difficulty:
- Beginner: 9x9 arena with ten mines to find;
- Intermediate: 16x16 arena with forty mines to find;
- Expert: 30x16 arena with 99 mines to find.
If you desire to reset the game, you can click on the smiley face.
You can understand better the games rules from this Youtube's video: How to play Minesweeper by Eric Buffington
The technologies used for this project are:
- HTML5
- CSS with the seamless use of CSS Grid and Flexbox
- Vanilla JavaScript
- Photoshop for little UI details
Before starting to code, I threw down what are the key functionalities of this game. To do so I had fun playing to the game on Google and generated a little TODO list at the opening of my app.js file to keep track of the deliverables. I helped myself with the VSCode's extension "Better Comments" to better categorize my annotations.
I structured all the JS around level Beginner, but with the ending purpose of the multi-level experience. This mindset allowed me to directly develop all the functions ready to be used for level Intermediate and level Expert without the need of refactoring the code. To achieve this, the rendering of the mined floor is handled by JavaScript.
Just at the end, when the game was perfectly working in level Beginner, I've added a function changeLevel()
that manipulates UI and logic of all the different levels thanks to the "Game" dropdown.
function changeLevel(event) { //this function change the UI and the logic of the game for every level
if (event === null) {
return
} else if (event.target.innerHTML === 'Intermediate') {
width = 16
height = 16
cellCount = width * height
nBombs = 40
nFlags = nBombs
flagsMonitor.innerHTML = nFlags
grid.style.gridTemplateColumns = 'repeat(16, 1fr)'
grid.style.gridTemplateRows = 'repeat(16, 1fr)'
grid.style.width = '300px'
gameWrapper.style.width = '300px'
reset()
} else if (event.target.innerHTML === 'Expert') {
width = 30
height = 16
cellCount = width * height
nBombs = 99
nFlags = nBombs
flagsMonitor.innerHTML = nFlags
grid.style.gridTemplateColumns = 'repeat(30, 1fr)'
grid.style.gridTemplateRows = 'repeat(16, 1fr)'
grid.style.width = '600px'
gameWrapper.style.width = '600px'
reset()
} else {
width = 9
height = 9
cellCount = width * height
nBombs = 10
nFlags = nBombs
flagsMonitor.innerHTML = nFlags
grid.style.gridTemplateColumns = 'repeat(9, 1fr)'
grid.style.gridTemplateRows = 'repeat(9, 1fr)'
grid.style.width = '300px'
gameWrapper.style.width = '300px'
reset()
}
One of the weak points of my project is the use of CSS classes to keep track of the bombs' position. That allows the player to cheat, just opening the browser's console and running this two lines:
document.querySelectorAll('.bomb').forEach((node) => node.classList.add('flagged'))
document.querySelectorAll('.covered:not(.bomb)').forEach((node) => node.click())
(Thank you, Andrew Webb, for let me realize this issue).
Another thing that I'm not proud of is UI. The background is not responsive, and I didn't have the opportunity to style it better cause of the incoming deadline.
I love how I've managed to create reusable functions for a much cleaner code.
An example is the function whoIsCloseToMe()
:
function whoIsCloseToMe(index) {
const column = cellsStatusInfo[index].column
const row = cellsStatusInfo[index].row
let cellDistance
const closeToMe = []
// up-left corner
if (row > 0 && column > 0) {
cellDistance = -(width + 1)
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
// up-center
if (row > 0) {
cellDistance = -(width)
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
//up-right
if (row > 0 && column < width - 1) {
cellDistance = -(width - 1)
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
//left
if (column > 0) {
cellDistance = - 1
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
//right
if (column < width - 1) {
cellDistance = + 1
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
//down-left
if (row < height - 1 && column > 0) {
cellDistance = width - 1
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
//down-center
if (row < height - 1) {
cellDistance = width
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
//down-right
if (row < height - 1 && column <code width - 1) {
cellDistance = width + 1
closeToMe.push(cellsStatusInfo[index + cellDistance].idCell)
}
return closeToMe
}
I've used this function to find the cells that are close to the selected one and this is being useful for two different cases:
- Open the cells that are around
- Find how many bombs are around each cell.
I have no intention to modify this project for this reason but if I was going to work on it I would implement these features:
- Custom Game, to give to user the opportunity to choose the number of rows, columns and bombs
- Implement an audio button to toggle on/off the audio of the explosion
- Opportunity to be used on touch screen devices
I loved this project because was my first made after learning basic concepts of HTML, CSS, and JavaScript.
It taught me a lot about planning with the end goal in mind and to keep the code more understandable thanks to annotations.
To improve even more the code and make it cleaner, I would refactor app.js in smaller components and replace those long functions with smaller functions that take care of just one thing. This would help readability and future maintenance.
- Alberto Cerrone 📧
If you have suggestions for improving this project, please open an issue on GitHub.
I will fix just bugs but any suggestions you'll give me to improve the functionality of the game will be used as form of learning but not applied to the code.
This work is dedicated to the public domain (CC0 1.0). To the extent possible under law, Alberto Cerrone has waived all copyright and related or neighboring rights to the Minesweeper Project. See the LICENSE file for all the legalese.
- Twitter - @AlbertoCerrone
- LinkedIn - Alberto Cerrone
- Website - Portfolio