1// æ«é·æ¸¸æå®ç° 2class Minesweeper { 3 constructor() { 4 this.BOARD_SIZE = 9; 5 this.MINES_COUNT = 10; 6 this.board = []; 7 this.revealed = []; 8 this.flagged = []; 9 this.gameOver = false; 10 this.firstClick = true; 11 this.timeElapsed = 0; 12 this.timer = null; 13 this.minesLeft = this.MINES_COUNT; 14 15 this.container = document.getElementById('minesweeper-container'); 16 this.init(); 17 } 18 19 init() { 20 // åå»ºæ¸¸ææ§å¶é¢æ¿ 21 const controlPanel = document.createElement('div'); 22 controlPanel.className = 'control-panel'; 23 controlPanel.innerHTML = ` 24 <div class="mine-counter">${String(this.minesLeft).padStart(3, '0')}</div> 25 <button class="reset-button">ð</button> 26 <div class="timer">000</div> 27 `; 28 this.container.appendChild(controlPanel); 29 30 // åå»ºæ¸¸ææ£ç 31 const gameBoard = document.createElement('div'); 32 gameBoard.className = 'game-board'; 33 this.container.appendChild(gameBoard); 34 35 // åå§åæ¸¸ææ°æ® 36 this.initializeBoard(); 37 this.renderBoard(); 38 39 // æ·»å äºä»¶çå¬å¨ 40 this.addEventListeners(); 41 42 // æ·»å æ ·å¼ 43 this.addStyles(); 44 } 45 46 addStyles() { 47 const style = document.createElement('style'); 48 style.textContent = ` 49 #minesweeper-container { 50 padding: 10px; 51 background: #c0c0c0; 52 border: 2px solid #808080; 53 } 54 .control-panel { 55 display: flex; 56 justify-content: space-between; 57 margin-bottom: 10px; 58 padding: 5px; 59 background: #c0c0c0; 60 border: 2px solid #808080; 61 } 62 .mine-counter, .timer { 63 background: #000; 64 color: #f00; 65 padding: 2px 5px; 66 font-family: 'Digital', monospace; 67 font-size: 20px; 68 } 69 .reset-button { 70 width: 26px; 71 height: 26px; 72 font-size: 20px; 73 border: 2px solid #fff; 74 border-right-color: #808080; 75 border-bottom-color: #808080; 76 background: #c0c0c0; 77 cursor: pointer; 78 display: flex; 79 align-items: center; 80 justify-content: center; 81 padding: 0; 82 } 83 .game-board { 84 display: grid; 85 grid-template-columns: repeat(${this.BOARD_SIZE}, 30px); 86 gap: 1px; 87 background: #808080; 88 border: 3px solid #808080; 89 } 90 .cell { 91 width: 30px; 92 height: 30px; 93 background: #c0c0c0; 94 border: 2px solid #fff; 95 border-right-color: #808080; 96 border-bottom-color: #808080; 97 display: flex; 98 align-items: center; 99 justify-content: center; 100 font-weight: bold; 101 cursor: pointer; 102 font-size: 16px; 103 } 104 .cell.revealed { 105 border: 1px solid #808080; 106 background: #c0c0c0; 107 } 108 .cell[data-number="1"] { color: blue; } 109 .cell[data-number="2"] { color: green; } 110 .cell[data-number="3"] { color: red; } 111 .cell[data-number="4"] { color: darkblue; } 112 .cell[data-number="5"] { color: darkred; } 113 .cell[data-number="6"] { color: teal; } 114 .cell[data-number="7"] { color: black; } 115 .cell[data-number="8"] { color: gray; } 116 `; 117 document.head.appendChild(style); 118 } 119 120 initializeBoard() { 121 // åå§å空æ£ç 122 this.board = Array(this.BOARD_SIZE).fill().map(() => 123 Array(this.BOARD_SIZE).fill(0) 124 ); 125 this.revealed = Array(this.BOARD_SIZE).fill().map(() => 126 Array(this.BOARD_SIZE).fill(false) 127 ); 128 this.flagged = Array(this.BOARD_SIZE).fill().map(() => 129 Array(this.BOARD_SIZE).fill(false) 130 ); 131 } 132 133 placeMines(firstX, firstY) { 134 let minesPlaced = 0; 135 while (minesPlaced < this.MINES_COUNT) { 136 const x = Math.floor(Math.random() * this.BOARD_SIZE); 137 const y = Math.floor(Math.random() * this.BOARD_SIZE); 138 139 // ç¡®ä¿ä¸å¨ç¬¬ä¸æ¬¡ç¹å»çä½ç½®åå ¶å¨å´æ¾ç½®å°é· 140 if (this.board[x][y] !== -1 && 141 (Math.abs(x - firstX) > 1 || Math.abs(y - firstY) > 1)) { 142 this.board[x][y] = -1; 143 minesPlaced++; 144 } 145 } 146 147 // è®¡ç®æ¯ä¸ªæ ¼åå¨å´çå°é·æ° 148 for (let x = 0; x < this.BOARD_SIZE; x++) { 149 for (let y = 0; y < this.BOARD_SIZE; y++) { 150 if (this.board[x][y] !== -1) { 151 this.board[x][y] = this.countAdjacentMines(x, y); 152 } 153 } 154 } 155 } 156 157 countAdjacentMines(x, y) { 158 let count = 0; 159 for (let dx = -1; dx <= 1; dx++) { 160 for (let dy = -1; dy <= 1; dy++) { 161 const newX = x + dx; 162 const newY = y + dy; 163 if (newX >= 0 && newX < this.BOARD_SIZE && 164 newY >= 0 && newY < this.BOARD_SIZE && 165 this.board[newX][newY] === -1) { 166 count++; 167 } 168 } 169 } 170 return count; 171 } 172 173 renderBoard() { 174 const gameBoard = this.container.querySelector('.game-board'); 175 gameBoard.innerHTML = ''; 176 177 for (let x = 0; x < this.BOARD_SIZE; x++) { 178 for (let y = 0; y < this.BOARD_SIZE; y++) { 179 const cell = document.createElement('div'); 180 cell.className = 'cell'; 181 cell.dataset.x = x; 182 cell.dataset.y = y; 183 184 if (this.revealed[x][y]) { 185 cell.classList.add('revealed'); 186 if (this.board[x][y] === -1) { 187 cell.textContent = 'ð£'; 188 } else if (this.board[x][y] > 0) { 189 cell.textContent = this.board[x][y]; 190 cell.dataset.number = this.board[x][y]; 191 } 192 } else if (this.flagged[x][y]) { 193 cell.textContent = 'ð©'; 194 } 195 196 gameBoard.appendChild(cell); 197 } 198 } 199 } 200 201 addEventListeners() { 202 const gameBoard = this.container.querySelector('.game-board'); 203 const resetButton = this.container.querySelector('.reset-button'); 204 205 gameBoard.addEventListener('click', (e) => { 206 const cell = e.target.closest('.cell'); 207 if (cell && !this.gameOver) { 208 const x = parseInt(cell.dataset.x); 209 const y = parseInt(cell.dataset.y); 210 this.handleClick(x, y); 211 } 212 }); 213 214 gameBoard.addEventListener('contextmenu', (e) => { 215 e.preventDefault(); 216 const cell = e.target.closest('.cell'); 217 if (cell && !this.gameOver) { 218 const x = parseInt(cell.dataset.x); 219 const y = parseInt(cell.dataset.y); 220 this.handleRightClick(x, y); 221 } 222 }); 223 224 resetButton.addEventListener('click', () => { 225 this.resetGame(); 226 }); 227 } 228 229 handleClick(x, y) { 230 if (this.flagged[x][y] || this.revealed[x][y]) return; 231 232 if (this.firstClick) { 233 this.firstClick = false;
234 this.placeMines(x, y); 235 this.startTimer(); 236 } 237 238 if (this.board[x][y] === -1) { 239 this.gameOver = true; 240 this.revealAllMines(); 241 this.updateResetButton('ðµ'); 242 this.stopTimer(); 243 return; 244 } 245 246 this.reveal(x, y); 247 this.renderBoard(); 248 249 if (this.checkWin()) { 250 this.gameOver = true; 251 this.updateResetButton('ð'); 252 this.stopTimer(); 253 } 254 } 255 256 handleRightClick(x, y) { 257 if (this.revealed[x][y]) return; 258 259 this.flagged[x][y] = !this.flagged[x][y]; 260 this.minesLeft += this.flagged[x][y] ? -1 : 1; 261 this.updateMineCounter(); 262 this.renderBoard(); 263 264 if (this.checkWin()) { 265 this.gameOver = true; 266 this.updateResetButton('ð'); 267 this.stopTimer(); 268 } 269 } 270 271 reveal(x, y) { 272 if (x < 0 || x >= this.BOARD_SIZE || y < 0 || y >= this.BOARD_SIZE || 273 this.revealed[x][y] || this.flagged[x][y]) { 274 return; 275 } 276 277 this.revealed[x][y] = true; 278 279 if (this.board[x][y] === 0) { 280 for (let dx = -1; dx <= 1; dx++) { 281 for (let dy = -1; dy <= 1; dy++) { 282 this.reveal(x + dx, y + dy); 283 } 284 } 285 } 286 } 287 288 revealAllMines() { 289 for (let x = 0; x < this.BOARD_SIZE; x++) { 290 for (let y = 0; y < this.BOARD_SIZE; y++) { 291 if (this.board[x][y] === -1) { 292 this.revealed[x][y] = true; 293 } 294 } 295 } 296 this.renderBoard(); 297 } 298 299 checkWin() { 300 for (let x = 0; x < this.BOARD_SIZE; x++) { 301 for (let y = 0; y < this.BOARD_SIZE; y++) { 302 if (this.board[x][y] !== -1 && !this.revealed[x][y]) { 303 return false; 304 } 305 if (this.board[x][y] === -1 && !this.flagged[x][y]) { 306 return false; 307 } 308 } 309 } 310 return true; 311 } 312 313 updateResetButton(emoji) { 314 const resetButton = this.container.querySelector('.reset-button'); 315 resetButton.textContent = emoji; 316 } 317 318 updateMineCounter() { 319 const counter = this.container.querySelector('.mine-counter'); 320 counter.textContent = String(this.minesLeft).padStart(3, '0'); 321 } 322 323 startTimer() { 324 const timerDisplay = this.container.querySelector('.timer'); 325 this.timer = setInterval(() => { 326 this.timeElapsed++; 327 timerDisplay.textContent = String(this.timeElapsed).padStart(3, '0'); 328 }, 1000); 329 } 330 331 stopTimer() { 332 if (this.timer) { 333 clearInterval(this.timer); 334 this.timer = null; 335 } 336 } 337 338 resetGame() { 339 this.stopTimer(); 340 this.timeElapsed = 0; 341 this.minesLeft = this.MINES_COUNT; 342 this.gameOver = false; 343 this.firstClick = true; 344 this.initializeBoard(); 345 this.updateResetButton('ð'); 346 this.updateMineCounter(); 347 this.container.querySelector('.timer').textContent = '000'; 348 this.renderBoard(); 349 } 350} 351 352// æ¾ç¤ºå ³äºå¼¹çª 353function showMinesweeperAbout() { 354 const aboutModal = document.getElementById('minesweeper-about'); 355 aboutModal.style.display = 'block'; 356} 357 358// éèå ³äºå¼¹çª 359function hideMinesweeperAbout() { 360 const aboutModal = document.getElementById('minesweeper-about'); 361 aboutModal.style.display = 'none'; 362} 363 364// å½çªå£æå¼æ¶åå§å游æ 365document.addEventListener('DOMContentLoaded', () => { 366 const minesweeperWindow = document.getElementById('minesweeper-window'); 367 if (!minesweeperWindow.dataset.initialized) { 368 new Minesweeper(); 369 minesweeperWindow.dataset.initialized = 'true'; 370 } 371});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.