const images = [ "images/fruit1.png", "images/fruit2.png", "images/fruit3.png", "images/fruit4.png", "images/fruit5.png", "images/fruit6.png", "images/fruit7.png", "images/fruit8.png", "images/fruit9.png", "images/fruit10.png" ]; let cards = [...images, ...images]; let flipped = []; let timerStarted = false; let time = 60; let moves = 0; let score = 0; let countdown; let combo = 1; let lastMatchTime = 0; let pendingMatch = false; function showComboPopup(targetCard, combo, bonus) { const popup = document.createElement("div"); popup.className = "combo-popup"; popup.innerHTML = `COMBO X${combo}
+${bonus} Bonus`; const rect = targetCard.getBoundingClientRect(); popup.style.left = rect.left + rect.width / 2 + "px"; popup.style.top = rect.top + "px"; popup.style.position = "fixed"; document.body.appendChild(popup); setTimeout(() => popup.remove(), 1500); } function shuffleDistant(cards, minDistance = 4) { let valid = false; let result; let attempts = 0; while (!valid) { result = [...cards]; for (let i = result.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [result[i], result[j]] = [result[j], result[i]]; } valid = true; const checked = new Set(); attempts++; if (attempts > 2000) { console.warn("Gagal menemukan posisi yang valid. Mengembalikan hasil acak."); break; } for (let i = 0; i < result.length; i++) { const value = result[i]; if (checked.has(value)) continue; checked.add(value); const indices = []; for (let k = 0; k < result.length; k++) { if (result[k] === value) indices.push(k); } for (let j = 0; j < indices.length - 1; j++) { const distance = indices[j+1] - indices[j]; if (distance < minDistance) { valid = false; break; } } if (!valid) break; } } return result; } function runCountdown(callback) { let count = 3; overlay.style.display = "flex"; overlay.innerHTML = `${count}`; playSFX(sfxCountdown); let cdTimer = setInterval(() => { count--; if (count > 0) { overlay.innerHTML = `${count}`; playSFX(sfxCountdown); } else if (count === 0) { overlay.innerHTML = `GO!`; } else { clearInterval(cdTimer); overlay.style.display = "none"; callback(); } }, 1000); } function startTimer() { timerStarted = true; countdown = setInterval(() => { document.getElementById("timer").textContent = --time; if (time <= 0) { clearInterval(countdown); showEndScreen(false); } }, 1000); } function showEndScreen(isWin) { clearInterval(countdown); bgMusic.pause(); if(isWin) playSFX(sfxWin); else playSFX(sfxLose); const titleEl = document.getElementById("endTitleDisplay"); const msgEl = document.getElementById("endMsgDisplay"); if (titleEl) titleEl.textContent = isWin ? "🎉 Selamat!" : "⏰ Waktu Habis!"; if (msgEl) msgEl.textContent = isWin ? "Anda berhasil menyelesaikan permainan!" : "Coba lagi lain kali!"; let baseScore = score; let timeBonus = isWin ? time * 5 : 0; let moveBonus = isWin ? Math.max(0, 200 - moves * 10) : 0; let total = baseScore + timeBonus + moveBonus; document.getElementById("baseScoreEnd").textContent = baseScore; document.getElementById("timeBonusEnd").textContent = "+" + timeBonus; document.getElementById("moveBonusEnd").textContent = "+" + moveBonus; document.getElementById("totalScoreEnd").textContent = total; document.getElementById("endScreen").style.display = "flex"; if (isWin) { let formData = new FormData(); formData.append('score', total); formData.append('difficulty', 'Hard'); fetch('score.php', { method: 'POST', body: formData }) .then(response => response.text()) .then(result => console.log("Status Database: " + result)) .catch(error => console.error('Error:', error)); } } function flipCard(card) { if (!timerStarted) startTimer(); if (flipped.length === 2 || card.classList.contains("matched") || card.classList.contains("flipped")) return; playSFX(sfxClick); card.classList.add("flipped"); flipped.push(card); if (flipped.length === 2) { moves++; document.getElementById("moves").textContent = moves; let img1 = flipped[0].querySelector("img").src; let img2 = flipped[1].querySelector("img").src; if (img1 === img2) { playSFX(sfxMatch); const now = Date.now(); if (!pendingMatch) { pendingMatch = true; combo = 1; } else { if (now - lastMatchTime <= 3000) { combo++; let comboBonus = combo * 10; score += comboBonus; showComboPopup(flipped[0], combo, comboBonus); } else { combo = 1; } } lastMatchTime = now; flipped.forEach(c => c.classList.add("matched")); score += 50; document.getElementById("score").textContent = score; time += 5; document.getElementById("timer").textContent = time; // Update tampilan waktu bonus flipped = []; if (document.querySelectorAll(".matched").length === cards.length) { setTimeout(() => showEndScreen(true), 600); } } else { playSFX(sfxWrong); setTimeout(() => { flipped.forEach(c => c.classList.remove("flipped")); flipped = []; }, 800); } } } function startGame() { document.getElementById("endScreen").style.display = "none"; const board = document.getElementById("game-board"); board.innerHTML = ""; runCountdown(() => { if(!musicMuted) bgMusic.play().catch(() => {}); const shuffledCards = shuffleDistant([...cards]); shuffledCards.forEach(image => { const card = document.createElement("div"); card.className = "card"; card.innerHTML = `
?
`; card.onclick = () => flipCard(card); board.appendChild(card); }); time = 60; moves = 0; score = 0; combo = 1; pendingMatch = false; flipped = []; timerStarted = false; document.getElementById("timer").textContent = time; document.getElementById("moves").textContent = moves; document.getElementById("score").textContent = score; }); } startGame();