726 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			726 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html lang="de">
 | |
| <head>
 | |
|     <meta charset="UTF-8">
 | |
|     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | |
|     <title>Minesweeper | PonyWave Tools</title>
 | |
|     <meta property="og:title" content="Minesweeper | PonyWave Tools">
 | |
|     <meta property="og:description" content="Klassisches Minesweeper-Spiel mit verschiedenen Schwierigkeitsgraden">
 | |
|     <meta property="og:type" content="website">
 | |
|     <meta property="og:url" content="https://tools.ponywave.de/minesweeper">
 | |
|     <meta property="og:image" content="https://tools.ponywave.de/minesweeper/icon.png">
 | |
|     
 | |
|     <!-- Favicons -->
 | |
|     <link rel="icon" type="image/png" href="https://tools.ponywave.de/minesweeper/icon.png">
 | |
|     <link rel="shortcut icon" href="https://tools.ponywave.de/minesweeper/icon.png">
 | |
|     <link rel="apple-touch-icon" href="https://tools.ponywave.de/minesweeper/icon.png">
 | |
|     <link rel="icon" sizes="192x192" href="https://tools.ponywave.de/minesweeper/icon.png">
 | |
| 
 | |
|     <!-- Umami Tracking -->
 | |
|     <script defer src="https://stats.ponywave.de/script" data-website-id="9ef713d2-adb9-4906-9df5-708d8a8b9131" data-tag="minesweeper"></script>
 | |
|     
 | |
|     <style>
 | |
|         :root {
 | |
|             --primary-color: #7F006E;
 | |
|             --secondary-color: #FF7FED;
 | |
|             --bg-gradient: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
 | |
|             --text-color: #2c3e50;
 | |
|             --cell-size: 30px;
 | |
|             --board-bg: #c0c0c0;
 | |
|             --cell-bg: #c0c0c0;
 | |
|             --cell-border: #808080;
 | |
|             --cell-revealed: #d9d9d9;
 | |
|             --font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 | |
|             --shadow-color: rgba(0, 0, 0, 0.1);
 | |
|             --footer-color: rgba(255, 255, 255, 0.8);
 | |
|             --button-bg: #f0f0f0;
 | |
|             --button-hover: #e0e0e0;
 | |
|             --button-active: #d0d0d0;
 | |
|         }
 | |
| 
 | |
|         .dark-mode {
 | |
|             --bg-gradient: linear-gradient(135deg, #4A0040 0%, #CC65B5 100%);
 | |
|             --text-color: #ffffff;
 | |
|             --board-bg: #444444;
 | |
|             --cell-bg: #555555;
 | |
|             --cell-border: #666666;
 | |
|             --cell-revealed: #333333;
 | |
|             --button-bg: #555555;
 | |
|             --button-hover: #666666;
 | |
|             --button-active: #777777;
 | |
|             --shadow-color: rgba(0, 0, 0, 0.3);
 | |
|             --footer-color: rgba(0, 0, 0, 0.8);
 | |
|         }
 | |
| 
 | |
|         body {
 | |
|             font-family: var(--font-family);
 | |
|             background-color: var(--board-bg);
 | |
|             background-image: none;
 | |
|             color: var(--text-color);
 | |
|             margin: 0;
 | |
|             padding: 20px 20px 60px;
 | |
|             min-height: 100vh;
 | |
|             position: relative;
 | |
|             line-height: 1.6;
 | |
|             text-align: center;
 | |
|         }
 | |
| 
 | |
|         .dark-mode body {
 | |
|             background-image: none;
 | |
|             background-color: #444444;
 | |
|         }
 | |
| 
 | |
|         .theme-toggle {
 | |
|             position: fixed;
 | |
|             top: 20px;
 | |
|             right: 20px;
 | |
|             background: var(--button-bg);
 | |
|             border: none;
 | |
|             border-radius: 50%;
 | |
|             width: 40px;
 | |
|             height: 40px;
 | |
|             cursor: pointer;
 | |
|             box-shadow: 0 2px 4px var(--shadow-color);
 | |
|             display: flex;
 | |
|             align-items: center;
 | |
|             justify-content: center;
 | |
|             font-size: 1.2em;
 | |
|             transition: all 0.3s ease;
 | |
|             z-index: 10;
 | |
|         }
 | |
| 
 | |
|         .theme-toggle:hover {
 | |
|             transform: scale(1.1);
 | |
|         }
 | |
| 
 | |
|         h1 {
 | |
|             margin: 20px 0;
 | |
|             color: var(--text-color);
 | |
|             text-shadow: 2px 2px 4px var(--shadow-color);
 | |
|         }
 | |
| 
 | |
|         .game-container {
 | |
|             display: flex;
 | |
|             flex-direction: column;
 | |
|             align-items: center;
 | |
|             justify-content: center;
 | |
|             margin: 20px auto;
 | |
|             max-width: 800px;
 | |
|             background: rgba(255, 255, 255, 0.9);
 | |
|             padding: 20px;
 | |
|             border-radius: 15px;
 | |
|             box-shadow: 0 4px 6px var(--shadow-color);
 | |
|             backdrop-filter: blur(5px);
 | |
|             overflow-x: hidden;
 | |
|             width: 90%;
 | |
|         }
 | |
| 
 | |
|         .dark-mode .game-container {
 | |
|             background: rgba(45, 45, 45, 0.9);
 | |
|         }
 | |
| 
 | |
|         .game-header {
 | |
|             display: flex;
 | |
|             width: 100%;
 | |
|             justify-content: space-between;
 | |
|             align-items: center;
 | |
|             margin-bottom: 20px;
 | |
|         }
 | |
| 
 | |
|         .counter {
 | |
|             background: #000;
 | |
|             color: #f00;
 | |
|             font-family: 'Digital', monospace;
 | |
|             padding: 5px 10px;
 | |
|             border-radius: 3px;
 | |
|             font-size: 1.5em;
 | |
|             min-width: 80px;
 | |
|             text-align: center;
 | |
|             box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
 | |
|         }
 | |
| 
 | |
|         .smiley {
 | |
|             width: 40px;
 | |
|             height: 40px;
 | |
|             background: var(--button-bg);
 | |
|             border: 2px outset var(--cell-border);
 | |
|             border-radius: 50%;
 | |
|             display: flex;
 | |
|             align-items: center;
 | |
|             justify-content: center;
 | |
|             font-size: 1.5em;
 | |
|             cursor: pointer;
 | |
|             user-select: none;
 | |
|         }
 | |
| 
 | |
|         .smiley:active {
 | |
|             border-style: inset;
 | |
|         }
 | |
| 
 | |
|         .difficulty {
 | |
|             display: flex;
 | |
|             gap: 10px;
 | |
|             margin-bottom: 20px;
 | |
|         }
 | |
| 
 | |
|         .difficulty button {
 | |
|             padding: 8px 15px;
 | |
|             background: var(--button-bg);
 | |
|             border: 1px solid var(--cell-border);
 | |
|             border-radius: 5px;
 | |
|             cursor: pointer;
 | |
|             transition: all 0.2s;
 | |
|             font-family: var(--font-family);
 | |
|         }
 | |
| 
 | |
|         .difficulty button:hover {
 | |
|             background: var(--button-hover);
 | |
|         }
 | |
| 
 | |
|         .difficulty button.active {
 | |
|             background: var(--primary-color);
 | |
|             color: white;
 | |
|         }
 | |
| 
 | |
|         .minesweeper-board {
 | |
|             display: grid;
 | |
|             background: var(--board-bg);
 | |
|             border: 3px solid var(--cell-border);
 | |
|             box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
 | |
|             margin: 0 auto;
 | |
|             user-select: none;
 | |
|             max-width: 100%;
 | |
|         }
 | |
| 
 | |
|         .cell {
 | |
|             width: var(--cell-size);
 | |
|             height: var(--cell-size);
 | |
|             background: var(--cell-bg);
 | |
|             border: 2px outset var(--cell-border);
 | |
|             display: flex;
 | |
|             align-items: center;
 | |
|             justify-content: center;
 | |
|             font-weight: bold;
 | |
|             font-size: 1.1em;
 | |
|             cursor: pointer;
 | |
|             transition: background-color 0.1s;
 | |
|         }
 | |
| 
 | |
|         .cell.revealed {
 | |
|             background: var(--cell-revealed);
 | |
|             border: 1px solid var(--cell-border);
 | |
|         }
 | |
| 
 | |
|         .cell.flagged::before {
 | |
|             content: "🚩";
 | |
|         }
 | |
| 
 | |
|         .cell.mine-clicked {
 | |
|             background: red;
 | |
|         }
 | |
| 
 | |
|         .cell.mine::before {
 | |
|             content: "💣";
 | |
|         }
 | |
| 
 | |
|         .cell.number-1 { color: blue; }
 | |
|         .cell.number-2 { color: green; }
 | |
|         .cell.number-3 { color: red; }
 | |
|         .cell.number-4 { color: darkblue; }
 | |
|         .cell.number-5 { color: brown; }
 | |
|         .cell.number-6 { color: teal; }
 | |
|         .cell.number-7 { color: black; }
 | |
|         .cell.number-8 { color: gray; }
 | |
| 
 | |
|         .instructions {
 | |
|             margin: 20px auto;
 | |
|             max-width: 600px;
 | |
|             text-align: left;
 | |
|             padding: 15px;
 | |
|             background: rgba(255, 255, 255, 0.8);
 | |
|             border-radius: 10px;
 | |
|             box-shadow: 0 2px 5px var(--shadow-color);
 | |
|         }
 | |
| 
 | |
|         .dark-mode .instructions {
 | |
|             background: rgba(45, 45, 45, 0.8);
 | |
|         }
 | |
| 
 | |
|         footer {
 | |
|             position: fixed;
 | |
|             bottom: 0;
 | |
|             left: 0;
 | |
|             right: 0;
 | |
|             padding: 15px;
 | |
|             text-align: center;
 | |
|             font-size: 0.9em;
 | |
|             background: var(--footer-color);
 | |
|             backdrop-filter: blur(5px);
 | |
|             z-index: 10;
 | |
|         }
 | |
| 
 | |
|         footer a {
 | |
|             color: var(--primary-color);
 | |
|             text-decoration: none;
 | |
|             font-weight: 500;
 | |
|             transition: opacity 0.3s ease;
 | |
|         }
 | |
| 
 | |
|         footer a:hover {
 | |
|             opacity: 0.8;
 | |
|             text-decoration: underline;
 | |
|         }
 | |
| 
 | |
|         @media (max-width: 600px) {
 | |
|             :root {
 | |
|                 --cell-size: 25px;
 | |
|             }
 | |
|             
 | |
|             .game-container {
 | |
|                 padding: 10px;
 | |
|             }
 | |
|             
 | |
|             .counter {
 | |
|                 font-size: 1.2em;
 | |
|                 min-width: 60px;
 | |
|             }
 | |
|             
 | |
|             .smiley {
 | |
|                 width: 35px;
 | |
|                 height: 35px;
 | |
|             }
 | |
|             
 | |
|             .difficulty button {
 | |
|                 padding: 6px 10px;
 | |
|                 font-size: 0.9em;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         @media (max-width: 400px) {
 | |
|             :root {
 | |
|                 --cell-size: 20px;
 | |
|             }
 | |
|         }
 | |
|     </style>
 | |
| </head>
 | |
| <body>
 | |
|     <button class="theme-toggle" onclick="toggleTheme()">🌙</button>
 | |
|     
 | |
|     <h1>Minesweeper</h1>
 | |
|     
 | |
|     <div class="game-container">
 | |
|         <div class="game-header">
 | |
|             <div class="counter" id="mines-counter">000</div>
 | |
|             <div class="smiley" id="smiley">😊</div>
 | |
|             <div class="counter" id="timer">000</div>
 | |
|         </div>
 | |
|         
 | |
|         <div class="difficulty">
 | |
|             <button data-level="beginner" class="active">Anfänger (9x9)</button>
 | |
|             <button data-level="intermediate">Fortgeschritten (16x16)</button>
 | |
|             <button data-level="expert">Experte (30x16)</button>
 | |
|         </div>
 | |
|         
 | |
|         <div class="minesweeper-board" id="board"></div>
 | |
|     </div>
 | |
|     
 | |
|     <div class="instructions">
 | |
|         <h3>Anleitung:</h3>
 | |
|         <p><strong>Ziel des Spiels:</strong> Finde alle Minen auf dem Spielfeld, ohne eine zu aktivieren.</p>
 | |
|         <p><strong>Steuerung:</strong></p>
 | |
|         <ul>
 | |
|             <li><strong>Linksklick:</strong> Feld aufdecken</li>
 | |
|             <li><strong>Rechtsklick:</strong> Flagge setzen/entfernen</li>
 | |
|             <li><strong>Doppelklick auf aufgedecktes Feld:</strong> Umgebende Felder aufdecken, wenn entsprechende Anzahl Flaggen gesetzt ist</li>
 | |
|         </ul>
 | |
|         <p><strong>Zahlen:</strong> Zeigen an, wie viele Minen in den umliegenden 8 Feldern versteckt sind.</p>
 | |
|     </div>
 | |
| 
 | |
|     <footer>
 | |
|         <div>
 | |
|              <a href="https://tools.ponywave.de/">Zurück zur Startseite</a> | 
 | |
|              © <span id="currentYear"></span> Akamaru | 
 | |
|              Made with ❤️ by Claude
 | |
|         </div>
 | |
|     </footer>
 | |
| 
 | |
|     <script>
 | |
|         // Spielkonfiguration
 | |
|         const levels = {
 | |
|             beginner: { rows: 9, cols: 9, mines: 10 },
 | |
|             intermediate: { rows: 16, cols: 16, mines: 40 },
 | |
|             expert: { rows: 16, cols: 30, mines: 99 }
 | |
|         };
 | |
| 
 | |
|         let currentLevel = 'beginner';
 | |
|         let boardData = [];
 | |
|         let gameOver = false;
 | |
|         let gameStarted = false;
 | |
|         let timeInterval;
 | |
|         let startTime;
 | |
|         let flagCount = 0;
 | |
| 
 | |
|         // DOM-Elemente
 | |
|         const board = document.getElementById('board');
 | |
|         const smiley = document.getElementById('smiley');
 | |
|         const minesCounter = document.getElementById('mines-counter');
 | |
|         const timerElement = document.getElementById('timer');
 | |
|         const difficultyButtons = document.querySelectorAll('.difficulty button');
 | |
| 
 | |
|         // Event-Listener
 | |
|         difficultyButtons.forEach(button => {
 | |
|             button.addEventListener('click', (e) => {
 | |
|                 currentLevel = e.target.dataset.level;
 | |
|                 difficultyButtons.forEach(btn => btn.classList.remove('active'));
 | |
|                 e.target.classList.add('active');
 | |
|                 initGame();
 | |
|             });
 | |
|         });
 | |
| 
 | |
|         smiley.addEventListener('click', initGame);
 | |
| 
 | |
|         // Initialisieren des Spiels
 | |
|         function initGame() {
 | |
|             clearInterval(timeInterval);
 | |
|             gameOver = false;
 | |
|             gameStarted = false;
 | |
|             flagCount = 0;
 | |
|             smiley.textContent = '😊';
 | |
|             timerElement.textContent = '000';
 | |
|             
 | |
|             const { rows, cols, mines } = levels[currentLevel];
 | |
|             
 | |
|             // Brett erstellen
 | |
|             board.style.gridTemplateColumns = `repeat(${cols}, var(--cell-size))`;
 | |
|             board.style.gridTemplateRows = `repeat(${rows}, var(--cell-size))`;
 | |
|             board.innerHTML = '';
 | |
|             
 | |
|             // Zellengröße anpassen im Experten-Modus
 | |
|             if (currentLevel === 'expert') {
 | |
|                 const gameContainer = document.querySelector('.game-container');
 | |
|                 const containerWidth = gameContainer.clientWidth - 40; // Container-Breite abzüglich Padding
 | |
|                 const cellSize = Math.max(15, Math.floor(containerWidth / cols)); // Minimalgröße 15px
 | |
|                 document.documentElement.style.setProperty('--cell-size', `${cellSize}px`);
 | |
|             } else {
 | |
|                 // Zurücksetzen auf Standardwert für andere Modi
 | |
|                 document.documentElement.style.setProperty('--cell-size', '30px');
 | |
|             }
 | |
|             
 | |
|             // Minen-Counter aktualisieren
 | |
|             updateMinesCounter(mines);
 | |
|             
 | |
|             // Spielbrett-Daten initialisieren
 | |
|             boardData = Array(rows).fill().map(() => 
 | |
|                 Array(cols).fill().map(() => ({
 | |
|                     isMine: false,
 | |
|                     isRevealed: false,
 | |
|                     isFlagged: false,
 | |
|                     neighborMines: 0
 | |
|                 }))
 | |
|             );
 | |
|             
 | |
|             // Zellen erstellen
 | |
|             for (let row = 0; row < rows; row++) {
 | |
|                 for (let col = 0; col < cols; col++) {
 | |
|                     const cell = document.createElement('div');
 | |
|                     cell.className = 'cell';
 | |
|                     cell.dataset.row = row;
 | |
|                     cell.dataset.col = col;
 | |
|                     
 | |
|                     cell.addEventListener('click', handleCellClick);
 | |
|                     cell.addEventListener('contextmenu', handleRightClick);
 | |
|                     cell.addEventListener('dblclick', handleDoubleClick);
 | |
|                     
 | |
|                     board.appendChild(cell);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Minen platzieren
 | |
|         function placeMines(firstClickRow, firstClickCol) {
 | |
|             const { rows, cols, mines } = levels[currentLevel];
 | |
|             let minesPlaced = 0;
 | |
|             
 | |
|             while (minesPlaced < mines) {
 | |
|                 const row = Math.floor(Math.random() * rows);
 | |
|                 const col = Math.floor(Math.random() * cols);
 | |
|                 
 | |
|                 // Nicht auf die erste Klick-Position oder wo bereits eine Mine ist
 | |
|                 if ((row !== firstClickRow || col !== firstClickCol) && !boardData[row][col].isMine) {
 | |
|                     boardData[row][col].isMine = true;
 | |
|                     minesPlaced++;
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             // Nachbarn-Minen-Zähler berechnen
 | |
|             for (let row = 0; row < rows; row++) {
 | |
|                 for (let col = 0; col < cols; col++) {
 | |
|                     if (!boardData[row][col].isMine) {
 | |
|                         boardData[row][col].neighborMines = countNeighborMines(row, col);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Nachbarn-Minen zählen
 | |
|         function countNeighborMines(row, col) {
 | |
|             const { rows, cols } = levels[currentLevel];
 | |
|             let count = 0;
 | |
|             
 | |
|             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) && boardData[r][c].isMine) {
 | |
|                         count++;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             return count;
 | |
|         }
 | |
| 
 | |
|         // Zellen-Klick behandeln
 | |
|         function handleCellClick(e) {
 | |
|             if (gameOver) return;
 | |
|             
 | |
|             const row = parseInt(e.target.dataset.row);
 | |
|             const col = parseInt(e.target.dataset.col);
 | |
|             
 | |
|             // Erster Klick initialisiert das Spiel
 | |
|             if (!gameStarted) {
 | |
|                 gameStarted = true;
 | |
|                 startTimer();
 | |
|                 placeMines(row, col);
 | |
|             }
 | |
|             
 | |
|             // Nicht auf eine Flagge klicken
 | |
|             if (boardData[row][col].isFlagged) return;
 | |
|             
 | |
|             // Bei Minen-Klick Game Over
 | |
|             if (boardData[row][col].isMine) {
 | |
|                 revealMines();
 | |
|                 gameOver = true;
 | |
|                 clearInterval(timeInterval);
 | |
|                 smiley.textContent = '😵';
 | |
|                 e.target.classList.add('mine-clicked');
 | |
|                 return;
 | |
|             }
 | |
|             
 | |
|             // Zelle aufdecken
 | |
|             revealCell(row, col);
 | |
|             
 | |
|             // Prüfen auf Sieg
 | |
|             checkWin();
 | |
|         }
 | |
| 
 | |
|         // Rechtsklick behandeln (Flagge setzen)
 | |
|         function handleRightClick(e) {
 | |
|             e.preventDefault();
 | |
|             if (gameOver || !gameStarted) return;
 | |
|             
 | |
|             const row = parseInt(e.target.dataset.row);
 | |
|             const col = parseInt(e.target.dataset.col);
 | |
|             
 | |
|             // Nur nicht aufgedeckte Zellen flaggen
 | |
|             if (boardData[row][col].isRevealed) return;
 | |
|             
 | |
|             const cell = e.target;
 | |
|             
 | |
|             if (boardData[row][col].isFlagged) {
 | |
|                 // Flagge entfernen
 | |
|                 boardData[row][col].isFlagged = false;
 | |
|                 cell.classList.remove('flagged');
 | |
|                 flagCount--;
 | |
|             } else {
 | |
|                 // Flagge setzen
 | |
|                 boardData[row][col].isFlagged = true;
 | |
|                 cell.classList.add('flagged');
 | |
|                 flagCount++;
 | |
|             }
 | |
|             
 | |
|             // Minen-Counter aktualisieren
 | |
|             updateMinesCounter(levels[currentLevel].mines - flagCount);
 | |
|         }
 | |
| 
 | |
|         // Doppelklick behandeln (Nachbarn aufdecken)
 | |
|         function handleDoubleClick(e) {
 | |
|             if (gameOver || !gameStarted) return;
 | |
|             
 | |
|             const row = parseInt(e.target.dataset.row);
 | |
|             const col = parseInt(e.target.dataset.col);
 | |
|             
 | |
|             // Nur für aufgedeckte Zellen mit Zahlen
 | |
|             if (!boardData[row][col].isRevealed || boardData[row][col].neighborMines === 0) return;
 | |
|             
 | |
|             const { rows, cols } = levels[currentLevel];
 | |
|             let flagCount = 0;
 | |
|             
 | |
|             // Zählen der Flaggen in der Umgebung
 | |
|             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 (boardData[r][c].isFlagged) {
 | |
|                         flagCount++;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             // Wenn die Anzahl der Flaggen mit der Zahl übereinstimmt, Nachbarn aufdecken
 | |
|             if (flagCount === boardData[row][col].neighborMines) {
 | |
|                 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 (!boardData[r][c].isRevealed && !boardData[r][c].isFlagged) {
 | |
|                             // Simuliere einen Klick auf die Zelle
 | |
|                             const cellElement = document.querySelector(`.cell[data-row="${r}"][data-col="${c}"]`);
 | |
|                             if (cellElement) {
 | |
|                                 cellElement.click();
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Zelle aufdecken
 | |
|         function revealCell(row, col) {
 | |
|             const { rows, cols } = levels[currentLevel];
 | |
|             
 | |
|             // Bereits aufgedeckt oder geflaggt überspringen
 | |
|             if (boardData[row][col].isRevealed || boardData[row][col].isFlagged) return;
 | |
|             
 | |
|             // Zelle als aufgedeckt markieren
 | |
|             boardData[row][col].isRevealed = true;
 | |
|             
 | |
|             // DOM aktualisieren
 | |
|             const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
 | |
|             cell.classList.add('revealed');
 | |
|             
 | |
|             // Nachbarn-Anzahl anzeigen wenn > 0
 | |
|             if (boardData[row][col].neighborMines > 0) {
 | |
|                 cell.textContent = boardData[row][col].neighborMines;
 | |
|                 cell.classList.add(`number-${boardData[row][col].neighborMines}`);
 | |
|             } else {
 | |
|                 // Bei 0 Nachbarn automatisch alle angrenzenden Zellen aufdecken
 | |
|                 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) {
 | |
|                             revealCell(r, c);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Alle Minen aufdecken (bei Game Over)
 | |
|         function revealMines() {
 | |
|             const { rows, cols } = levels[currentLevel];
 | |
|             
 | |
|             for (let row = 0; row < rows; row++) {
 | |
|                 for (let col = 0; col < cols; col++) {
 | |
|                     if (boardData[row][col].isMine) {
 | |
|                         const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
 | |
|                         cell.classList.add('revealed', 'mine');
 | |
|                     } else if (boardData[row][col].isFlagged) {
 | |
|                         // Falsch platzierte Flaggen markieren
 | |
|                         const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
 | |
|                         cell.classList.add('revealed');
 | |
|                         cell.classList.add('wrong-flag');
 | |
|                         cell.textContent = '❌';
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Prüfen, ob das Spiel gewonnen wurde
 | |
|         function checkWin() {
 | |
|             const { rows, cols, mines } = levels[currentLevel];
 | |
|             let revealedCount = 0;
 | |
|             
 | |
|             for (let row = 0; row < rows; row++) {
 | |
|                 for (let col = 0; col < cols; col++) {
 | |
|                     if (boardData[row][col].isRevealed) {
 | |
|                         revealedCount++;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             // Gewonnen, wenn alle Nicht-Minen-Zellen aufgedeckt sind
 | |
|             if (revealedCount === (rows * cols - mines)) {
 | |
|                 gameOver = true;
 | |
|                 clearInterval(timeInterval);
 | |
|                 smiley.textContent = '😎';
 | |
|                 
 | |
|                 // Alle Minen automatisch flaggen
 | |
|                 for (let row = 0; row < rows; row++) {
 | |
|                     for (let col = 0; col < cols; col++) {
 | |
|                         if (boardData[row][col].isMine && !boardData[row][col].isFlagged) {
 | |
|                             boardData[row][col].isFlagged = true;
 | |
|                             const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
 | |
|                             cell.classList.add('flagged');
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // Minen-Counter auf 0 setzen
 | |
|                 updateMinesCounter(0);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Timer starten
 | |
|         function startTimer() {
 | |
|             startTime = Date.now();
 | |
|             timeInterval = setInterval(() => {
 | |
|                 const elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
 | |
|                 // Maximale Anzeige: 999 Sekunden
 | |
|                 const displayTime = Math.min(elapsedSeconds, 999);
 | |
|                 timerElement.textContent = displayTime.toString().padStart(3, '0');
 | |
|             }, 1000);
 | |
|         }
 | |
| 
 | |
|         // Minen-Counter aktualisieren
 | |
|         function updateMinesCounter(count) {
 | |
|             minesCounter.textContent = count.toString().padStart(3, '0');
 | |
|         }
 | |
| 
 | |
|         // Dark Mode
 | |
|         function toggleTheme() {
 | |
|             document.body.classList.toggle('dark-mode');
 | |
|             const btn = document.querySelector('.theme-toggle');
 | |
|             btn.textContent = document.body.classList.contains('dark-mode') ? '☀️' : '🌙';
 | |
|             
 | |
|             // Speichern der Präferenz
 | |
|             const isDark = document.body.classList.contains('dark-mode');
 | |
|             localStorage.setItem('theme', isDark ? 'dark' : 'light');
 | |
|         }
 | |
| 
 | |
|         // Theme initialisieren
 | |
|         function initTheme() {
 | |
|             const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
 | |
|             const savedTheme = localStorage.getItem('theme');
 | |
|             
 | |
|             if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
 | |
|                 document.body.classList.add('dark-mode');
 | |
|                 document.querySelector('.theme-toggle').textContent = '☀️';
 | |
|             }
 | |
|             
 | |
|             // Jahr aktualisieren
 | |
|             document.getElementById('currentYear').textContent = new Date().getFullYear();
 | |
|         }
 | |
| 
 | |
|         // Kontextmenü für rechte Maustaste verhindern
 | |
|         board.addEventListener('contextmenu', e => e.preventDefault());
 | |
| 
 | |
|         // Beim Laden ausführen
 | |
|         initTheme();
 | |
|         initGame();
 | |
| 
 | |
|         // Bei Resize Fenster die Zellengröße anpassen
 | |
|         window.addEventListener('resize', () => {
 | |
|             if (currentLevel === 'expert') {
 | |
|                 const gameContainer = document.querySelector('.game-container');
 | |
|                 const containerWidth = gameContainer.clientWidth - 40;
 | |
|                 const cellSize = Math.max(15, Math.floor(containerWidth / levels.expert.cols)); // Minimalgröße 15px
 | |
|                 document.documentElement.style.setProperty('--cell-size', `${cellSize}px`);
 | |
|             }
 | |
|         });
 | |
|     </script>
 | |
| </body>
 | |
| </html>  | 
