Created
June 3, 2026 18:11
-
-
Save senko/f7e54469906dde943805ccdc1ef16d7b to your computer and use it in GitHub Desktop.
Minesweeper by Gemma 4 12B Q4 - had to fix a few trivial syntax errors manually
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="=device-width, initial-scale=initial-scale=1.0"> | |
| <title>Modern Minesweeper</title> | |
| <style> | |
| :root { | |
| --bg-color: #eef2f3; | |
| --cell-bg: #d1d9de; | |
| --cell-border: #adb5bd; | |
| --cell-revealed: #ffffff; | |
| --primary-color: #2c3e50; | |
| --accent-color: #3498db; | |
| --danger-color: #e74c3c; | |
| --success-color: #2ecc71; | |
| --font-main: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background-color: var(--bg-color); | |
| font-family: var(--font-main); | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 100vh; | |
| margin: 0; | |
| } | |
| .game-container { | |
| background: white; | |
| padding: 2rem; | |
| border-radius: 15px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| text-align: center; | |
| } | |
| h1 { margin-bottom: 1rem; color: var(--primary-color); } | |
| .stats-bar { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-bottom: 1rem; | |
| font-weight: bold; | |
| font-size: 1.2rem; | |
| background: #f8f9fa; | |
| padding: 10px 20px; | |
| border-radius: 8px; | |
| } | |
| #grid { | |
| display: grid; | |
| gap: 4px; | |
| background-color: var(--cell-border); | |
| border: 4px solid var(--cell-border); | |
| border-radius: 4px; | |
| margin: 0 auto; | |
| } | |
| .cell { | |
| width: 30px; | |
| height: 30px; | |
| background-color: var(--cell-bg); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-weight: bold; | |
| cursor: pointer; | |
| user-select: none; | |
| transition: background 0.1s, transform 0.1s; | |
| border-radius: 2px; | |
| } | |
| .cell:hover:not(.revealed) { | |
| background-color: #bdc3c7; | |
| transform: scale(1.05); | |
| } | |
| .cell.revealed { | |
| background-color: var(--cell-revealed); | |
| cursor: default; | |
| transform: none; | |
| } | |
| .cell.mine { | |
| background-color: var(--danger-color) !important; | |
| } | |
| .cell.flagged::after { | |
| content: "🚩"; | |
| font-size: 14px; | |
| } | |
| .cell.revealed.n1 { color: blue; } | |
| .cell.revealed.n2 { color: green; } | |
| .cell.revealed.n3 { color: red; } | |
| .cell.revealed.n4 { color: darkblue; } | |
| .cell.revealed.n5 { color: brown; } | |
| .cell.revealed.n6 { color: cyan; } | |
| .cell.revealed.n7 { color: black; } | |
| .cell.revealed.n8 { color: grey; } | |
| .controls { | |
| margin-top: 1.5rem; | |
| display: flex; | |
| gap: 10px; | |
| justify-content: center; | |
| } | |
| button { | |
| padding: 10px 20px; | |
| border: none; | |
| border-radius: 5px; | |
| background: var(--accent-color); | |
| color: white; | |
| font-weight: bold; | |
| cursor: pointer; | |
| transition: opacity 0.2s; | |
| } | |
| button:hover { opacity: 0.8; } | |
| select { | |
| padding: 10px; | |
| border-radius: 5px; | |
| border: 1px solid var(--cell-border); | |
| } | |
| .game-over { | |
| position: fixed; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(0,0,0,0.8); | |
| color: white; | |
| padding: 2rem; | |
| border-radius: 10px; | |
| display: none; | |
| z-index: 10; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="game-container"> | |
| <h1>Minesweeper</h1> | |
| <div class="stats-bar"> | |
| <div>💣 <span id="mine-count">0</span></div> | |
| <div>⏱️ <span id="timer">000</span></div> | |
| </div> | |
| <div id="grid"></div> | |
| <div class="controls"> | |
| <select id="difficulty"> | |
| <option value="easy">Easy (10x10, 10 Mines)</option> | |
| <option value="medium"> Medium (15x15, 30 Mines)</option> | |
| <option value="hard"> Hard (20x20, 60 Mines)</option> | |
| </select> | |
| <button id="reset-btn">New Game</button> | |
| </div> | |
| </div> | |
| <div id="overlay" class="game-over"> | |
| <h2 id="status-msg">Game Over</h2> | |
| <button onclick="resetGame()">Play Again</button> | |
| </div> | |
| <script> | |
| const gridElement = document.getElementById('grid'); | |
| const mineCountElement = document.getElementById('mine-count'); | |
| const timerElement = document.getElementById('timer'); | |
| const resetBtn = document.getElementById('reset-btn'); | |
| const difficultySelect = document.getElementById('difficulty'); | |
| const overlay = document.getElementById('overlay'); | |
| const statusMsg = document.getElementById('status-msg'); | |
| let board = []; | |
| let mines = 0; | |
| let rows, cols; | |
| let revealedCount = 0; | |
| let timerInterval = null; | |
| let seconds = 0; | |
| let gameOver = false; | |
| const configs = { | |
| easy: { r: 10, c: 10, m: 10 }, | |
| medium: { r: 15, c: 15, m: 30 }, | |
| hard: { r: 20, c: 20, m: 60 } | |
| }; | |
| function initGame() { | |
| gameOver = false; | |
| revealedCount = 0; | |
| seconds = 0; | |
| clearInterval(timerInterval); | |
| timerElement.innerText = "000"; | |
| overlay.style.display = "none"; | |
| const config = configs[difficultySelect.value]; | |
| rows = config.r; | |
| cols = config.c; | |
| mines = config.m; | |
| mineCountElement.innerText = mines; | |
| // Setup Grid CSS | |
| gridElement.style.gridTemplateColumns = `repeat(${cols}, 30px)`; | |
| gridElement.innerHTML = ''; | |
| // Initialize Board Array | |
| board = []; | |
| for (let r = 0; r < rows; r++) { | |
| board[r] = []; | |
| for (let c = 0; c < cols; c++) { | |
| const cell = { | |
| r, c, | |
| mine: false, | |
| revealed: false, | |
| flagged: false, | |
| neighborCount: 0, | |
| element: null | |
| }; | |
| board[r][c] = cell; | |
| } | |
| } | |
| // Place Mines | |
| let placed = 0; | |
| while (placed < mines) { | |
| let r = Math.floor(Math.random() * rows); | |
| let c = Math.floor(Math.random() * cols); | |
| if (!board[r][c].mine) { | |
| board[r][c].mine = true; | |
| placed++; | |
| } | |
| } | |
| // Calculate Neighbors | |
| for (let r = 0; r < rows; r++) { | |
| for (let c = 0; c < cols; c++) { | |
| if (!board[r][c].mine) { | |
| let count = 0; | |
| for (let dr = -1; dr <= 1; dr++) { | |
| for (let dc = -1; dc <= 1; dc++) { | |
| let nr = r + dr; | |
| let nc = c + dc; | |
| if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) { | |
| if (board[nr][nc].mine) count++; | |
| } | |
| } | |
| } | |
| board[r][c].neighborCount = count; | |
| } | |
| } | |
| } | |
| // Create DOM Elements | |
| for (let r = 0; r < rows; r++) { | |
| for (let c = 0; c < cols; c++) { | |
| const cellObj = board[r][c]; | |
| const div = document.createElement('div'); | |
| div.classList.add('cell'); | |
| div.addEventListener('click', (e) => handleLeftClick(r, c)); | |
| div.addEventListener('contextmenu', (e) => { | |
| e.preventDefault(); | |
| handleRightClick(r, c); | |
| }); | |
| cellObj.element = div; | |
| gridElement.appendChild(div); | |
| } | |
| } | |
| startTimer(); | |
| } | |
| function startTimer() { | |
| timerInterval = setInterval(() => { | |
| seconds++; | |
| timerElement.innerText = String(seconds).padStart(3, '0'); | |
| }, 1000); | |
| } | |
| function handleLeftClick(r, c) { | |
| if (gameOver || board[r][c].flagged || board[r][c].revealed) return; | |
| if (board[r][c].mine) { | |
| revealAllMines(); | |
| endGame(false); | |
| return; | |
| } | |
| revealCell(r, c); | |
| checkWin(); | |
| } | |
| function handleRightClick(r, c) { | |
| if (gameOver || board[r][c].revealed) return; | |
| const cell = board[r][c]; | |
| cell.flagged = !cell.flagged; | |
| cell.element.classList.toggle('flagged', cell.flagged); | |
| const currentFlags = document.querySelectorAll('.flagged').length; | |
| mineCountElement.innerText = mines - currentFlags; | |
| } | |
| function revealCell(r, c) { | |
| const cell = board[r][c]; | |
| if (cell.revealed || cell.flagged) return; | |
| cell.revealed = true; | |
| cell.element.classList.add('revealed'); | |
| revealedCount++; | |
| if (cell.mine) { | |
| cell.element.classList.add('mine'); | |
| return; | |
| } | |
| if (cell.neighborCount > 0) { | |
| cell.element.innerText = cell.neighborCount; | |
| cell.element.classList.add(`n${cell.neighborCount}`); | |
| } else { | |
| // Flood fill | |
| for (let dr = -1; dr <= 1; dr++) { | |
| for (let dc = -1; dc <= 1; dc++) { | |
| let nr = r + dr; | |
| let nc = c + dc; | |
| if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) { | |
| revealCell(nr, nc); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| function revealAllMines() { | |
| for (let r = 0; r < rows; r++) { | |
| for (let c = 0; c < cols; c++) { | |
| if (board[r][c].mine) { | |
| board[r][c].element.classList.add('mine'); | |
| board[r][c].element.classList.add('revealed'); | |
| } | |
| } | |
| } | |
| } | |
| function checkWin() { | |
| if (revealedCount === (rows * cols) - mines) { | |
| endGame(true); | |
| } | |
| } | |
| function endGame(win) { | |
| gameOver = true; | |
| clearInterval(timerInterval); | |
| statusMsg.innerText = win ? "YOU WIN! 🎉" : "GAME OVER 💥"; | |
| statusMsg.style.color = win ? "var(--success-color)" : "var(--danger-color)"; | |
| overlay.style.display = "block"; | |
| } | |
| function resetGame() { | |
| initGame(); | |
| } | |
| resetBtn.addEventListener('click', resetGame); | |
| difficultySelect.addEventListener('change', resetGame); | |
| // Start initial game | |
| initGame(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment