const canvas = document.getElementById("tablero"); const ctx = canvas.getContext("2d"); const startButton = document.getElementById("startButton"); const banderas = document.getElementById("banderas"); const tiempo = document.getElementById("tiempo"); const FILAS = 25; const COLUMNAS = 25; const cellSize = 32; const nBombas = 50; const tilesBorde = new Image(); tilesBorde.src = './img/borde.png'; const tilesMisc = new Image(); tilesMisc.src = './img/tiles.png'; let nBanderas=nBombas; let tiempoTranscurrido = 0; let showBombas = false; let cronometro; let tablero = []; canvas.width = COLUMNAS * cellSize; canvas.height = FILAS * cellSize; function handleKey(event) { if (event.key === "1") { showBombas=!showBombas; } else if (event.key === "Escape") { gameOver(); } }; function handleClick(event) { const { x, y } = getCellCoordinates(event); if (!tablero[y][x].tieneFlag) levantaCelda(y, x); } function handleContextMenu(event) { event.preventDefault(); const { x, y } = getCellCoordinates(event); marcaFlagCelda(y, x); } function getCellCoordinates(event) { const rect = canvas.getBoundingClientRect(); return { x: Math.floor((event.x - rect.left) / cellSize), y: Math.floor((event.y - rect.top) / cellSize), }; } function generaTablero() { for (let y = 0; y < FILAS; y++) { tablero[y] = []; for (let x = 0; x < COLUMNAS; x++) { tablero[y][x] = { esMina: false, abierto: false, tieneFlag: false, nAdyacentes: 0, }; } } for (let z = 0; z < nBombas; z++) { let x, y; do { y = Math.floor(Math.random() * (FILAS)); x = Math.floor(Math.random() * (COLUMNAS)); } while (tablero[y][x].esMina); tablero[y][x].esMina = true; for (let i = -1; i <= 1; i++) { for (let j = -1; j <= 1; j++) { if (y + i >= 0 && y + i < FILAS && x + j >= 0 && x + j < COLUMNAS) { if (!tablero[y + i][x + j].esMina) { tablero[y + i][x + j].nAdyacentes += 1; } } } } } } function levantaCelda(y, x) { if (!tablero[y][x].abierto) { tablero[y][x].abierto = true; if (tablero[y][x].tieneFlag){ tablero[y][x].tieneFlag = false; nBanderas++; } if (tablero[y][x].nAdyacentes === 0 && !tablero[y][x].esMina) { for (let i = -1; i <= 1; i++) { for (let j = -1; j <= 1; j++) { if ( y + i >= 0 && y + i < FILAS && x + j >= 0 && x + j < COLUMNAS && !(i === 0 && j === 0) ) { levantaCelda(y + i, x + j); } } } } if (tablero[y][x].esMina) { gameOver(); } else if (comprobarVictoria()) { victoria(); } } } function comprobarVictoria() { return tablero.every((row) => row.every((cell) => cell.abierto || cell.esMina) ); } function marcaFlagCelda(y, x) { if (!tablero[y][x].abierto) { if (tablero[y][x].tieneFlag){ tablero[y][x].tieneFlag = false; nBanderas++; }else if (nBanderas>0){ tablero[y][x].tieneFlag = true; nBanderas--; } } } function dibujaTablero() { for (let y = 0; y < FILAS; y++) { for (let x = 0; x < COLUMNAS; x++) { if (!tablero[y][x].abierto) { ctx.drawImage(tilesMisc,32,0,cellSize,cellSize,x * cellSize, y * cellSize,cellSize,cellSize); } else { ctx.drawImage(tilesMisc,96,0,cellSize,cellSize,x * cellSize, y * cellSize,cellSize,cellSize); if (tablero[y][x].nAdyacentes > 0) { ctx.font = "24px Bungee Spice"; //ctx.fillStyle = "black"; const text = tablero[y][x].nAdyacentes; const textX = x * cellSize + cellSize / 2 - ctx.measureText(text).width / 2; const textY = y * cellSize + cellSize / 2 + 10; ctx.fillText(text, textX, textY); } } if (showBombas && tablero[y][x].esMina){ ctx.drawImage(tilesMisc,64,0,cellSize,cellSize,x * cellSize, y * cellSize,cellSize,cellSize); } if (tablero[y][x].tieneFlag) { ctx.drawImage(tilesMisc,0,0,cellSize,cellSize,x * cellSize, y * cellSize,cellSize,cellSize); } } } dibujaBordesMapa(); } function dibujaBordesMapa(){ for (let y = 1; y < FILAS-1; y++) { ctx.drawImage(tilesBorde,96,0,cellSize,cellSize,0,y*cellSize,cellSize,cellSize); ctx.drawImage(tilesBorde,96,32,cellSize,cellSize,(COLUMNAS-1)*cellSize,y*cellSize,cellSize,cellSize); } for (let x = 1; x < COLUMNAS-1; x++) { ctx.drawImage(tilesBorde,64,0,cellSize,cellSize,x*cellSize,0,cellSize,cellSize); ctx.drawImage(tilesBorde,64,32,cellSize,cellSize,x*cellSize,(FILAS-1)*cellSize,cellSize,cellSize); } ctx.drawImage(tilesBorde,0,0,cellSize,cellSize,0,0,cellSize,cellSize); ctx.drawImage(tilesBorde,32,0,cellSize,cellSize,(FILAS-1)*cellSize,0,cellSize,cellSize); ctx.drawImage(tilesBorde,0,32,cellSize,cellSize,0,(COLUMNAS-1)*cellSize,cellSize,cellSize); ctx.drawImage(tilesBorde,32,32,cellSize,cellSize,(FILAS-1)*cellSize,(COLUMNAS-1)*cellSize,cellSize,cellSize); } function gameLoop() { tiempo.textContent = convertirTiempo(tiempoTranscurrido); banderas.textContent = nBanderas; dibujaTablero(); window.requestAnimationFrame(gameLoop); } function iniciarCronometro() { tiempoTranscurrido = 0; cronometro = setInterval(() => { tiempoTranscurrido++; }, 1000); } function detenerCronometro() { clearInterval(cronometro); } function convertirTiempo(tiempoSegundos) { const horas = Math.floor(tiempoSegundos / 3600); const minutos = Math.floor((tiempoSegundos % 3600) / 60); const segundos = tiempoSegundos % 60; const horasStr = String(horas).padStart(2, "0"); const minutosStr = String(minutos).padStart(2, "0"); const segundosStr = String(segundos).padStart(2, "0"); return `${horasStr}:${minutosStr}:${segundosStr}`; } function iniciarPartida() { startButton.blur(); startButton.style.visibility = "hidden"; nBanderas=nBombas; showBombas=false; canvas.addEventListener("click", handleClick); canvas.addEventListener("contextmenu", handleContextMenu); document.addEventListener("keydown", handleKey); generaTablero(); iniciarCronometro(); gameLoop(); } function terminarPartida() { canvas.removeEventListener("click", handleClick); canvas.removeEventListener("contextmenu", handleContextMenu); document.removeEventListener("keydown", handleKey); detenerCronometro(); startButton.style.visibility = "visible"; startButton.focus(); } function victoria() { terminarPartida(); } function gameOver() { terminarPartida(); }