I want to generate random mines with a button ".btn" for my Minesweeper Game but I only managed to hide the tiles. I can't figure out why calling getMinePositions(boardSize, numberOfMines) doesn't work - mines are not generated after clicking the button, they stay in the same place as before. I also want to unable the stopProp with button, right now if a mine is revealed (game is lost) I can't start a new game with button because I can't click on the tiles. Any help would be appreciated :-)
const TILE_STATUSES = {
HIDDEN: "hidden",
MINE: "mine",
NUMBER: "number",
};
function createBoard(boardSize, numberOfMines) {
const board = [];
const minePositions = getMinePositions(boardSize, numberOfMines);
for (let x = 0; x < boardSize; x++) {
const row = [];
for (let y = 0; y < boardSize; y++) {
const element = document.createElement("div");
element.dataset.status = TILE_STATUSES.HIDDEN;
document.querySelector(".btn").addEventListener("click", function () {
// 1.Hide the tiles - working just fine :)
element.dataset.status = TILE_STATUSES.HIDDEN;
// 2.Generate new mines - not working, mines stay in the same place as before. Only refreshing the page creates new mines. - Proper behaviour new mines should be generated when button is clicked.
getMinePositions(boardSize, numberOfMines);
// 3.No idea how to disable checkGameEnd function from "./script.js" with this button :( - Proper behaviour if mine is revealed and game is lost, click button to start new game (disable stopImmediatePropagation).
});
const tile = {
element,
x,
y,
mine: minePositions.some(positionMatch.bind(null, { x, y })),
get status() {
return this.element.dataset.status;
},
set status(value) {
this.element.dataset.status = value;
},
};
row.push(tile);
}
board.push(row);
}
return board;
}
function revealTile(tile) {
if (tile.status !== TILE_STATUSES.HIDDEN) {
return;
}
if (tile.mine) {
tile.status = TILE_STATUSES.MINE;
return;
}
tile.status = TILE_STATUSES.NUMBER;
}
function checkLose(board) {
return board.some((row) => {
return row.some((tile) => {
return tile.status === TILE_STATUSES.MINE;
});
});
}
function getMinePositions(boardSize, numberOfMines) {
const positions = [];
while (positions.length < numberOfMines) {
const position = {
x: randomNumber(boardSize),
y: randomNumber(boardSize),
};
if (!positions.some(positionMatch.bind(null, position))) {
positions.push(position);
}
}
return positions;
}
function positionMatch(a, b) {
return a.x === b.x && a.y === b.y;
}
function randomNumber(size) {
return Math.floor(Math.random() * size);
}
const BOARD_SIZE = 5;
const NUMBER_OF_MINES = 2;
const board = createBoard(BOARD_SIZE, NUMBER_OF_MINES);
const boardElement = document.querySelector(".board");
board.forEach((row) => {
row.forEach((tile) => {
boardElement.append(tile.element);
tile.element.addEventListener("click", () => {
revealTile(tile);
checkGameEnd();
});
tile.element.addEventListener("contextmenu", (e) => {
e.preventDefault();
});
});
});
boardElement.style.setProperty("--size", BOARD_SIZE);
// Disable this when click ".btn"
function checkGameEnd() {
const lose = checkLose(board);
if (lose) {
boardElement.addEventListener("click", stopProp, { capture: true });
boardElement.addEventListener("contextmenu", stopProp, { capture: true });
}
if (lose) {
board.forEach((row) => {
row.forEach((tile) => {
if (tile.mine) revealTile(tile);
});
});
}
}
function stopProp(a) {
a.stopImmediatePropagation();
}
* {
box-sizing: border-box;
}
body {
font-family: serif;
background-color: #000000da;
}
.btn {
font: inherit;
font-size: 20px;
font-family: Arial;
background-color: rgb(31, 30, 30);
color: rgba(255, 255, 255, 0.842);
border: 1px solid #2bbe06;
position: absolute;
cursor: pointer;
border-radius: 2px;
width: 230px;
height: 30px;
left: 20px;
top: 40%;
}
.board {
display: inline-grid;
grid-template-columns: repeat(var(--size), 100px);
grid-template-rows: repeat(var(--size), 100px);
gap: 20px;
background-color: rgb(31, 30, 30);
padding-top: 30px;
padding-left: 40px;
}
.board > * {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
color: white;
user-select: none;
border-radius: 5px;
border: 2px solid rgba(255, 217, 0, 0.507);
box-shadow: 0 0 4px rgb(246, 246, 67);
}
.board > [data-status="hidden"] {
background-color: rgba(255, 255, 255, 0.068);
cursor: pointer;
}
.board > [data-status="mine"] {
background-color: rgba(255, 0, 0, 0.63);
box-shadow: 0 0 5px rgb(255, 0, 0);
border: 2px solid rgb(255, 255, 255);
}
.board > [data-status="number"] {
background-color: rgba(38, 255, 0, 0.466);
border: 2px solid rgb(255, 217, 0);
box-shadow: 0 0 5px rgb(255, 255, 255);
}
.bOx {
width: 270px;
height: 640px;
border-radius: 5px;
position: absolute;
left: 550px;
bottom: 660px;
top: 200px;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.13);
background-color: rgb(31, 30, 30);
}
.card {
width: 660px;
height: 640px;
left: 825px;
top: 50px;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.13);
position: absolute;
margin: 20px auto;
border-radius: 5px;
margin-top: 150px;
margin-right: 350px;
background-color: rgb(31, 30, 30);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<script src="script.js" type="module"></script>
</head>
<body>
<div class="card">
<div class="board"></div>
</div>
<div class="bOx">
<button class="btn">Start</button>
</div>
</body>
</html>