const roomController = require('./room'); const youtubeService = require('../services/youtubeService'); const shuffleArray = (array) => { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; }; const gameStates = {}; const initializeGameState = (roomId) => { if (!gameStates[roomId]) { gameStates[roomId] = { round: 0, phase: 'waiting', roles: {}, selectedSong: null, scores: {}, songOptions: [], guessResults: {}, currentComposer: null, roundStartTime: null, phaseTimeLimit: { composing: 30, guessing: 30 }, lastFrequency: 440, }; const users = roomController.getRoomUsers(roomId); users.forEach(user => { gameStates[roomId].scores[user.id] = 0; }); } return gameStates[roomId]; }; const startNewRound = async (roomId) => { const gameState = gameStates[roomId]; if (!gameState) return false; const users = roomController.getRoomUsers(roomId); if (users.length < 2) return false; gameState.round += 1; gameState.phase = 'composing'; gameState.guessResults = {}; gameState.roundStartTime = Date.now(); gameState.roles = {}; gameState.currentComposer = determineNextComposer(roomId, gameState, users); users.forEach(user => { gameState.roles[user.id] = user.id === gameState.currentComposer ? 'composer' : 'guesser'; }); return await selectSongAndOptions(gameState); }; const determineNextComposer = (roomId, gameState, users) => { if (gameState.round === 1 || !gameState.currentComposer) { return users[Math.floor(Math.random() * users.length)].id; } const currentIndex = users.findIndex(user => user.id === gameState.currentComposer); if (currentIndex === -1) { return users[Math.floor(Math.random() * users.length)].id; } return users[(currentIndex + 1) % users.length].id; }; // Then modify the selectSongAndOptions function to use the shuffle: const selectSongAndOptions = async (gameState) => { try { const availableIds = await youtubeService.getAvailableSongIds(); if (!availableIds || availableIds.length === 0) { console.error("No song IDs available for selection"); return false; } const selectedId = availableIds[Math.floor(Math.random() * availableIds.length)]; gameState.selectedSong = { id: selectedId }; const optionIds = new Set([selectedId]); const attempts = Math.min(20, availableIds.length); let count = 0; while (optionIds.size < 5 && count < attempts) { const randomId = availableIds[Math.floor(Math.random() * availableIds.length)]; optionIds.add(randomId); count++; } // Shuffle the song options to randomize the position of the correct answer gameState.songOptions = shuffleArray(Array.from(optionIds).map(id => ({ id }))); return true; } catch (error) { console.error("Error selecting songs and options:", error); return false; } }; const getTimeRemaining = (roomId) => { const gameState = gameStates[roomId]; if (!gameState || !gameState.roundStartTime) return 0; const phaseDuration = gameState.phaseTimeLimit[gameState.phase] * 1000; const timeElapsed = Date.now() - gameState.roundStartTime; const timeRemaining = Math.max(0, phaseDuration - timeElapsed); return Math.ceil(timeRemaining / 1000); }; const advancePhase = (roomId) => { const gameState = gameStates[roomId]; if (!gameState) { console.error(`Cannot advance phase: no game state for room ${roomId}`); return false; } const currentPhase = gameState.phase; console.log(`Advancing phase for room ${roomId} from ${currentPhase}`); if (currentPhase === 'composing') { gameState.phase = 'guessing'; gameState.roundStartTime = Date.now(); console.log(`Room ${roomId} advanced to guessing phase`); return { phase: 'guessing' }; } else if (currentPhase === 'guessing') { gameState.phase = 'results'; console.log(`Room ${roomId} advanced to results phase`); return { phase: 'results' }; } else if (currentPhase === 'results') { console.log(`Room ${roomId} starting new round from results phase`); return startNewRound(roomId); } console.warn(`Cannot advance from unknown phase "${currentPhase}" in room ${roomId}`); return false; }; const updateFrequency = (roomId, frequency) => { if (!gameStates[roomId]) return false; gameStates[roomId].lastFrequency = frequency; return true; }; const submitGuess = (roomId, userId, songId) => { const gameState = gameStates[roomId]; if (!gameState || gameState.phase !== 'guessing' || gameState.roles[userId] !== 'guesser') { return false; } const isCorrect = gameState.selectedSong.id === parseInt(songId); const points = isCorrect ? 10 : 0; gameState.guessResults[userId] = {songId, isCorrect, points}; if (isCorrect) { gameState.scores[userId] = (gameState.scores[userId] || 0) + points; } return { isCorrect, correctSong: gameState.selectedSong, points }; }; const getCurrentFrequency = (roomId) => gameStates[roomId]?.lastFrequency || 440; const getRoles = (roomId) => gameStates[roomId]?.roles || {}; const getUserRole = (roomId, userId) => gameStates[roomId]?.roles[userId] || null; const getSongOptions = (roomId) => gameStates[roomId]?.songOptions || []; const getSelectedSong = (roomId) => gameStates[roomId]?.selectedSong || null; const getRoundResults = (roomId) => { const gameState = gameStates[roomId]; if (!gameState) return {round: 0, scores: {}, guessResults: {}, selectedSong: null}; const playerNames = {}; Object.keys(gameState.scores).forEach(userId => { playerNames[userId] = roomController.getUserName(userId) || "Player"; }); return { round: gameState.round, selectedSong: gameState.selectedSong, guessResults: gameState.guessResults, scores: gameState.scores, playerNames: playerNames }; }; const cleanupGameState = (roomId) => { delete gameStates[roomId]; }; const getCurrentComposer = (roomId) => gameStates[roomId]?.currentComposer || null; const getGameState = (roomId) => { return gameStates[roomId] || null; }; module.exports = { initializeGameState, startNewRound, getTimeRemaining, advancePhase, updateFrequency, getCurrentFrequency, submitGuess, getRoundResults, getRoles, getUserRole, getSongOptions, getSelectedSong, cleanupGameState, getCurrentComposer, getGameState };