Sweeping Mines is inspired by the classic computer game Minesweeper. The same mechanics have been implemented but with graphics designed by me. Moreover, the game can be played on either PCs or Phones!
Just like the original game, the objective is to find all of the empty cells while avoiding the mines hidden on the board.
Unlike the original game, the map is a 10x10 units/cells, hence a total of 100 cells. 20 of these cells contain bombs spread out in random positions all around the grid. When a non-bomb cell is revealed, a number is revealed in the cell. The number indicates the number of bombs 1 unit around the cell, from zero to 8. If no bombs are present around the cell, no number is shown. The clue can be used by the user to identify/guess the position of bombs in the grid. The player has a flag at their disposal which can be placed on any empty cell as a bomb-marker.
IMPORTANT: the flag can be placed on any cell, bomb or empty.
Whenever one of these cells with a bomb is clicked, the game ends in a lost. Although, if all the empty cells are found, the game ends with a victory instead!
- HTML/CSS
- JavaScrit
You can click the following link to open the GitHub web page: https://ertucci674.github.io/sweeping-mines/
Otherwise, download the repository or clone it, then:
Open the index.html file with any browser and start playing! Preferably, use one of the following ones:
- Google Chrome
- Mozilla Firefox
- Microsoft Edge
- Safari
- Opera
- Brave
- Internet Explorer 11 and later versions
Other applications might work - Bugs should be expected.
No compiler is necessary as the game runs on Browsers. JavaScript knowledge is required to modify the program. Just clone the repository in your local machine and start programming:
git clone https://github.com/ErTucci674/sweeping-mines.git
The index.html
file contains the entire structure of the page and game. The style.css
file contains all of the aesthetics of the game.
The script.js
file is where the all of the dynamics and logic of the game takes place.
The file begins with the variables setup. During the game, the program will check if a bomb is present in the selected cell. To keep track of the cells' position and contained item a 2d array is used. Each item in the array contains a number equivalent to either EMPTY
to set it as an empty cells or BOMB
to "insert" a bomb in the cell. The array is initialized with empty cells at first:
let cells = Array(rows).fill().map(() => Array(columns).fill(EMPTY));
A while loop then "generates" a totalBombs
number of bombs on random positions around the grid while making sure the selected cell is awlays empty. The cells
array is then updated with a BOMB
value on the randomly chosen position:
while (insertedBombs < totalBombs) {
// Generate a random number between 0 and rows/columns
const randomRow = Math.floor(Math.random() * rows);
const randomColumn = Math.floor(Math.random() * columns);
if (cells[randomColumn][randomRow] != BOMB) {
cells[randomColumn][randomRow] = BOMB;
insertedBombs++;
}
}
The score value is displayed on the top right corner of the game display. This keeps count of all of the empty cells the player found. The number starts with a series of zeros. The number of zeros represent the number of units needed to form the number of cells in the game (e.g., 100 cells --> 3 zeros OR 1000 cells --> 4 zeros). A while loop calculates the number of zeros needed:
let tmpValue = totalCells;
do {
tmpValue = Math.floor(tmpValue / 10);
scoreZeros++;
scoreCounter.innerText += '0';
} while (tmpValue > 0);
The total number of cells is stored in a variable so the original value is not affected. In the while loop, the variable is divided by 10 so one unit is counted and a zero added to the Score string. Whenever the variable reaches a value of zero, the while loop stops.
The updateScore()
function uses the number of zeros counted in the while loop to increment and display the new score by keeping the correct number of zeros.
function updateScore() {
score++;
scoreCounter.innerText = score.toString().padStart(scoreZeros, '0');
if (score === maxScore) {
endGame(true);
}
}
Next is the grid generation. A grid
class is assigned to a div
in the HTML file and all the settings (size, colour, position, etc.) are managed by the CSS file. However, the cells are missing and implementing them by hand would make the code chunky and hard to read. Therefore, a couple of for loops do the job for us.
The loops cycle as many times as the values stored in rows
and columns
. In each cycle, a div
element is created and added as a child to the grid
element. Each cell inherits the cell
class and a cellText
element which shows the number of bombs around it.
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
// Generate cell
const cell = document.createElement("div");
cell.classList.add("cell");
...
const cellText = document.createElement("div");
cell.classList.add("cellText");
cellText.innerHTML = "";
cell.appendChild(cellText);
grid.appendChild(cell);
}
}
Each cell
also includes two EventListeners
: right and left mouse clicks. The right click adds or removes the cell-flagged
class which draws a flag in the cell. The left click reveals the cell instead. A series of if statements check if a bomb is in the selected cell by looking into the cells
position selected on the grid and checking if a BOMB
value is stored.
The revealAllBombs()
function is used at the end of the game (whether the player wins or loses). All of the cell elements are temporarily stored in the allCells
array. The function goes through the cells
array with a double for loop and every time a bomb is encountered the cell-bomb
class is added to the corresponding cell in the allCells
array so the bomb can be shown.
function revealAllBombs() {
const allCells = document.querySelectorAll('.cell');
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) {
if (cells[c][r] == BOMB) {
const cellNum = r * rows + c;
allCells[cellNum].classList.remove('cell-flagged');
allCells[cellNum].classList.add('cell-bomb');
}
}
}
}
The endGame()
function manages the final illustrations dependant on the game's final outcome. Whether the player wins or loses, the final screen colours and text are determined and shown on top of the board game.
function endGame(isVictory) {
if (isVictory) {
endGameText.innerHTML = "YOU<br>WON";
endGameScreen.classList.add("win");
}
revealAllBombs();
endGameScreen.classList.remove("hidden");
}
When the game ends, a Play Again button is shown. This includes an event listener that checks for a mouse click. When the button is clicked, the page is reloaded, hence the game restarted.
playAgainButton.addEventListener("click", () => {
window.location.reload();
});
On the CSS file, a @media
is used to see if the screen of the device that accessed the browser is of a certain length. In case it is less than the pre-stablished maximum number, the tutorial text is swapped for a Flag Button.
@media screen and (max-width: 767px) {
.tutorial-pc {
display: none;
}
.tutorial-phone-btn {
display: block;
}
}
PC users have the left and right 'click' of a mouse to reveal the cells and place a flag. Phone users have only the 'touch' option, instead. This counts as a mouse left click which is reveals cells. The flag button allows phone users to insert flags as well by changing the 'touch' mode of the game. When the button is clicked and the flag mode is ON, every 'touch'places/removes a flag. Whilst the flag mode is OFF, every 'touch' reveals the selected cell.
tutorialPhoneBtn.addEventListener("click", () => {
tutorialBtnActive = !tutorialBtnActive;
if (tutorialBtnActive) {
tutorialPhoneBtn.classList.add('tutorial-phone-btn-active');
}
else {
tutorialPhoneBtn.classList.remove('tutorial-phone-btn-active');
}
});
This project is licensed under the terms of the GNU General Public License, version 3.0.