Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Classic Minesweeper</title> | |
| <style> | |
| :root { | |
| --cell-size: 40px; | |
| --cell-bg: #c0c0c0; | |
| --cell-border-light: #f0f0f0; | |
| --cell-border-dark: #808080; | |
| --cell-revealed: #b8b8b8; | |
| --mine-counter: #ff0000; | |
| --primary-color: #4682b4; | |
| --button-hover: #5f9ea0; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 100vh; | |
| background-color: #f5f5f5; | |
| padding: 20px; | |
| } | |
| .game-container { | |
| background-color: white; | |
| border-radius: 10px; | |
| box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); | |
| padding: 20px; | |
| text-align: center; | |
| } | |
| h1 { | |
| color: var(--primary-color); | |
| margin-bottom: 20px; | |
| font-size: 2.5rem; | |
| text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); | |
| } | |
| .game-info { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-bottom: 15px; | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 10px 20px; | |
| border-radius: 5px; | |
| font-weight: bold; | |
| } | |
| .counter, .timer { | |
| font-family: 'Courier New', monospace; | |
| font-size: 1.5rem; | |
| letter-spacing: 2px; | |
| } | |
| .board { | |
| display: grid; | |
| grid-template-columns: repeat(9, var(--cell-size)); | |
| grid-gap: 2px; | |
| margin: 0 auto 20px; | |
| border: 4px solid var(--cell-border-dark); | |
| border-radius: 5px; | |
| background-color: var(--cell-border-dark); | |
| } | |
| .cell { | |
| width: var(--cell-size); | |
| height: var(--cell-size); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-weight: bold; | |
| font-size: 1.2rem; | |
| background-color: var(--cell-bg); | |
| border-top: 3px solid var(--cell-border-light); | |
| border-left: 3px solid var(--cell-border-light); | |
| border-right: 3px solid var(--cell-border-dark); | |
| border-bottom: 3px solid var(--cell-border-dark); | |
| cursor: pointer; | |
| user-select: none; | |
| transition: all 0.1s ease; | |
| } | |
| .cell.revealed { | |
| background-color: var(--cell-revealed); | |
| border: 1px solid var(--cell-border-dark); | |
| } | |
| .cell.flagged::after { | |
| content: '🚩'; | |
| font-size: 0.8em; | |
| } | |
| .cell.mine::after { | |
| content: '💣'; | |
| } | |
| .cell.mine.revealed { | |
| background-color: #ffcccc; | |
| } | |
| .cell:hover:not(.revealed):not(.flagged) { | |
| background-color: #d8d8d8; | |
| } | |
| .number-1 { color: blue; } | |
| .number-2 { color: green; } | |
| .number-3 { color: red; } | |
| .number-4 { color: darkblue; } | |
| .number-5 { color: brown; } | |
| .number-6 { color: teal; } | |
| .number-7 { color: black; } | |
| .number-8 { color: gray; } | |
| .controls { | |
| margin-top: 10px; | |
| } | |
| button { | |
| background-color: var(--primary-color); | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-size: 1rem; | |
| font-weight: bold; | |
| transition: background-color 0.2s; | |
| } | |
| button:hover { | |
| background-color: var(--button-hover); | |
| } | |
| .message { | |
| margin-top: 15px; | |
| min-height: 24px; | |
| font-weight: bold; | |
| color: var(--primary-color); | |
| } | |
| @media (max-width: 500px) { | |
| :root { | |
| --cell-size: 30px; | |
| } | |
| h1 { | |
| font-size: 1.8rem; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="game-container"> | |
| <h1>Minesweeper</h1> | |
| <div class="game-info"> | |
| <div class="counter">💣 <span id="mines-count">10</span></div> | |
| <div class="timer">⏱ <span id="time">0</span>s</div> | |
| </div> | |
| <div class="board" id="board"></div> | |
| <div class="controls"> | |
| <button id="reset-btn">New Game</button> | |
| </div> | |
| <div class="message" id="message"></div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const SIZE = 9; | |
| const MINES_COUNT = 10; | |
| const board = document.getElementById('board'); | |
| const minesCountElement = document.getElementById('mines-count'); | |
| const timerElement = document.getElementById('time'); | |
| const resetBtn = document.getElementById('reset-btn'); | |
| const messageElement = document.getElementById('message'); | |
| let cells = []; | |
| let mines = []; | |
| let revealed = 0; | |
| let flagged = 0; | |
| let gameOver = false; | |
| let firstClick = true; | |
| let timer; | |
| let seconds = 0; | |
| function initGame() { | |
| // Reset game state | |
| board.innerHTML = ''; | |
| cells = []; | |
| mines = []; | |
| revealed = 0; | |
| flagged = 0; | |
| gameOver = false; | |
| firstClick = true; | |
| clearInterval(timer); | |
| seconds = 0; | |
| timerElement.textContent = '0'; | |
| minesCountElement.textContent = MINES_COUNT; | |
| messageElement.textContent = ''; | |
| // Create cells | |
| for (let row = 0; row < SIZE; row++) { | |
| cells[row] = []; | |
| for (let col = 0; col < SIZE; col++) { | |
| const cell = document.createElement('div'); | |
| cell.className = 'cell'; | |
| cell.dataset.row = row; | |
| cell.dataset.col = col; | |
| cell.addEventListener('click', () => handleCellClick(row, col)); | |
| cell.addEventListener('contextmenu', (e) => { | |
| e.preventDefault(); | |
| handleRightClick(row, col); | |
| }); | |
| board.appendChild(cell); | |
| cells[row][col] = { | |
| element: cell, | |
| mine: false, | |
| revealed: false, | |
| flagged: false, | |
| neighborMines: 0 | |
| }; | |
| } | |
| } | |
| } | |
| function startTimer() { | |
| clearInterval(timer); | |
| timer = setInterval(() => { | |
| seconds++; | |
| timerElement.textContent = seconds; | |
| }, 1000); | |
| } | |
| function placeMines(firstRow, firstCol) { | |
| let minesPlaced = 0; | |
| while (minesPlaced < MINES_COUNT) { | |
| const row = Math.floor(Math.random() * SIZE); | |
| const col = Math.floor(Math.random() * SIZE); | |
| // Don't place mine on first click cell or its neighbors | |
| const isFirstClickOrAdjacent = | |
| (row === firstRow && col === firstCol) || | |
| (Math.abs(row - firstRow) <= 1 && Math.abs(col - firstCol) <= 1); | |
| if (!cells[row][col].mine && !isFirstClickOrAdjacent) { | |
| cells[row][col].mine = true; | |
| mines.push({row, col}); | |
| minesPlaced++; | |
| } | |
| } | |
| // Calculate neighbor mines for each cell | |
| for (let row = 0; row < SIZE; row++) { | |
| for (let col = 0; col < SIZE; col++) { | |
| if (!cells[row][col].mine) { | |
| cells[row][col].neighborMines = countNeighborMines(row, col); | |
| } | |
| } | |
| } | |
| } | |
| function countNeighborMines(row, col) { | |
| let count = 0; | |
| for (let r = Math.max(0, row - 1); r <= Math.min(SIZE - 1, row + 1); r++) { | |
| for (let c = Math.max(0, col - 1); c <= Math.min(SIZE - 1, col + 1); c++) { | |
| if (cells[r][c].mine) { | |
| count++; | |
| } | |
| } | |
| } | |
| return count; | |
| } | |
| function handleCellClick(row, col) { | |
| if (gameOver || cells[row][col].flagged || cells[row][col].revealed) { | |
| return; | |
| } | |
| if (firstClick) { | |
| firstClick = false; | |
| placeMines(row, col); | |
| startTimer(); | |
| } | |
| revealCell(row, col); | |
| if (cells[row][col].mine) { | |
| gameOver = true; | |
| revealAllMines(); | |
| clearInterval(timer); | |
| messageElement.textContent = 'Game Over! You hit a mine.'; | |
| } else if (revealed === SIZE * SIZE - MINES_COUNT) { | |
| gameOver = true; | |
| flagAllMines(); | |
| clearInterval(timer); | |
| messageElement.textContent = 'Congratulations! You won!'; | |
| } | |
| } | |
| function revealCell(row, col) { | |
| if (row < 0 || row >= SIZE || col < 0 || col >= SIZE || | |
| cells[row][col].revealed || cells[row][col].flagged) { | |
| return; | |
| } | |
| cells[row][col].revealed = true; | |
| cells[row][col].element.classList.add('revealed'); | |
| revealed++; | |
| if (cells[row][col].neighborMines > 0) { | |
| cells[row][col].element.classList.add(`number-${cells[row][col].neighborMines}`); | |
| cells[row][col].element.textContent = cells[row][col].neighborMines; | |
| } else { | |
| // Reveal all adjacent cells if this is an empty cell | |
| for (let r = row - 1; r <= row + 1; r++) { | |
| for (let c = col - 1; c <= col + 1; c++) { | |
| if (r === row && c === col) continue; | |
| revealCell(r, c); | |
| } | |
| } | |
| } | |
| } | |
| function handleRightClick(row, col) { | |
| if (gameOver || cells[row][col].revealed) { | |
| return; | |
| } | |
| if (cells[row][col].flagged) { | |
| cells[row][col].flagged = false; | |
| cells[row][col].element.classList.remove('flagged'); | |
| flagged--; | |
| } else { | |
| cells[row][col].flagged = true; | |
| cells[row][col].element.classList.add('flagged'); | |
| flagged++; | |
| } | |
| minesCountElement.textContent = MINES_COUNT - flagged; | |
| return false; | |
| } | |
| function revealAllMines() { | |
| mines.forEach(mine => { | |
| const cell = cells[mine.row][mine.col]; | |
| if (!cell.flagged) { | |
| cell.revealed = true; | |
| cell.element.classList.add('revealed', 'mine'); | |
| } | |
| }); | |
| } | |
| function flagAllMines() { | |
| mines.forEach(mine => { | |
| const cell = cells[mine.row][mine.col]; | |
| if (!cell.flagged) { | |
| cell.flagged = true; | |
| cell.element.classList.add('flagged'); | |
| } | |
| }); | |
| } | |
| resetBtn.addEventListener('click', initGame); | |
| // Start the game | |
| initGame(); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
| </html> |