'use strict'; // SΓ­mbolos disponibles (>= 18 ΓΊnicos para niveles altos) const SYMBOLS = [ '🍎','🍌','πŸ’','πŸ‡','πŸ‰','πŸ‘','🍊','πŸ“', 'πŸ₯','🍍','πŸ₯₯','🍐','🍈','🍏','πŸ”','πŸ•', '🎈','⭐','πŸŒ™','β˜€οΈ','⚽','πŸ€','🎲','🎡', '🐢','🐱','🐼','🐸','🦊','🦁','πŸ¦„','🐯', 'πŸš—','πŸš€','✈️','🚲','🏝️','🏰' ]; const DIFFICULTIES = { facil: { pairs: 6 }, normal: { pairs: 8 }, dificil: { pairs: 12 }, extremo: { pairs: 18 } }; // Estado del juego let deck = []; // array de sΓ­mbolos duplicados y mezclados let firstCard = null; let secondCard = null; let lockBoard = false; let matches = 0; let moves = 0; let totalPairs = DIFFICULTIES.normal.pairs; let timerId = null; let startTime = 0; // DOM const gameBoard = document.getElementById('game-board'); const infoDiv = document.getElementById('info'); const resetBtn = document.getElementById('reset-btn'); const difficultySelect = document.getElementById('difficulty'); const movesSpan = document.getElementById('moves'); const timeSpan = document.getElementById('time'); const bestSpan = document.getElementById('best-score'); // Utils function shuffle(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]]; } } function pickSymbols(n) { const pool = SYMBOLS.slice(); shuffle(pool); return pool.slice(0, n); } function formatTime(seconds) { const s = Math.max(0, Math.floor(seconds)); return `${s}s`; } function bestKey(diff) { return `memory_best_time_${diff}`; } function getBest(diff) { const v = localStorage.getItem(bestKey(diff)); return v ? parseInt(v, 10) : null; } function setBestIfBetter(diff, timeSec) { const prev = getBest(diff); if (prev === null || timeSec < prev) { localStorage.setItem(bestKey(diff), String(timeSec)); } const best = getBest(diff); if (bestSpan) bestSpan.textContent = best !== null ? `${best}s` : 'β€”'; } function startTimer() { stopTimer(); startTime = Date.now(); timerId = setInterval(() => { const elapsed = (Date.now() - startTime) / 1000; if (timeSpan) timeSpan.textContent = formatTime(elapsed); }, 250); } function stopTimer() { if (timerId) { clearInterval(timerId); timerId = null; } } function gridColumnsFor(totalCards) { // Aproxima columnas en funciΓ³n del total para formar rejilla compacta if (totalCards <= 12) return 4; if (totalCards <= 16) return 4; if (totalCards <= 24) return 6; if (totalCards <= 30) return 6; return 6; } function setupBoard() { // Leer dificultad const diff = (difficultySelect && difficultySelect.value) || 'normal'; const conf = DIFFICULTIES[diff] || DIFFICULTIES.normal; totalPairs = conf.pairs; // Reiniciar estado matches = 0; moves = 0; firstCard = null; secondCard = null; lockBoard = false; if (movesSpan) movesSpan.textContent = String(moves); if (infoDiv) infoDiv.textContent = ''; // Construir mazo const chosen = pickSymbols(totalPairs); deck = [...chosen, ...chosen]; shuffle(deck); // Render tablero accesible gameBoard.textContent = ''; const totalCards = deck.length; const cols = gridColumnsFor(totalCards); gameBoard.style.gridTemplateColumns = `repeat(${cols}, 1fr)`; deck.forEach((symbol, idx) => { const cardEl = document.createElement('button'); cardEl.type = 'button'; cardEl.className = 'card'; cardEl.dataset.index = String(idx); cardEl.dataset.symbol = symbol; cardEl.textContent = ''; cardEl.setAttribute('role', 'gridcell'); cardEl.setAttribute('aria-label', 'Carta de memoria'); cardEl.setAttribute('aria-disabled', 'false'); cardEl.addEventListener('click', () => flipCard(cardEl)); cardEl.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); flipCard(cardEl); } }); gameBoard.appendChild(cardEl); }); // Mostrar mejor tiempo const best = getBest(diff); if (bestSpan) bestSpan.textContent = best !== null ? `${best}s` : 'β€”'; // Arrancar temporizador startTimer(); // Foco inicial const first = gameBoard.querySelector('.card'); if (first) first.focus(); } function flipCard(cardEl) { if (lockBoard) return; if (cardEl.classList.contains('flipped') || cardEl.classList.contains('matched')) return; // Voltear carta cardEl.classList.add('flipped'); cardEl.textContent = cardEl.dataset.symbol; cardEl.setAttribute('aria-disabled', 'true'); if (!firstCard) { firstCard = cardEl; return; } if (!secondCard && cardEl !== firstCard) { secondCard = cardEl; lockBoard = true; moves++; if (movesSpan) movesSpan.textContent = String(moves); if (firstCard.dataset.symbol === secondCard.dataset.symbol) { // Pareja encontrada firstCard.classList.add('matched'); secondCard.classList.add('matched'); matches++; setTimeout(() => { resetSelection(); if (matches === totalPairs) { // Fin de partida const elapsed = Math.floor((Date.now() - startTime) / 1000); if (infoDiv) infoDiv.textContent = `Β‘Felicidades! πŸŽ‰ Parejas: ${totalPairs} Β· Movimientos: ${moves} Β· Tiempo: ${elapsed}s`; stopTimer(); const diff = (difficultySelect && difficultySelect.value) || 'normal'; setBestIfBetter(diff, elapsed); } }, 400); } else { // No es pareja, desvoltear tras un momento setTimeout(() => { unflip(firstCard); unflip(secondCard); resetSelection(); }, 700); } } } function unflip(el) { if (!el) return; el.classList.remove('flipped'); el.textContent = ''; el.setAttribute('aria-disabled', 'false'); } function resetSelection() { firstCard = null; secondCard = null; lockBoard = false; } // Listeners resetBtn.addEventListener('click', () => { stopTimer(); setupBoard(); }); if (difficultySelect) { difficultySelect.addEventListener('change', () => { stopTimer(); setupBoard(); }); } // Init setupBoard();