Edita código
Copiar al portapapeles
Ejecutar »
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Sopa de Letras</title> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; background: linear-gradient(to bottom, #e0ffff, #cce0ff); } .container { display: flex; flex-direction: column; align-items: center; padding: 20px; border-radius: 10px; background-color: rgba(255, 255, 255, 0.8); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); text-align: center; } h1 { font-size: 2.5em; color: #333; margin-bottom: 20px; text-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2); perspective: 100px; } h1 span { display: inline-block; transform: translateZ(20px); } .sopa-y-palabras { display: flex; align-items: center; justify-content: center; width: 100%; max-width: 800px; margin-bottom: 20px; } table { border-collapse: collapse; user-select: none; background-color: #444; border-radius: 10px; margin-right: 20px; } td { width: 30px; height: 30px; text-align: center; border: 3px solid #666; cursor: pointer; font-size: 1.2em; color: white; background-color: #222; box-shadow: 5px 5px 8px rgba(0, 0, 0, 0.8); position: relative; vertical-align: middle; transition: background-color 0.3s ease; } td::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; border: 3px solid; border-color: #ccc transparent transparent transparent; pointer-events: none; } .selected { background-color: lightgreen; } .found { text-decoration: line-through; color: hsl(random(360), 50%, 50%); } .solution { background-color: #800080; font-weight: bold; } #palabras-container { /* Contenedor para el marco */ border: 2px solid #333; padding: 10px; border-radius: 10px; } #palabras { list-style-type: none; padding: 0; text-align: left; } #palabras li { margin-bottom: 8px; font-size: 1em; color: #333; } #botones { display: flex; justify-content: center; margin-top: 10px; } button { padding: 10px 20px; margin: 0 10px; border: none; border-radius: 20px; font-size: 1em; color: white; cursor: pointer; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); transition: background-color 0.3s ease; } #reiniciar { background: linear-gradient(to right, #4CAF50, #2E8B57); } #solucion { background: linear-gradient(to right, #FF4500, #D2691E); } #felicitaciones { margin-top: 20px; font-weight: bold; color: green; font-size: 1.2em; } #marcador { margin-bottom: 10px; font-size: 1.2em; color: #333; } /* Estilos Responsivos */ @media (max-width: 500px) { .sopa-y-palabras { flex-direction: column; align-items: center; } table { margin-right: 0; margin-bottom: 20px; } } </style> </head> <body> <div class="container"> <h1><span>Sopa de Letras</span></h1> <div id="marcador">Palabras encontradas: <span id="aciertos">0</span> de <span id="totalPalabras"></span> </div> <div class="sopa-y-palabras"> <table id="sopa"></table> <div id="palabras-container"> <ul id="palabras"></ul> </div> </div> <div id="botones"> <button id="reiniciar">Reiniciar</button> <button id="solucion">Solución</button> </div> <div id="felicitaciones"></div> </div> <script> const palabras = ["ARGENTINA", "BOLIVIA", "COLOMBIA", "PANAMÃ", "ITALIA", "ESPAÑA", "FRANCIA"]; const filas = 11; const columnas = 11; const letras = "ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"; let tablero; let seleccionInicio = null; let seleccionFin = null; let mouseDown = false; let palabrasEncontradas = []; let palabrasColocadas = []; let colorSeleccionado = "#663399"; const marcadorAciertos = document.getElementById("aciertos"); const marcadorTotalPalabras = document.getElementById("totalPalabras"); marcadorTotalPalabras.textContent = palabras.length; function generarSopa() { const sopa = document.getElementById("sopa"); const palabrasLista = document.getElementById("palabras"); document.getElementById("felicitaciones").textContent = ""; sopa.innerHTML = ""; palabrasLista.innerHTML = ""; tablero = crearTableroVacio(); palabrasColocadas = []; for (let palabra of palabras) { colocarPalabra(tablero, palabra); } rellenarCeldasVacias(tablero); for (let i = 0; i < filas; i++) { const fila = document.createElement("tr"); for (let j = 0; j < columnas; j++) { const celda = document.createElement("td"); celda.textContent = tablero[i][j]; fila.appendChild(celda); } sopa.appendChild(fila); } const celdas = document.querySelectorAll("td"); for (let celda of celdas) { celda.addEventListener("mousedown", iniciarSeleccion); celda.addEventListener("mouseover", actualizarSeleccion); celda.addEventListener("mouseup", finalizarSeleccion); } for (let palabra of palabras) { const li = document.createElement("li"); li.textContent = palabra; palabrasLista.appendChild(li); } palabrasEncontradas = []; marcadorAciertos.textContent = "0"; } function iniciarSeleccion(event) { seleccionInicio = event.target; seleccionFin = null; mouseDown = true; actualizarSeleccion(event); } function actualizarSeleccion(event) { if (mouseDown) { const celdas = document.querySelectorAll("td"); for (let celda of celdas) { celda.classList.remove("selected"); } seleccionFin = event.target; marcarPalabra(seleccionInicio, seleccionFin); } } function finalizarSeleccion() { mouseDown = false; const celdas = document.querySelectorAll(".selected"); let palabra = ""; for (let celda of celdas) { palabra += celda.textContent; } if ((palabras.includes(palabra) || palabras.includes(palabra.split("").reverse().join(""))) && !palabrasEncontradas.includes(palabra)) { for (let celda of celdas) { celda.style.backgroundColor = colorSeleccionado; } const palabraElemento = document.querySelectorAll("#palabras li")[palabras.indexOf(palabra) >= 0 ? palabras.indexOf(palabra) : palabras.indexOf(palabra.split("").reverse().join(""))]; palabraElemento.classList.add("found"); palabrasEncontradas.push(palabra); colorSeleccionado = `#${Math.floor((Math.random() * 0x666666) + 0x333333).toString(16)}`; marcadorAciertos.textContent = palabrasEncontradas.length; } else { for (let celda of celdas) { celda.classList.remove("selected"); } } if (palabrasEncontradas.length === palabras.length) { document.getElementById("felicitaciones").textContent = "¡Felicidades! Has encontrado todas las palabras."; } } function marcarPalabra(inicio, fin) { const filaInicio = inicio.parentNode.rowIndex; const columnaInicio = inicio.cellIndex; const filaFin = fin.parentNode.rowIndex; const columnaFin = fin.cellIndex; let filaActual = filaInicio; let columnaActual = columnaInicio; let incrementoFila = (filaFin > filaInicio) ? 1 : (filaFin < filaInicio) ? -1 : 0; let incrementoColumna = (columnaFin > columnaInicio) ? 1 : (columnaFin < columnaInicio) ? -1 : 0; while (filaActual !== filaFin || columnaActual !== columnaFin) { const celda = document.querySelector(`tr:nth-child(${filaActual + 1}) td:nth-child(${columnaActual + 1})`); celda.classList.add("selected"); filaActual += incrementoFila; columnaActual += incrementoColumna; } const celdaFin = document.querySelector(`tr:nth-child(${filaFin + 1}) td:nth-child(${columnaFin + 1})`); celdaFin.classList.add("selected"); } function crearTableroVacio() { let tablero = []; for (let i = 0; i < filas; i++) { tablero[i] = []; for (let j = 0; j < columnas; j++) { tablero[i][j] = "."; } } return tablero; } function rellenarCeldasVacias(tablero) { for (let i = 0; i < filas; i++) { for (let j = 0; j < columnas; j++) { if (tablero[i][j] === ".") { tablero[i][j] = letras[Math.floor(Math.random() * letras.length)]; } } } } function colocarPalabra(tablero, palabra) { const direcciones = [ [0, 1], [1, 0], [0, -1], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1] ]; let intentos = 0; const maxIntentos = 1000; while (intentos < maxIntentos) { const direccion = direcciones[Math.floor(Math.random() * direcciones.length)]; const filaInicio = Math.floor(Math.random() * filas); const columnaInicio = Math.floor(Math.random() * columnas); let filaActual = filaInicio; let columnaActual = columnaInicio; let posicionesValidas = true; for (let i = 0; i < palabra.length; i++) { if ( filaActual < 0 || filaActual >= filas || columnaActual < 0 || columnaActual >= columnas || (tablero[filaActual][columnaActual] !== palabra[i] && tablero[filaActual][columnaActual] !== ".") ) { posicionesValidas = false; break; } filaActual += direccion[0]; columnaActual += direccion[1]; } if (posicionesValidas) { filaActual = filaInicio; columnaActual = columnaInicio; for (let i = 0; i < palabra.length; i++) { tablero[filaActual][columnaActual] = palabra[i]; filaActual += direccion[0]; columnaActual += direccion[1]; } palabrasColocadas.push(palabra); return; } intentos++; } console.warn(`No se pudo colocar la palabra "${palabra}"`); } document.getElementById("reiniciar").addEventListener("click", generarSopa); document.getElementById("solucion").addEventListener("click", mostrarSolucion); function mostrarSolucion() { const celdas = document.querySelectorAll("td"); for (let celda of celdas) { celda.classList.remove("selected"); } for (let palabra of palabrasColocadas) { marcarPalabraEnSolucion(palabra); } } function marcarPalabraEnSolucion(palabra) { const direcciones = [ [0, 1], [1, 0], [0, -1], [-1, 0], [1, 1], [1, -1], [-1, 1], [-1, -1] ]; for (let fila = 0; fila < filas; fila++) { for (let columna = 0; columna < columnas; columna++) { for (let direccion of direcciones) { let filaActual = fila; let columnaActual = columna; let coincide = true; for (let i = 0; i < palabra.length; i++) { if ( filaActual < 0 || filaActual >= filas || columnaActual < 0 || columnaActual >= columnas || tablero[filaActual][columnaActual] !== palabra[i] ) { coincide = false; break; } filaActual += direccion[0]; columnaActual += direccion[1]; } if (coincide) { filaActual = fila; columnaActual = columna; for (let i = 0; i < palabra.length; i++) { const celda = document.querySelector(`tr:nth-child(${filaActual + 1}) td:nth-child(${columnaActual + 1})`); celda.classList.add("solution"); filaActual += direccion[0]; columnaActual += direccion[1]; } return; } } } } } generarSopa(); </script> </body> </html>
Resultado
Instrucciones