Changed around line 1
+ class MinesweeperGame {
+ constructor() {
+ this.level = 1;
+ this.grid = [];
+ this.mines = [];
+ this.timer = 0;
+ this.timerInterval = null;
+ this.isGameOver = false;
+
+ this.initializeDOM();
+ this.setupEventListeners();
+ this.startLevel(this.level);
+ }
+
+ initializeDOM() {
+ this.gridElement = document.getElementById('grid');
+ this.levelElement = document.getElementById('current-level');
+ this.minesElement = document.getElementById('mines-count');
+ this.timerElement = document.getElementById('timer');
+ this.modal = document.getElementById('modal');
+ this.modalTitle = document.getElementById('modal-title');
+ this.modalMessage = document.getElementById('modal-message');
+ this.modalButton = document.getElementById('modal-button');
+ }
+
+ setupEventListeners() {
+ document.getElementById('restart').addEventListener('click', () => this.startLevel(this.level));
+ document.getElementById('help').addEventListener('click', () => this.showHelp());
+ this.modalButton.addEventListener('click', () => this.hideModal());
+ }
+
+ getLevelConfig(level) {
+ return {
+ rows: Math.min(8 + Math.floor(level / 5), 16),
+ cols: Math.min(8 + Math.floor(level / 5), 16),
+ mines: Math.min(10 + level * 2, 99)
+ };
+ }
+
+ startLevel(level) {
+ this.level = level;
+ this.isGameOver = false;
+ clearInterval(this.timerInterval);
+ this.timer = 0;
+ this.timerElement.textContent = '0';
+
+ const config = this.getLevelConfig(level);
+ this.createGrid(config);
+ this.levelElement.textContent = level;
+ this.minesElement.textContent = config.mines;
+
+ this.timerInterval = setInterval(() => {
+ this.timer++;
+ this.timerElement.textContent = this.timer;
+ }, 1000);
+ }
+
+ createGrid(config) {
+ this.grid = [];
+ this.mines = [];
+ this.gridElement.innerHTML = '';
+ this.gridElement.style.gridTemplateColumns = `repeat(${config.cols}, var(--cell-size))`;
+
+ for (let i = 0; i < config.rows; i++) {
+ this.grid[i] = [];
+ for (let j = 0; j < config.cols; j++) {
+ const cell = document.createElement('button');
+ cell.className = 'cell';
+ cell.dataset.row = i;
+ cell.dataset.col = j;
+
+ cell.addEventListener('click', (e) => this.handleClick(e));
+ cell.addEventListener('contextmenu', (e) => this.handleRightClick(e));
+
+ this.gridElement.appendChild(cell);
+ this.grid[i][j] = {
+ element: cell,
+ isMine: false,
+ isRevealed: false,
+ isFlagged: false,
+ neighborMines: 0
+ };
+ }
+ }
+
+ this.placeMines(config);
+ this.calculateNeighborMines(config);
+ }
+
+ placeMines(config) {
+ let minesToPlace = config.mines;
+ while (minesToPlace > 0) {
+ const row = Math.floor(Math.random() * config.rows);
+ const col = Math.floor(Math.random() * config.cols);
+
+ if (!this.grid[row][col].isMine) {
+ this.grid[row][col].isMine = true;
+ this.mines.push({row, col});
+ minesToPlace--;
+ }
+ }
+ }
+
+ calculateNeighborMines(config) {
+ const directions = [
+ [-1,-1], [-1,0], [-1,1],
+ [0,-1], [0,1],
+ [1,-1], [1,0], [1,1]
+ ];
+
+ for (let i = 0; i < config.rows; i++) {
+ for (let j = 0; j < config.cols; j++) {
+ if (!this.grid[i][j].isMine) {
+ let count = 0;
+ for (const [dx, dy] of directions) {
+ const newRow = i + dx;
+ const newCol = j + dy;
+ if (newRow >= 0 && newRow < config.rows &&
+ newCol >= 0 && newCol < config.cols &&
+ this.grid[newRow][newCol].isMine) {
+ count++;
+ }
+ }
+ this.grid[i][j].neighborMines = count;
+ }
+ }
+ }
+ }
+
+ handleClick(e) {
+ e.preventDefault();
+ if (this.isGameOver) return;
+
+ const row = parseInt(e.target.dataset.row);
+ const col = parseInt(e.target.dataset.col);
+ const cell = this.grid[row][col];
+
+ if (cell.isFlagged) return;
+
+ if (cell.isMine) {
+ this.gameOver(false);
+ return;
+ }
+
+ this.revealCell(row, col);
+ this.checkWin();
+ }
+
+ handleRightClick(e) {
+ e.preventDefault();
+ if (this.isGameOver) return;
+
+ const row = parseInt(e.target.dataset.row);
+ const col = parseInt(e.target.dataset.col);
+ const cell = this.grid[row][col];
+
+ if (!cell.isRevealed) {
+ cell.isFlagged = !cell.isFlagged;
+ cell.element.classList.toggle('flagged');
+ }
+ }
+
+ revealCell(row, col) {
+ const cell = this.grid[row][col];
+ if (cell.isRevealed || cell.isFlagged) return;
+
+ cell.isRevealed = true;
+ cell.element.classList.add('revealed');
+
+ if (cell.neighborMines > 0) {
+ cell.element.textContent = cell.neighborMines;
+ } else {
+ const directions = [
+ [-1,-1], [-1,0], [-1,1],
+ [0,-1], [0,1],
+ [1,-1], [1,0], [1,1]
+ ];
+
+ for (const [dx, dy] of directions) {
+ const newRow = row + dx;
+ const newCol = col + dy;
+ if (newRow >= 0 && newRow < this.grid.length &&
+ newCol >= 0 && newCol < this.grid[0].length) {
+ this.revealCell(newRow, newCol);
+ }
+ }
+ }
+ }
+
+ checkWin() {
+ const config = this.getLevelConfig(this.level);
+ const totalCells = config.rows * config.cols;
+ let revealedCells = 0;
+
+ for (let i = 0; i < config.rows; i++) {
+ for (let j = 0; j < config.cols; j++) {
+ if (this.grid[i][j].isRevealed) revealedCells++;
+ }
+ }
+
+ if (revealedCells === totalCells - config.mines) {
+ this.gameOver(true);
+ }
+ }
+
+ gameOver(won) {
+ this.isGameOver = true;
+ clearInterval(this.timerInterval);
+
+ if (won) {
+ if (this.level === 30) {
+ this.showModal('Congratulations!', 'You\'ve completed all levels!', 'Play Again');
+ this.level = 1;
+ } else {
+ this.showModal('Level Complete!', `Ready for level ${this.level + 1}?`, 'Next Level');
+ this.level++;
+ }
+ } else {
+ this.showModal('Game Over', 'Try again?', 'Restart Level');
+ this.revealMines();
+ }
+ }
+
+ revealMines() {
+ this.mines.forEach(({row, col}) => {
+ const cell = this.grid[row][col];
+ cell.element.classList.add('mine');
+ });
+ }
+
+ showModal(title, message, buttonText) {
+ this.modalTitle.textContent = title;
+ this.modalMessage.textContent = message;
+ this.modalButton.textContent = buttonText;
+ this.modal.style.display = 'flex';
+ }
+
+ hideModal() {
+ this.modal.style.display = 'none';
+ this.startLevel(this.level);
+ }
+
+ showHelp() {
+ this.showModal('How to Play',
+ 'Left click to reveal cells. Right click to flag mines. Avoid all mines to complete the level!',
+ 'Got it!'
+ );
+ }
+ }
+
+ window.addEventListener('load', () => {
+ new MinesweeperGame();
+ });