Skip to content

Instantly share code, notes, and snippets.

@senko
Created July 23, 2025 11:17
Show Gist options
  • Save senko/0914a98bd7b946a395a7b051d8798622 to your computer and use it in GitHub Desktop.
Save senko/0914a98bd7b946a395a7b051d8798622 to your computer and use it in GitHub Desktop.
Qwen3-coder single-shotting Minesweeper
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minesweeper</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
padding: 20px;
}
.game-container {
background-color: #2c3e50;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
padding: 20px;
text-align: center;
max-width: 500px;
width: 100%;
}
h1 {
color: #ecf0f1;
margin-bottom: 15px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.stats {
display: flex;
justify-content: space-between;
background-color: #34495e;
padding: 12px 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3);
}
.stat-box {
background-color: #2c3e50;
color: #ecf0f1;
padding: 8px 15px;
border-radius: 5px;
font-weight: bold;
min-width: 80px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.stat-value {
font-size: 24px;
color: #f1c40f;
}
.controls {
margin: 15px 0;
}
button {
background: linear-gradient(to bottom, #3498db, #2980b9);
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
transition: all 0.2s;
}
button:hover {
background: linear-gradient(to bottom, #3cb0fd, #3498db);
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.3);
}
button:active {
transform: translateY(1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.difficulty {
display: flex;
justify-content: center;
gap: 10px;
margin: 15px 0;
}
.difficulty button {
padding: 8px 15px;
font-size: 14px;
}
.board {
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 4px;
margin: 0 auto;
max-width: 400px;
}
.cell {
aspect-ratio: 1;
background: linear-gradient(to bottom right, #3498db, #2980b9);
border-radius: 3px;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
font-size: 18px;
cursor: pointer;
user-select: none;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: all 0.1s;
}
.cell:hover {
background: linear-gradient(to bottom right, #3cb0fd, #3498db);
}
.cell.revealed {
background: #bdc3c7;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
}
.cell.flagged::before {
content: "🚩";
}
.cell.mine.revealed {
background: #e74c3c;
}
.cell.mine.revealed::before {
content: "💣";
}
.number-1 { color: #3498db; }
.number-2 { color: #2ecc71; }
.number-3 { color: #e74c3c; }
.number-4 { color: #9b59b6; }
.number-5 { color: #e67e22; }
.number-6 { color: #1abc9c; }
.number-7 { color: #34495e; }
.number-8 { color: #7f8c8d; }
.instructions {
background-color: #34495e;
color: #ecf0f1;
padding: 15px;
border-radius: 8px;
margin-top: 20px;
text-align: left;
font-size: 14px;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.3);
}
.instructions h3 {
margin-bottom: 10px;
color: #f1c40f;
}
.instructions ul {
padding-left: 20px;
}
.instructions li {
margin-bottom: 8px;
}
.game-over {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.game-over.show {
opacity: 1;
pointer-events: all;
}
.game-over-content {
background: #2c3e50;
padding: 30px;
border-radius: 10px;
text-align: center;
max-width: 90%;
width: 400px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.game-over h2 {
color: #ecf0f1;
margin-bottom: 20px;
}
.win {
color: #2ecc71;
}
.lose {
color: #e74c3c;
}
@media (max-width: 500px) {
.board {
grid-template-columns: repeat(10, 1fr);
gap: 2px;
}
.cell {
font-size: 14px;
}
.stat-box {
padding: 6px 10px;
min-width: 70px;
}
.stat-value {
font-size: 20px;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>MINESWEEPER</h1>
<div class="stats">
<div class="stat-box">
<div>MINES</div>
<div id="mine-count" class="stat-value">15</div>
</div>
<div class="stat-box">
<div>FLAGS</div>
<div id="flag-count" class="stat-value">0</div>
</div>
<div class="stat-box">
<div>TIME</div>
<div id="timer" class="stat-value">0</div>
</div>
</div>
<div class="controls">
<button id="reset-btn">New Game</button>
</div>
<div class="difficulty">
<button id="easy-btn">Easy</button>
<button id="medium-btn">Medium</button>
<button id="hard-btn">Hard</button>
</div>
<div id="board" class="board"></div>
<div class="instructions">
<h3>How to Play:</h3>
<ul>
<li><strong>Left-click</strong> to reveal a cell</li>
<li><strong>Right-click</strong> to place/remove a flag</li>
<li>Numbers indicate how many mines are adjacent</li>
<li>Reveal all non-mine cells to win the game</li>
<li>Flag all mines to win faster!</li>
</ul>
</div>
</div>
<div id="game-over" class="game-over">
<div class="game-over-content">
<h2 id="game-result">Game Over</h2>
<p id="result-message">You clicked on a mine!</p>
<button id="play-again">Play Again</button>
</div>
</div>
<script>
// Game configuration
const config = {
easy: { rows: 10, cols: 10, mines: 15 },
medium: { rows: 14, cols: 14, mines: 35 },
hard: { rows: 18, cols: 18, mines: 70 }
};
// Game state
let gameState = {
board: [],
minePositions: [],
revealedCount: 0,
flaggedCount: 0,
gameOver: false,
gameWon: false,
firstClick: true,
timer: 0,
timerInterval: null,
difficulty: 'easy'
};
// DOM elements
const boardElement = document.getElementById('board');
const mineCountElement = document.getElementById('mine-count');
const flagCountElement = document.getElementById('flag-count');
const timerElement = document.getElementById('timer');
const resetButton = document.getElementById('reset-btn');
const easyButton = document.getElementById('easy-btn');
const mediumButton = document.getElementById('medium-btn');
const hardButton = document.getElementById('hard-btn');
const gameOverElement = document.getElementById('game-over');
const gameResultElement = document.getElementById('game-result');
const resultMessageElement = document.getElementById('result-message');
const playAgainButton = document.getElementById('play-again');
// Initialize the game
function initGame() {
const { rows, cols, mines } = config[gameState.difficulty];
// Reset game state
gameState.board = [];
gameState.minePositions = [];
gameState.revealedCount = 0;
gameState.flaggedCount = 0;
gameState.gameOver = false;
gameState.gameWon = false;
gameState.firstClick = true;
gameState.timer = 0;
// Clear the board
boardElement.innerHTML = '';
boardElement.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
// Update mine count display
mineCountElement.textContent = mines;
flagCountElement.textContent = '0';
timerElement.textContent = '0';
// Clear any existing timer
if (gameState.timerInterval) {
clearInterval(gameState.timerInterval);
gameState.timerInterval = null;
}
// Hide game over screen
gameOverElement.classList.remove('show');
// Create the board
for (let row = 0; row < rows; row++) {
gameState.board[row] = [];
for (let col = 0; col < cols; col++) {
gameState.board[row][col] = {
isMine: false,
isRevealed: false,
isFlagged: false,
adjacentMines: 0
};
// Create cell element
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.row = row;
cell.dataset.col = col;
// Add event listeners
cell.addEventListener('click', () => handleCellClick(row, col));
cell.addEventListener('contextmenu', (e) => {
e.preventDefault();
handleRightClick(row, col);
});
boardElement.appendChild(cell);
}
}
}
// Place mines on the board (avoiding the first clicked cell)
function placeMines(firstRow, firstCol) {
const { rows, cols, mines } = config[gameState.difficulty];
const totalCells = rows * cols;
const minePositions = [];
// Create array of all possible positions
const positions = [];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
// Don't place mine on first clicked cell or adjacent cells
if (Math.abs(row - firstRow) <= 1 && Math.abs(col - firstCol) <= 1) {
continue;
}
positions.push({ row, col });
}
}
// Shuffle positions and select mines
for (let i = positions.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[positions[i], positions[j]] = [positions[j], positions[i]];
}
// Place mines
for (let i = 0; i < mines; i++) {
const { row, col } = positions[i];
gameState.board[row][col].isMine = true;
minePositions.push({ row, col });
}
gameState.minePositions = minePositions;
// Calculate adjacent mines for each cell
calculateAdjacentMines();
}
// Calculate adjacent mines for each cell
function calculateAdjacentMines() {
const { rows, cols } = config[gameState.difficulty];
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
if (gameState.board[row][col].isMine) continue;
let count = 0;
// Check all 8 adjacent cells
for (let r = Math.max(0, row - 1); r <= Math.min(rows - 1, row + 1); r++) {
for (let c = Math.max(0, col - 1); c <= Math.min(cols - 1, col + 1); c++) {
if (gameState.board[r][c].isMine) {
count++;
}
}
}
gameState.board[row][col].adjacentMines = count;
}
}
}
// Handle cell click
function handleCellClick(row, col) {
// Ignore if game is over or cell is flagged
if (gameState.gameOver || gameState.board[row][col].isFlagged) return;
const cell = gameState.board[row][col];
// First click - place mines and start timer
if (gameState.firstClick) {
gameState.firstClick = false;
placeMines(row, col);
startTimer();
}
// If it's a mine, game over
if (cell.isMine) {
revealMines();
endGame(false);
return;
}
// Reveal the cell
revealCell(row, col);
// Check for win
checkWin();
}
// Handle right click (flag placement)
function handleRightClick(row, col) {
// Ignore if game is over or cell is revealed
if (gameState.gameOver || gameState.board[row][col].isRevealed) return;
const cell = gameState.board[row][col];
const cellElement = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
// Toggle flag
if (cell.isFlagged) {
cell.isFlagged = false;
gameState.flaggedCount--;
cellElement.classList.remove('flagged');
} else {
// Don't allow more flags than mines
if (gameState.flaggedCount >= config[gameState.difficulty].mines) return;
cell.isFlagged = true;
gameState.flaggedCount++;
cellElement.classList.add('flagged');
}
// Update flag count display
flagCountElement.textContent = gameState.flaggedCount;
// Check for win
checkWin();
}
// Reveal a cell and adjacent cells if empty
function revealCell(row, col) {
const { rows, cols } = config[gameState.difficulty];
const cell = gameState.board[row][col];
// Ignore if already revealed or flagged
if (cell.isRevealed || cell.isFlagged) return;
// Mark as revealed
cell.isRevealed = true;
gameState.revealedCount++;
// Update cell display
const cellElement = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
cellElement.classList.add('revealed');
// If it's an empty cell, reveal adjacent cells
if (cell.adjacentMines === 0) {
cellElement.textContent = '';
// Reveal all adjacent cells
for (let r = Math.max(0, row - 1); r <= Math.min(rows - 1, row + 1); r++) {
for (let c = Math.max(0, col - 1); c <= Math.min(cols - 1, col + 1); c++) {
if (r === row && c === col) continue;
revealCell(r, c);
}
}
} else {
// Show the number of adjacent mines
cellElement.textContent = cell.adjacentMines;
cellElement.classList.add(`number-${cell.adjacentMines}`);
}
}
// Reveal all mines (when game is lost)
function revealMines() {
gameState.minePositions.forEach(({ row, col }) => {
const cell = gameState.board[row][col];
if (!cell.isRevealed) {
cell.isRevealed = true;
const cellElement = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
cellElement.classList.add('revealed', 'mine');
}
});
}
// Start the game timer
function startTimer() {
gameState.timer = 0;
timerElement.textContent = gameState.timer;
gameState.timerInterval = setInterval(() => {
gameState.timer++;
timerElement.textContent = gameState.timer;
}, 1000);
}
// Check if the player has won
function checkWin() {
const { rows, cols, mines } = config[gameState.difficulty];
const totalCells = rows * cols;
// Win condition: all non-mine cells are revealed
if (gameState.revealedCount === totalCells - mines) {
endGame(true);
}
// Alternative win condition: all mines are flagged and all other cells are revealed
if (gameState.flaggedCount === mines) {
let allFlaggedAreMines = true;
let allNonMinesRevealed = true;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const cell = gameState.board[row][col];
if (cell.isFlagged && !cell.isMine) {
allFlaggedAreMines = false;
}
if (!cell.isFlagged && !cell.isRevealed && !cell.isMine) {
allNonMinesRevealed = false;
}
}
}
if (allFlaggedAreMines && allNonMinesRevealed) {
endGame(true);
}
}
}
// End the game
function endGame(isWin) {
gameState.gameOver = true;
gameState.gameWon = isWin;
// Stop the timer
if (gameState.timerInterval) {
clearInterval(gameState.timerInterval);
gameState.timerInterval = null;
}
// Show game over screen
setTimeout(() => {
if (isWin) {
gameResultElement.textContent = 'You Win!';
gameResultElement.className = 'win';
resultMessageElement.textContent = `Congratulations! You found all mines in ${gameState.timer} seconds.`;
} else {
gameResultElement.textContent = 'Game Over!';
gameResultElement.className = 'lose';
resultMessageElement.textContent = 'You clicked on a mine!';
}
gameOverElement.classList.add('show');
}, 500);
}
// Set difficulty
function setDifficulty(difficulty) {
gameState.difficulty = difficulty;
initGame();
}
// Event listeners
resetButton.addEventListener('click', () => initGame());
easyButton.addEventListener('click', () => setDifficulty('easy'));
mediumButton.addEventListener('click', () => setDifficulty('medium'));
hardButton.addEventListener('click', () => setDifficulty('hard'));
playAgainButton.addEventListener('click', () => {
gameOverElement.classList.remove('show');
initGame();
});
// Initialize the game
initGame();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment