Crea un juego de relacionar elementos mediante arrastrables para trabajar [Temática deseada]. Utiliza como fundamento el siguiente código que te facilito:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aventura Geométrica: ¡Arrastra y Adivina!</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #e0f7fa; /* Celeste muy claro */
}
.game-container {
max-width: 1000px;
background-color: white;
border-radius: 12px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}
.draggable-item {
background-color: #ffe0b2;
color: #4e342e;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
cursor: grab;
transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
user-select: none;
}
.draggable-item:hover {
transform: translateY(-1px);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
}
.dragging { /* Clase aplicada mientras se arrastra un elemento */
opacity: 0.5;
transform: scale(1.03);
cursor: grabbing;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
.placed-item { /* Estilo para el elemento una vez colocado en una zona de respuesta */
background-color: #ffcc80;
color: #4e342e;
border-radius: 6px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
cursor: grab; /* Cambiará a 'default' si está bloqueado */
transition: transform 0.15s ease, box-shadow 0.15s ease;
user-select: none;
}
.drop-zone {
border: 1px dashed #bdbdbd;
background-color: #f8f8f8;
border-radius: 6px;
transition: background-color 0.15s ease, border-color 0.15s ease;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
}
.drop-zone.over { /* Estilo cuando un elemento arrastrable está sobre la zona */
background-color: #d4ead6;
border-color: #5cb85c;
}
.drop-zone[data-locked="true"] { /* Estilo para una zona de respuesta bloqueada */
border-style: solid;
border-color: #a5d6a7; /* Un verde más claro para indicar bloqueo sutil */
}
.feedback-dot {
width: 14px;
height: 14px;
border-radius: 50%;
background-color: #ffcc80;
transition: background-color 0.2s ease, transform 0.2s ease;
flex-shrink: 0;
}
.feedback-dot.correct {
background-color: #66bb6a;
transform: scale(1.1);
}
.feedback-dot.incorrect {
background-color: #ef5350;
}
.progress-bar-fill {
background-color: #4caf50;
transition: width 0.4s ease-in-out;
border-radius: 4px;
}
.progressScoreArea {
background-color: #f0f0f0;
padding: 0.6rem;
border-radius: 8px;
}
.hidden-in-pool {
display: none !important;
}
/* Ajustes responsivos */
@media (max-width: 768px) {
.game-container {
padding: 0.75rem;
}
.shape-row {
flex-direction: column;
align-items: stretch;
padding: 0.5rem;
}
.shape-description, .shape-display-segment, .drop-zone-container {
width: 100% !important;
margin-bottom: 0.4rem;
}
.shape-display-segment {
flex-direction: row;
align-items: center;
padding: 0.25rem;
}
.shape-image-container {
margin-right: 0.4rem;
}
.draggableOptionsContainer {
justify-content: center;
padding: 0.5rem;
gap: 0.4rem;
}
h1 {
font-size: 1.5rem;
}
header p {
font-size: 0.875rem;
}
}
</style>
</head>
<body class="min-h-screen flex items-center justify-center p-1 sm:p-2">
<div id="game-container" class="game-container w-full p-3 md:p-4">
<header class="text-center mb-3 md:mb-4">
<h1 class="text-xl sm:text-2xl md:text-3xl font-bold text-gray-800">Aventura Geométrica</h1>
<p class="text-xs sm:text-sm md:text-base text-gray-600 mt-1">Arrastra el nombre a su forma correcta.</p>
</header>
<div id="progressScoreArea" class="progressScoreArea mb-3 md:mb-4">
<div class="flex flex-col sm:flex-row justify-between items-center mb-1.5 space-y-1 sm:space-y-0">
<div id="scoreDisplay" class="text-sm md:text-base font-semibold text-gray-700">Formas: 0 de 0</div>
<div id="progressPercentageDisplay" class="text-sm md:text-base font-semibold text-gray-700">0%</div>
</div>
<div class="w-full bg-gray-300 rounded-full h-2.5 md:h-3 overflow-hidden">
<div id="progressBar" class="progress-bar-fill h-full rounded-full" style="width: 0%;"></div>
</div>
<p id="completionMessage" class="text-center text-green-600 font-semibold mt-1.5 text-base md:text-lg" style="display: none;">
¡Fantástico! ¡Conoces todas las formas!
</p>
</div>
<div id="draggableOptionsContainer" class="draggableOptionsContainer flex flex-wrap gap-1.5 p-1.5 sm:p-2 border border-gray-200 rounded-lg mb-3 md:mb-4 min-h-[50px] bg-gray-50 justify-center items-center">
</div>
<div id="gameArea" class="space-y-2 md:space-y-3">
</div>
</div>
<script>
// --- DATOS DEL JUEGO ---
const shapesData = [
{
id: "row1", // Círculo
imageSVG: `<svg viewBox="0 0 100 100" width="50" height="50">
<circle cx="50" cy="50" r="45" fill="#42a5f5" stroke="#1e88e5" stroke-width="2.5"/>
<circle cx="35" cy="45" r="10" fill="#FFFFFF"/>
<circle cx="65" cy="45" r="10" fill="#FFFFFF"/>
<circle cx="37" cy="48" r="5" fill="#2c3e50"/>
<circle cx="63" cy="48" r="5" fill="#2c3e50"/>
<circle cx="40" cy="42" r="2.5" fill="white" opacity="0.9"/>
<circle cx="68" cy="42" r="2.5" fill="white" opacity="0.9"/>
<path d="M35 65 Q50 78 65 65" stroke="#FFFFFF" stroke-width="3" fill="none" stroke-linecap="round"/>
<circle cx="22" cy="58" r="7" fill="#81d4fa" opacity="0.7"/>
<circle cx="78" cy="58" r="7" fill="#81d4fa" opacity="0.7"/>
</svg>`,
title: "Círculo",
summary: "Redondo como el sol, sin esquinas."
},
{
id: "row2", // Cuadrado
imageSVG: `<svg viewBox="0 0 100 100" width="50" height="50">
<rect x="10" y="10" width="80" height="80" fill="#ef5350" rx="5" stroke="#c62828" stroke-width="2.5"/>
<circle cx="35" cy="42" r="10" fill="#FFFFFF"/>
<circle cx="65" cy="42" r="10" fill="#FFFFFF"/>
<circle cx="37" cy="45" r="5" fill="#2c3e50"/>
<circle cx="63" cy="45" r="5" fill="#2c3e50"/>
<circle cx="40" cy="39" r="2.5" fill="white" opacity="0.9"/>
<circle cx="68" cy="39" r="2.5" fill="white" opacity="0.9"/>
<path d="M35 68 Q50 80 65 68" stroke="#FFFFFF" stroke-width="3" fill="none" stroke-linecap="round"/>
<ellipse cx="22" cy="60" rx="8" ry="5" fill="#ff8a80" opacity="0.7"/>
<ellipse cx="78" cy="60" rx="8" ry="5" fill="#ff8a80" opacity="0.7"/>
</svg>`,
title: "Cuadrado",
summary: "Cuatro lados iguales, ángulos rectos."
},
{
id: "row3", // Triángulo
imageSVG: `<svg viewBox="0 0 100 100" width="50" height="50">
<polygon points="50,5 95,88 5,88" fill="#66bb6a" stroke="#388e3c" stroke-width="2.5"/>
<circle cx="40" cy="60" r="9" fill="#FFFFFF"/>
<circle cx="60" cy="60" r="9" fill="#FFFFFF"/>
<circle cx="42" cy="63" r="4.5" fill="#2c3e50"/>
<circle cx="58" cy="63" r="4.5" fill="#2c3e50"/>
<circle cx="45" cy="57" r="2" fill="white" opacity="0.9"/>
<circle cx="63" cy="57" r="2" fill="white" opacity="0.9"/>
<path d="M40 75 Q50 82 60 75" stroke="#FFFFFF" stroke-width="2.5" fill="none" stroke-linecap="round"/>
<circle cx="28" cy="72" r="6" fill="#a5d6a7" opacity="0.8"/>
<circle cx="72" cy="72" r="6" fill="#a5d6a7" opacity="0.8"/>
</svg>`,
title: "Triángulo",
summary: "Tres lados y tres ángulos. Como pizza."
},
{
id: "row4", // Rectángulo
imageSVG: `<svg viewBox="0 0 120 80" width="60" height="40">
<rect x="10" y="10" width="100" height="60" fill="#ffa726" rx="5" stroke="#f57c00" stroke-width="2.5"/>
<circle cx="40" cy="38" r="9" fill="#FFFFFF"/>
<circle cx="80" cy="38" r="9" fill="#FFFFFF"/>
<circle cx="42" cy="41" r="4.5" fill="#2c3e50"/>
<circle cx="78" cy="41" r="4.5" fill="#2c3e50"/>
<circle cx="45" cy="35" r="2" fill="white" opacity="0.9"/>
<circle cx="83" cy="35" r="2" fill="white" opacity="0.9"/>
<path d="M38 58 Q60 70 82 58" stroke="#FFFFFF" stroke-width="3" fill="none" stroke-linecap="round"/>
<ellipse cx="25" cy="50" rx="7" ry="4.5" fill="#ffcc80" opacity="0.7"/>
<ellipse cx="95" cy="50" rx="7" ry="4.5" fill="#ffcc80" opacity="0.7"/>
</svg>`,
title: "Rectángulo",
summary: "Como el cuadrado, dos lados más largos."
},
{
id: "row5", // Estrella
imageSVG: `<svg viewBox="0 0 100 100" width="50" height="50">
<polygon points="50,2 63,38 98,38 70,60 79,96 50,75 21,96 30,60 2,38 37,38" fill="#ffee58" stroke="#fbc02d" stroke-width="2"/>
<circle cx="45" cy="52" r="8" fill="#FFFFFF"/>
<circle cx="55" cy="52" r="8" fill="#FFFFFF"/>
<circle cx="46.5" cy="54.5" r="4" fill="#4E342E"/>
<circle cx="53.5" cy="54.5" r="4" fill="#4E342E"/>
<circle cx="49" cy="49" r="2" fill="white" opacity="0.9"/>
<circle cx="51" cy="49" r="2" fill="white" opacity="0.9"/>
<path d="M42 65 Q50 72 58 65" stroke="#4E342E" stroke-width="2.5" fill="none" stroke-linecap="round"/>
<circle cx="35" cy="62" r="5" fill="#fff59d" opacity="0.8"/>
<circle cx="65" cy="62" r="5" fill="#fff59d" opacity="0.8"/>
</svg>`,
title: "Estrella",
summary: "Brilla en la noche, tiene varias puntas."
}
];
// --- VARIABLES GLOBALES DEL JUEGO ---
let score = 0;
let totalQuestions = shapesData.length;
let draggedItem = null;
let originalSourceContainer = null;
// --- ELEMENTOS DEL DOM ---
const draggableOptionsContainer = document.getElementById('draggableOptionsContainer');
const gameArea = document.getElementById('gameArea');
const scoreDisplay = document.getElementById('scoreDisplay');
const progressPercentageDisplay = document.getElementById('progressPercentageDisplay');
const progressBar = document.getElementById('progressBar');
const completionMessage = document.getElementById('completionMessage');
// --- FUNCIONES DEL JUEGO ---
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
function initializeGame() {
score = 0;
draggableOptionsContainer.innerHTML = '';
gameArea.innerHTML = '';
completionMessage.style.display = 'none';
// Reiniciar el estado 'locked' de las drop zones si se reinicia el juego
document.querySelectorAll('.drop-zone').forEach(dz => {
dz.dataset.locked = 'false';
dz.classList.remove('border-solid', 'border-green-200'); // Quitar estilos de bloqueo
});
const shapeNames = shapesData.map(shape => shape.title);
const shuffledShapeNames = shuffleArray([...shapeNames]);
shuffledShapeNames.forEach(name => {
const draggableDiv = document.createElement('div');
draggableDiv.classList.add('draggable-item', 'p-1.5', 'm-0.5', 'text-center', 'font-semibold', 'text-xs', 'sm:text-sm');
draggableDiv.textContent = name;
draggableDiv.draggable = true; // Asegurarse de que sean arrastrables al inicio
draggableDiv.style.cursor = 'grab'; // Asegurar cursor de arrastre
draggableDiv.dataset.shapeName = name;
draggableDiv.id = `draggable-${name.toLowerCase().replace(/\s+/g, '-')}`;
draggableOptionsContainer.appendChild(draggableDiv);
});
shapesData.forEach(shape => {
const shapeRow = document.createElement('div');
shapeRow.classList.add('shape-row', 'flex', 'flex-col', 'md:flex-row', 'items-center', 'p-1.5', 'md:p-2', 'bg-white', 'rounded-md', 'shadow-sm');
shapeRow.id = shape.id;
shapeRow.dataset.expectedShapeName = shape.title;
const descriptionDiv = document.createElement('div');
descriptionDiv.classList.add('shape-description', 'w-full', 'md:w-2/5', 'p-1', 'text-gray-700', 'text-xs', 'sm:text-sm');
descriptionDiv.textContent = shape.summary;
const displaySegmentDiv = document.createElement('div');
displaySegmentDiv.classList.add('shape-display-segment', 'w-full', 'md:w-1/5', 'p-1', 'flex', 'items-center', 'justify-center', 'md:justify-start');
const imageContainer = document.createElement('div');
imageContainer.classList.add('shape-image-container', 'mr-1.5');
imageContainer.innerHTML = shape.imageSVG;
const feedbackDot = document.createElement('div');
feedbackDot.classList.add('feedback-dot');
displaySegmentDiv.appendChild(imageContainer);
displaySegmentDiv.appendChild(feedbackDot);
const dropZoneContainerDiv = document.createElement('div');
dropZoneContainerDiv.classList.add('drop-zone-container', 'w-full', 'md:w-2/5', 'p-1');
const dropZoneDiv = document.createElement('div');
dropZoneDiv.classList.add('drop-zone', 'p-1.5', 'text-gray-500');
dropZoneDiv.textContent = "Arrastra aquí";
dropZoneDiv.dataset.expectedShapeName = shape.title;
dropZoneDiv.dataset.locked = 'false'; // Inicializar como no bloqueada
dropZoneContainerDiv.appendChild(dropZoneDiv);
shapeRow.appendChild(descriptionDiv);
shapeRow.appendChild(displaySegmentDiv);
shapeRow.appendChild(dropZoneContainerDiv);
gameArea.appendChild(shapeRow);
});
addDragAndDropListeners();
updateScoreAndProgressDisplay();
checkGameCompletion();
}
function addDragAndDropListeners() {
document.querySelectorAll('.draggable-item, .placed-item').forEach(item => {
// Solo añadir listeners si el item es realmente arrastrable
if (item.draggable) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragend', handleDragEnd);
}
});
document.querySelectorAll('.drop-zone, #draggableOptionsContainer').forEach(zone => {
zone.addEventListener('dragover', handleDragOver);
zone.addEventListener('dragleave', handleDragLeave);
zone.addEventListener('drop', handleDrop);
});
}
function handleDragStart(event) {
// Solo permitir arrastrar si el elemento no está bloqueado (implícito por draggable=true)
// y la zona de origen no está bloqueada (si es un placed-item)
if (event.target.draggable) {
draggedItem = event.target;
originalSourceContainer = draggedItem.parentElement;
// No permitir arrastrar desde una zona de respuesta ya bloqueada
if (originalSourceContainer.classList.contains('drop-zone') && originalSourceContainer.dataset.locked === 'true') {
event.preventDefault(); // Prevenir el arrastre
draggedItem = null;
originalSourceContainer = null;
return;
}
event.dataTransfer.setData('text/plain', draggedItem.dataset.shapeName);
event.target.classList.add('dragging');
} else {
event.preventDefault(); // Prevenir el arrastre si draggable es false
}
}
function handleDragEnd(event) {
if (draggedItem) { // Solo actuar si un arrastre válido comenzó
draggedItem.classList.remove('dragging');
}
draggedItem = null;
originalSourceContainer = null;
}
function handleDragOver(event) {
event.preventDefault();
const targetZone = event.target.closest('.drop-zone, #draggableOptionsContainer');
if (targetZone) {
// No mostrar 'over' si la zona de respuesta está bloqueada
if (targetZone.classList.contains('drop-zone') && targetZone.dataset.locked === 'true') {
return;
}
targetZone.classList.add('over');
}
}
function handleDragLeave(event) {
const targetZone = event.target.closest('.drop-zone, #draggableOptionsContainer');
if (targetZone) {
targetZone.classList.remove('over');
}
}
function handleDrop(event) {
event.preventDefault();
if (!draggedItem) return; // Si no hay item arrastrado (p.ej. porque se previno en dragstart)
const targetDropZoneElement = event.target.closest('.drop-zone, #draggableOptionsContainer');
if (!targetDropZoneElement) {
draggedItem.classList.remove('dragging'); // Limpiar si se suelta fuera de una zona válida
return;
}
targetDropZoneElement.classList.remove('over');
const draggedShapeName = draggedItem.dataset.shapeName;
// A. Si la zona de destino es el CONTENEDOR DE OPCIONES ARRASTRABLES (pool)
if (targetDropZoneElement.id === 'draggableOptionsContainer') {
if (draggedItem.classList.contains('placed-item') && originalSourceContainer.classList.contains('drop-zone')) {
// Solo procesar si la zona de origen NO estaba bloqueada
if (originalSourceContainer.dataset.locked !== 'true') {
handleItemRemovedFromDropZone(originalSourceContainer);
const originalPoolItem = draggableOptionsContainer.querySelector(`.draggable-item[data-shape-name="${draggedShapeName}"]`);
if (originalPoolItem) {
originalPoolItem.classList.remove('hidden-in-pool');
}
draggedItem.remove(); // Eliminar el 'placed-item' que se arrastró de vuelta
}
}
}
// B. Si la zona de destino es una ZONA DE RESPUESTA
else if (targetDropZoneElement.classList.contains('drop-zone')) {
// SI LA ZONA YA ESTÁ BLOQUEADA CON UNA RESPUESTA CORRECTA, RECHAZAR EL DROP
if (targetDropZoneElement.dataset.locked === 'true') {
draggedItem.classList.remove('dragging'); // Limpiar clase dragging
return;
}
const targetShapeRow = targetDropZoneElement.closest('.shape-row');
const expectedShapeName = targetShapeRow.dataset.expectedShapeName;
let itemToPlaceInTarget;
// B.1. Manejar item existente en la zona de destino (si la zona no está bloqueada)
const existingPlacedItem = targetDropZoneElement.querySelector('.placed-item');
if (existingPlacedItem && existingPlacedItem !== draggedItem) {
handleItemRemovedFromDropZone(targetDropZoneElement);
const originalPoolItemForExisting = draggableOptionsContainer.querySelector(`.draggable-item[data-shape-name="${existingPlacedItem.dataset.shapeName}"]`);
if (originalPoolItemForExisting) {
originalPoolItemForExisting.classList.remove('hidden-in-pool');
}
existingPlacedItem.remove();
}
// B.2. Manejar si el item se mueve desde OTRA ZONA DE RESPUESTA (y esa origen no está bloqueada)
if (originalSourceContainer && originalSourceContainer.classList.contains('drop-zone') &&
originalSourceContainer !== targetDropZoneElement &&
originalSourceContainer.dataset.locked !== 'true') {
handleItemRemovedFromDropZone(originalSourceContainer);
}
// B.3. Colocar el elemento arrastrado
targetDropZoneElement.innerHTML = ''; // Limpiar placeholder o item anterior
if (draggedItem.classList.contains('draggable-item')) { // Si viene del pool de opciones
itemToPlaceInTarget = draggedItem.cloneNode(true);
itemToPlaceInTarget.classList.remove('dragging'); // Asegurar que no tenga opacidad
itemToPlaceInTarget.classList.remove('draggable-item', 'p-1.5', 'm-0.5');
itemToPlaceInTarget.classList.add('placed-item', 'p-1', 'w-auto', 'max-w-full', 'text-xs', 'sm:text-sm', 'font-semibold');
itemToPlaceInTarget.draggable = true; // Inicialmente arrastrable
itemToPlaceInTarget.addEventListener('dragstart', handleDragStart);
itemToPlaceInTarget.addEventListener('dragend', handleDragEnd);
targetDropZoneElement.appendChild(itemToPlaceInTarget);
// Ocultar el original del pool (esto se mantiene, ya que si es incorrecto, se puede devolver)
draggedItem.classList.add('hidden-in-pool');
} else if (draggedItem.classList.contains('placed-item')) { // Si se mueve desde otra zona de respuesta
itemToPlaceInTarget = draggedItem;
itemToPlaceInTarget.classList.remove('dragging'); // Asegurar que no tenga opacidad
targetDropZoneElement.appendChild(itemToPlaceInTarget);
}
// B.4. Validación y actualización de la zona de destino
if (itemToPlaceInTarget) {
const isCorrect = itemToPlaceInTarget.dataset.shapeName === expectedShapeName;
const feedbackDot = targetShapeRow.querySelector('.feedback-dot');
feedbackDot.classList.remove('correct', 'incorrect');
if (isCorrect) {
feedbackDot.classList.add('correct');
if (targetDropZoneElement.dataset.locked !== 'true') { // Solo sumar puntos si no estaba ya bloqueada como correcta
score++;
}
// BLOQUEAR EL ITEM Y LA ZONA
itemToPlaceInTarget.draggable = false;
itemToPlaceInTarget.style.cursor = 'default';
targetDropZoneElement.dataset.locked = 'true';
} else {
feedbackDot.classList.add('incorrect');
// Si es incorrecto, el item original del pool (draggedItem) ya se ocultó.
// Si el usuario devuelve el item incorrecto (itemToPlaceInTarget) al pool,
// la lógica en la sección A se encargará de volver a mostrar el original.
}
}
}
draggedItem.classList.remove('dragging'); // Limpiar clase al final del drop
updateScoreAndProgressDisplay();
checkGameCompletion();
}
function handleItemRemovedFromDropZone(dropZoneElement) {
// Esta función solo se llama si la dropZoneElement NO estaba bloqueada.
const shapeRow = dropZoneElement.closest('.shape-row');
if (!shapeRow) return;
const feedbackDot = shapeRow.querySelector('.feedback-dot');
// No restar puntos si se quita un item de una zona que ya estaba marcada como correcta y bloqueada
// (aunque la lógica actual previene quitar de zonas bloqueadas).
// Esta condición es una salvaguarda.
if (feedbackDot.classList.contains('correct') && dropZoneElement.dataset.locked !== 'true') {
// Si era correcto pero la zona no estaba bloqueada (ej. un error previo), no se debería restar.
// La puntuación se maneja principalmente al colocar correctamente.
// Considerar si es necesario restar puntos aquí. Por ahora, la lógica de bloqueo previene esto.
}
feedbackDot.classList.remove('correct', 'incorrect');
dropZoneElement.innerHTML = 'Arrastra aquí';
dropZoneElement.dataset.locked = 'false'; // Asegurarse que la zona se marca como no bloqueada
}
function updateScoreAndProgressDisplay() {
scoreDisplay.textContent = `Formas: ${score} de ${totalQuestions}`;
const progress = totalQuestions > 0 ? (Math.min(score, totalQuestions) / totalQuestions) * 100 : 0; // Asegurar que no pase de 100%
progressPercentageDisplay.textContent = `${Math.round(progress)}%`;
progressBar.style.width = `${progress}%`;
}
function checkGameCompletion() {
// La condición de juego completo es que todas las zonas estén bloqueadas Y la puntuación sea la total.
let allZonesCorrectlyLocked = true;
if (score < totalQuestions) {
allZonesCorrectlyLocked = false;
} else {
document.querySelectorAll('.drop-zone').forEach(dz => {
if (dz.dataset.locked !== 'true') {
allZonesCorrectlyLocked = false;
}
});
}
if (allZonesCorrectlyLocked) {
completionMessage.style.display = 'block';
} else {
completionMessage.style.display = 'none';
}
}
// --- INICIO DEL JUEGO ---
document.addEventListener('DOMContentLoaded', initializeGame);
</script>
</body>
</html>