I have made a simple game of Minesweeper with JavaScript and it's working fine except that when I click on the middle of a big area without mines it doesn't clear that whole area, only the position where I clicked.
There are already other questions for that but the way I made mine check to generate the numbers is (I believe) different so the solution should be made for it more specifically instead of changing the code to look more like what others did.
Here's an image which explains better the situation (with additional colors that don't show in the actual code):
Blue is where the user clicked and then it should check both vertically and horizontally (dark green) if those positions have 0 mines around to expand (green) until the border (yellow) where the mines (orange) are close enough.
I tried to make the code as readable and easy to understand:
(function() {
var minesweeper = document.createElement('div');
var positions = [];
var playing = true;
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function end() {
this.onclick = null;
if ( playing ) {
playing = false;
this.style.backgroundColor = 'rgb(255, 0, 0)';
alert('Game over.');
}
}
function update() {
this.onclick = null;
if ( playing ) {
this.style.backgroundColor = 'rgb(0, 255, 0)';
this.className = 'safe';
let mines = 0;
let element = this.previousElementSibling;
if ( element ) {
if ( element.className == 'mine' && this.style.top == element.style.top ) mines++;
for ( let i = 0; i < 8; i++ ) {
element = element.previousElementSibling;
if ( !element ) break;
}
if ( element ) {
if ( element.className == 'mine' && this.style.top != element.style.top ) mines++;
element = element.previousElementSibling;
if ( element ) {
if ( element.className == 'mine' ) mines++;
element = element.previousElementSibling;
if ( element )
if ( element.className == 'mine' && (parseInt(this.style.top) - parseInt(element.style.top)) == 9 ) mines++;
}
}
}
element = this.nextElementSibling;
if ( element ) {
if ( element.className == 'mine' && this.style.top == element.style.top ) mines++;
for ( let i = 0; i < 8; i++ ) {
element = element.nextElementSibling;
if ( !element ) break;
}
if ( element ) {
if ( element.className == 'mine' && this.style.top != element.style.top ) mines++;
element = element.nextElementSibling;
if ( element ) {
if ( element.className == 'mine' ) mines++;
element = element.nextElementSibling;
if ( element )
if ( element.className == 'mine' && (parseInt(element.style.top) - parseInt(this.style.top)) == 9 ) mines++;
}
}
}
this.innerText = mines;
if ( minesweeper.querySelectorAll('div.safe').length == 90 ) {
playing = false;
alert('Victory.');
}
}
}
minesweeper.style.backgroundColor = 'rgb(0, 0, 0)';
minesweeper.style.fontSize = '7vmin';
minesweeper.style.textAlign = 'center';
minesweeper.style.userSelect = 'none';
minesweeper.style.position = 'absolute';
minesweeper.style.left = 'calc(50vw - 45.5vmin)';
minesweeper.style.top = 'calc(50vh - 45.5vmin)';
minesweeper.style.width = '91vmin';
minesweeper.style.height = '91vmin';
for ( let i = 0; i < 10; i++ ) {
for ( let j = 0; j < 10; j++ ) {
const n = i * 10 + j;
positions[n] = document.createElement('div');
positions[n].style.backgroundColor = 'rgb(255, 255, 255)';
positions[n].style.position = 'absolute';
positions[n].style.left = (j * 8 + j + 1) + 'vmin';
positions[n].style.top = (i * 8 + i + 1) + 'vmin';
positions[n].style.width = '8vmin';
positions[n].style.height = '8vmin';
minesweeper.appendChild(positions[n]);
}
}
for ( let i = 0; i < 11; i++ ) {
const empty = minesweeper.querySelectorAll('div:not(.mine)');
if ( i == 10 ) {
for ( let j = 0; j < 90; j++ ) {
empty[j].onclick = update;
}
break;
}
const n = random(0, (empty.length - 1));
empty[n].className = 'mine';
empty[n].onclick = end;
}
document.body.style.margin = '0px';
document.body.appendChild(minesweeper);
})();
The way I do the checks for the positions around the one where the number goes is with previousElementSibling
and nextElementSibling
.