class MemoryGame { constructor(options = {}) { this.words = options.words || []; this.pairsCount = options.pairsCount || 15; this.images = []; this.cards = []; this.flippedCards = []; this.score = 0; this.attempts = 0; this.isProcessing = false; this.startTime = Date.now(); this.timerInterval = null; this.recognition = null; this.sounds = { cardFlip: document.getElementById('cardFlipSound'), correctMatch: document.getElementById('correctMatchSound'), incorrectMatch: document.getElementById('incorrectMatchSound'), gameWin: document.getElementById('gameWinSound') }; this.remainingAttempts = 3; // Přidáno pro multiplayer this.players = options.players || [{ name: 'Hráč 1', score: 0 }]; this.currentPlayerIndex = 0; this.isMultiplayer = this.players.length > 1; // Přidáme vytvoření kontejneru hráčů před inicializací hry this.createPlayersContainer(); this.setupSpeechRecognition(); this.initGame(); } async initGame() { if (this.words.length === 0) { await this.loadWords(); } this.selectWords(); this.createGameBoard(); this.startTimer(); this.setupMicButton(); } async loadWords() { try { const urlParams = new URLSearchParams(window.location.search); const letter = urlParams.get('letter'); const response = await fetch('js/pexeso/words.json'); const data = await response.json(); this.words = data[letter] || []; } catch (error) { console.error('Chyba pri načitaní slov:', error); } } selectWords() { const shuffled = this.shuffleArray([...this.words]); this.images = shuffled.slice(0, this.pairsCount); this.images = [...this.images, ...this.images]; this.images = this.shuffleArray(this.images); } createGameBoard() { const gameContainer = document.getElementById('gameContainer'); gameContainer.innerHTML = ''; this.images.forEach((card, index) => { const cardElement = this.createCard(card, index); gameContainer.appendChild(cardElement); }); } createPlayersContainer() { // Najdeme nebo vytvoříme kontejner před herním kontejnerem let playersContainer = document.querySelector('.players-container'); if (!playersContainer) { playersContainer = document.createElement('div'); playersContainer.className = 'players-container'; // Vložíme kontejner před herní kontejner const gameContainer = document.getElementById('gameContainer'); gameContainer.parentNode.insertBefore(playersContainer, gameContainer); } // Vymažeme případný existující obsah playersContainer.innerHTML = ''; // Definujeme barvy pro hráče const playerColors = [ '#FF6B6B', // červená '#4ECDC4', // tyrkysová '#45B7D1', // modrá '#FDCB6E' // žlutá ]; // Vytvoříme prvky pro každého hráče this.players.forEach((player, index) => { const playerElement = document.createElement('div'); playerElement.className = 'player-indicator'; playerElement.dataset.playerIndex = index; // Přiřadíme barvu hráči const playerColor = playerColors[index % playerColors.length]; playerElement.innerHTML = `
Hráč: ${player.name}
Skóre: ${player.score}
`; // Zvýrazníme prvního hráče if (index === 0) { playerElement.classList.add('active-player'); } playersContainer.appendChild(playerElement); }); } createCard(card, index) { const cardElement = document.createElement('div'); cardElement.className = 'card'; cardElement.dataset.word = card.word; const img = document.createElement('img'); img.src = card.src; img.alt = card.word; const wordLabel = document.createElement('div'); wordLabel.textContent = card.word; wordLabel.className = 'card-word'; cardElement.appendChild(img); cardElement.appendChild(wordLabel); cardElement.addEventListener('click', () => this.flipCard(cardElement)); return cardElement; } flipCard(cardElement) { if (this.isProcessing || cardElement.classList.contains('flipped') || this.flippedCards.length >= 2) return; this.sounds.cardFlip.play(); cardElement.classList.add('flipped'); this.flippedCards.push(cardElement); if (this.flippedCards.length === 2) { this.checkMatch(); } } checkMatch() { this.attempts++; document.getElementById('attempts').textContent = this.attempts; const [card1, card2] = this.flippedCards; if (card1.dataset.word === card2.dataset.word) { this.handleCorrectMatch(); // V multiplayer módu zůstává současný hráč na tahu if (!this.isMultiplayer) { this.switchToNextPlayer(); } } else { this.handleIncorrectMatch(); // V multiplayer módu se mění hráč if (this.isMultiplayer) { this.switchToNextPlayer(); } } } switchToNextPlayer() { this.currentPlayerIndex = (this.currentPlayerIndex + 1) % this.players.length; this.updatePlayerIndicator(); } updatePlayerIndicator() { const playersContainer = document.querySelector('.players-container'); if (!playersContainer) return; const playerElements = playersContainer.querySelectorAll('.player-indicator'); playerElements.forEach((el, index) => { if (index === this.currentPlayerIndex) { el.classList.add('active-player'); } else { el.classList.remove('active-player'); } // Aktualizace skóre pro všechny hráče const scoresElement = el.querySelector('.player-scores'); if (scoresElement) { const player = this.players[index]; scoresElement.innerHTML = `Skóre: ${player.score}`; } }); } handleCorrectMatch() { this.sounds.correctMatch.play(); this.showSpeechContainer(); } handleIncorrectMatch() { this.sounds.incorrectMatch.play(); setTimeout(() => { this.flippedCards.forEach(card => card.classList.remove('flipped')); this.resetFlippedCards(); }, 1000); } showSpeechContainer() { const speechContainer = document.getElementById('speechContainer'); const gameWrapper = document.querySelector('.game-wrapper'); const matchText = document.getElementById('matchText'); const wordImage = document.getElementById('wordImage'); const card = this.flippedCards[0]; const word = card.dataset.word; // Nastavenie obrázka const img = card.querySelector('img'); wordImage.src = img.src; wordImage.alt = word; matchText.textContent = `${word}`; speechContainer.style.display = 'flex'; } setupSpeechRecognition() { if ('webkitSpeechRecognition' in window) { this.recognition = new webkitSpeechRecognition(); this.recognition.continuous = false; this.recognition.interimResults = false; this.recognition.lang = 'sk-SK'; this.recognition.onstart = () => { document.getElementById('recordingStatus').style.display = 'block'; }; this.recognition.onresult = (event) => { const spokenWord = event.results[0][0].transcript.toLowerCase(); this.checkSpokenWord(spokenWord); }; this.recognition.onend = () => { document.getElementById('recordingStatus').style.display = 'none'; }; } } setupMicButton() { const micButton = document.getElementById('micButton'); micButton.addEventListener('click', () => { if (this.recognition) { // Reset recognition pred každým novým pokusom this.recognition.abort(); this.recognition.start(); micButton.classList.add('active'); micButton.textContent = 'Počúvam 👂'; } else { alert('Rozpoznanie reči nie je podporované.'); } }); if (this.recognition) { this.recognition.onend = () => { document.getElementById('recordingStatus').style.display = 'none'; micButton.classList.remove('active'); micButton.textContent = 'Začni hovoriť 🎤'; }; } } checkSpokenWord(spokenWord) { const word = this.flippedCards[0].dataset.word; const speechContainer = document.getElementById('speechContainer'); const gameWrapper = document.querySelector('.game-wrapper'); // Pridáme rozmazanie pri zobrazení speech containera gameWrapper.classList.add('blurred'); if (spokenWord.includes(word)) { // Správna odpoveď this.showFeedback('spravne', () => { this.flippedCards.forEach(card => card.style.visibility = 'hidden'); if (this.isMultiplayer) { this.players[this.currentPlayerIndex].score++; this.updatePlayerIndicator(); } else { this.score++; } speechContainer.style.display = 'none'; gameWrapper.classList.remove('blurred'); this.remainingAttempts = 3; this.resetFlippedCards(); // Kontrola stavu hry this.checkGameState(); }); } else { // Nesprávna odpoveď this.remainingAttempts--; if (this.remainingAttempts > 0) { this.showFeedback('nespravne', () => { // Vrátime pôvodný obsah speech containera this.showSpeechContainer(); }); } else { this.showFeedback('nespravne', () => { this.flippedCards.forEach(card => { card.classList.remove('flipped'); }); speechContainer.style.display = 'none'; gameWrapper.classList.remove('blurred'); if (this.isMultiplayer) { this.switchToNextPlayer(); } this.remainingAttempts = 3; this.resetFlippedCards(); this.isProcessing = false; }); } } // Aktualizácia zobrazenia zostávajúcich pokusov const attemptsElement = document.querySelector('.attempts-left'); if (attemptsElement) { attemptsElement.textContent = `Počet zostávajúcich pokusov: ${this.remainingAttempts}`; } } showFeedback(type, callback) { const speechContainer = document.getElementById('speechContainer'); // Rozmazeme pôvodný obsah speech containera Array.from(speechContainer.children).forEach(child => { child.style.filter = 'blur(5px)'; }); // Vytvoríme nový feedback element const feedbackImage = document.createElement('img'); feedbackImage.className = 'feedback-image'; feedbackImage.src = `images/${type}.png`; feedbackImage.style.display = 'block'; // Pridáme feedback image speechContainer.appendChild(feedbackImage); // Prehráme zvuk pri správnej odpovedi if (type === 'spravne') { const sound = new Audio('zvuky/spravne.mp3'); sound.play(); } if (type === 'nespravne') { const sound = new Audio('zvuky/nespravne.mp3'); sound.play(); } // Po 1 sekunde odstránime feedback a zrušíme rozmazanie setTimeout(() => { feedbackImage.remove(); Array.from(speechContainer.children).forEach(child => { child.style.filter = 'none'; }); if (callback) callback(); }, 1000); } // Nová metóda pre kontrolu stavu hry checkGameState() { console.log('Checking game state...'); // debug const totalPairs = this.images.length / 2; // delíme 2, pretože každé slovo je v poli dvakrát if (this.isMultiplayer) { const totalScore = this.players.reduce((sum, player) => sum + player.score, 0); console.log('Multiplayer - Total score:', totalScore, 'Total pairs:', totalPairs); if (totalScore >= totalPairs) { console.log('Ending multiplayer game'); this.endGame(); } } else { console.log('Single player - Score:', this.score, 'Total pairs:', totalPairs); if (this.score >= totalPairs) { console.log('Ending single player game'); this.endGame(); } } } resetFlippedCards() { this.flippedCards = []; this.isProcessing = false; } startTimer() { const timerElement = document.getElementById('timer'); this.timerInterval = setInterval(() => { const currentTime = Math.floor((Date.now() - this.startTime) / 1000); const minutes = Math.floor(currentTime / 60); const seconds = currentTime % 60; timerElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; }, 1000); } endGame() { console.log('End game called'); // debug clearInterval(this.timerInterval); this.sounds.gameWin.play(); const endTime = Date.now(); const totalSeconds = Math.floor((endTime - this.startTime) / 1000); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; const gameEndModal = document.getElementById('gameEndModal'); console.log('Modal element:', gameEndModal); // debug if (!gameEndModal) { console.error('Game end modal not found!'); return; } try { document.getElementById('totalTime').textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`; document.getElementById('finalAttempts').textContent = this.attempts; if (this.isMultiplayer) { const winner = this.players.reduce((prev, current) => (prev.score > current.score) ? prev : current ); document.getElementById('winnerText').textContent = `Víťaz: ${winner.name}`; document.getElementById('finalScore').textContent = winner.score; } else { document.getElementById('winnerText').textContent = "Gratulujem!"; document.getElementById('finalScore').textContent = this.score; } gameEndModal.style.display = 'flex'; console.log('Modal should be visible now'); // debug // Odstránime existujúce event listenery (ak existujú) const restartBtn = document.getElementById('restartGameBtn'); const menuBtn = document.getElementById('backToMenuBtn'); restartBtn.replaceWith(restartBtn.cloneNode(true)); menuBtn.replaceWith(menuBtn.cloneNode(true)); // Pridáme nové event listenery document.getElementById('restartGameBtn').addEventListener('click', () => { console.log('Restart clicked'); // debug window.location.reload(); }); document.getElementById('backToMenuBtn').addEventListener('click', () => { console.log('Back to menu clicked'); // debug window.location.href = 'index.html'; }); } catch (error) { console.error('Error updating modal content:', error); } } 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; } } document.addEventListener('DOMContentLoaded', () => { const urlParams = new URLSearchParams(window.location.search); const isCustom = urlParams.get('custom'); const playersParam = urlParams.get('players'); if (isCustom) { const customWords = JSON.parse(decodeURIComponent(urlParams.get('words'))); const players = playersParam ? JSON.parse(decodeURIComponent(playersParam)) : [{ name: 'Hráč 1', score: 0 }]; new MemoryGame({ words: customWords, players: players }); } else { new MemoryGame(); } });