diff --git a/api/app/Http/Controllers/GameController.php b/api/app/Http/Controllers/GameController.php index 5590763..bde41ba 100644 --- a/api/app/Http/Controllers/GameController.php +++ b/api/app/Http/Controllers/GameController.php @@ -13,10 +13,10 @@ class GameController extends Controller public function index(Request $request) { $this->authorize('viewAny', Game::class); - + $user = Auth::user(); $query = Game::query()->with(["winner", "player1", "player2"]); - + // Filter games based on user type if ($user->type !== 'A') { // Players can only see games they participate in @@ -55,7 +55,7 @@ class GameController extends Controller public function store(Request $request) { $this->authorize('create', Game::class); - + $validated = $request->validate([ "type" => "required|in:3,9", ]); @@ -77,7 +77,7 @@ class GameController extends Controller "type" => $validated["type"], "status" => "Pending", "player1_user_id" => $user->id, - "player2_user_id" => self::GHOST_ID, + "player2_user_id" => self::GHOST_ID, "winner_user_id" => self::GHOST_ID, "loser_user_id" => self::GHOST_ID, "began_at" => now(), @@ -92,38 +92,30 @@ class GameController extends Controller ], 201); } - public function join(Game $game) - { - $this->authorize('join', $game); - - $user = Auth::user(); - - if ($game->player1_user_id == $user->id) { - return response()->json([ - "message" => "You are the host. Waiting for opponent...", - "game" => $game - ], 200); - } - - if ($game->player2_user_id !== self::GHOST_ID) { - return response()->json(["message" => "Game is full"], 400); - } - - $game->update([ - "status" => "Playing", - "player2_user_id" => $user->id, - ]); - - return response()->json([ - "message" => "Joined successfully!", - "game" => $game, - ], 200); +public function join(Request $request, Game $game) +{ + // Prevent joining if already full or started + if ($game->status !== 'Pending' || $game->player2_user_id !== 1) { + return response()->json(['message' => 'Game is not available'], 400); } + // Prevent joining your own game + if ($game->player1_user_id === $request->user()->id) { + return response()->json(['message' => 'Cannot join your own game'], 400); + } + + $game->update([ + 'player2_user_id' => $request->user()->id, + 'status' => 'Playing', + ]); + + return response()->json($game); +} + public function show(Game $game) { $this->authorize('view', $game); - + $game->load(["player1", "player2", "winner"]); return response()->json($game); } @@ -131,7 +123,7 @@ class GameController extends Controller public function update(Request $request, Game $game) { $this->authorize('update', $game); - + if ($game->status == "Ended") { return response()->json(["message" => "Game already ended"], 400); } @@ -158,13 +150,13 @@ class GameController extends Controller public function resign(Game $game) { $this->authorize('resign', $game); - + $user = Auth::user(); - + $game->update([ 'status' => 'Ended', - 'winner_user_id' => $game->player1_user_id === $user->id - ? $game->player2_user_id + 'winner_user_id' => $game->player1_user_id === $user->id + ? $game->player2_user_id : $game->player1_user_id, 'loser_user_id' => $user->id, 'ended_at' => now(), diff --git a/api/routes/api.php b/api/routes/api.php index 7ece2e8..cc96ded 100644 --- a/api/routes/api.php +++ b/api/routes/api.php @@ -47,8 +47,8 @@ Route::prefix('v1')->group(function () { }); Route::prefix('games')->group(function () { - // Host a new multiplayer game - Route::post('/host', function (\Illuminate\Http\Request $request) { + //Host a new multiplayer game - MUST come before resource routes + Route::post('host', function (\Illuminate\Http\Request $request) { $request->validate([ 'type' => 'required|in:3,9' ]); @@ -61,7 +61,21 @@ Route::prefix('v1')->group(function () { 'began_at' => now(), ]); - return response()->json($game); + return response()->json($game); + }); + + // List open games (available to join) + Route::get('open', function (\Illuminate\Http\Request $request) { + $type = $request->query('type', '9'); + + $games = \App\Models\Game::where('status', 'Pending') + ->where('player2_user_id', 1) // Only games waiting for a second player + ->where('type', $type) + ->with('player1') // Load player1 relationship + ->orderBy('began_at', 'asc') + ->paginate(10); + + return response()->json($games); }); Route::get('/', [GameController::class, 'index']); @@ -75,7 +89,7 @@ Route::prefix('v1')->group(function () { Route::prefix('matches')->group(function () { Route::apiResource('/', MatchController::class)->parameters(['' => 'match']); - Route::post('/{match}/join', [MatchController::class, 'join']); + Route::post('/{match}/join', [MatchController::class, 'join']); }); // Admin Routes diff --git a/frontend/src/components/game/GameBoard.vue b/frontend/src/components/game/GameBoard.vue index 2807944..caf35a6 100644 --- a/frontend/src/components/game/GameBoard.vue +++ b/frontend/src/components/game/GameBoard.vue @@ -7,6 +7,8 @@ :player-score="playerScore" :opponent-score="opponentScore" :current-turn="currentTurn" + :player-name="playerName" + :opponent-name="opponentName" :round-number="1" /> @@ -62,6 +64,8 @@ const props = defineProps({ // REMOVIDO: playableCardIndices (já não precisamos dele) playerScore: { type: Number, default: 0 }, opponentScore: { type: Number, default: 0 }, + playerName: { type: String, default: 'You' }, + opponentName: { type: String, default: 'Bot' }, currentTurn: { type: String, default: 'player', diff --git a/frontend/src/components/game/ScoreDisplay.vue b/frontend/src/components/game/ScoreDisplay.vue index ecc14b7..6571a10 100644 --- a/frontend/src/components/game/ScoreDisplay.vue +++ b/frontend/src/components/game/ScoreDisplay.vue @@ -33,7 +33,8 @@ turnChanged && 'animate-pulse', ]" > - {{ currentTurn === 'player' ? 'Your Turn' : "Bot's Turn" }} + + {{ currentTurn === 'player' ? playerName + "'s Turn" : opponentName + "'s Turn" }} Round {{ roundNumber }} diff --git a/frontend/src/pages/game/MultiplayerGamePage.vue b/frontend/src/pages/game/MultiplayerGamePage.vue index 6cb66ed..fe0d7cf 100644 --- a/frontend/src/pages/game/MultiplayerGamePage.vue +++ b/frontend/src/pages/game/MultiplayerGamePage.vue @@ -1,7 +1,6 @@ diff --git a/frontend/src/pages/home/HomePage.vue b/frontend/src/pages/home/HomePage.vue index 6eda4c8..21cc138 100644 --- a/frontend/src/pages/home/HomePage.vue +++ b/frontend/src/pages/home/HomePage.vue @@ -56,14 +56,19 @@ const getPendingGames = async (mode = selectedMode.value) => { if (gLoading.value) return; gLoading.value = true; - apiStore.gameQueryParameters.page = gPage.value++; - apiStore.gameQueryParameters.filters.sort_direction = "asc" - apiStore.gameQueryParameters.filters.type = mode - apiStore.gameQueryParameters.filters.status = 'Pending' try { - const response = await apiStore.getGames(); + const response = await axios.get(`${API_BASE_URL}/games/open`, { + params: { + type: mode, + page: gPage.value + } + }); + const newGames = response.data.data; openGames.value = [...openGames.value, ...newGames]; + gPage.value++; + } catch (error) { + console.error('Failed to fetch games:', error); } finally { gLoading.value = false; } diff --git a/frontend/src/stores/socket.js b/frontend/src/stores/socket.js index e46923d..b77d0a7 100644 --- a/frontend/src/stores/socket.js +++ b/frontend/src/stores/socket.js @@ -10,6 +10,7 @@ export const useSocketStore = defineStore('websocket', () => { const connected = ref(false) const gameState = ref(null) const lastError = ref(null) + const currentGameId = ref(null) const WS_URL = 'http://localhost:3000' @@ -23,16 +24,18 @@ export const useSocketStore = defineStore('websocket', () => { } socket.value = io(WS_URL, { - auth: { - token: `Bearer ${token}` - }, + auth: { token: `Bearer ${token}` }, reconnection: true, reconnectionAttempts: 5, reconnectionDelay: 1000 }) - // Connection events socket.value.on('connect', () => { + if (currentGameId.value) { + console.log("Reconnected to socket. Rejoining game..."); + socket.emit("join-game", { gameId: currentGameId.value }); + } + connected.value = true console.log('[WebSocket] Connected:', socket.value.id) }) @@ -47,15 +50,12 @@ export const useSocketStore = defineStore('websocket', () => { lastError.value = error.message }) - // Heartbeat socket.value.on('heartbeat', () => { socket.value.emit('heartbeat_ack') }) - // Game events socket.value.on('game-state', (state) => { gameState.value = state - console.log('[Game] State updated:', state) }) socket.value.on('game-error', (data) => { @@ -76,48 +76,40 @@ export const useSocketStore = defineStore('websocket', () => { connected.value = false gameState.value = null lastError.value = null + currentGameId.value = null } } const joinGame = (gameId) => { - if (!socket.value?.connected) { - console.error('[Game] Socket not connected') - return - } + currentGameId.value = gameId + if (!socket.value?.connected) return console.log('[Game] Joining game:', gameId) socket.value.emit('join-game', { gameId }) } const playCard = (gameId, cardId) => { - if (!socket.value?.connected) { - console.error('[Game] Socket not connected') - return - } - console.log('[Game] Playing card:', cardId) + if (!socket.value?.connected) return socket.value.emit('play-card', { gameId, cardId }) } + // --- NEW: Surrender Action --- + const surrender = (gameId) => { + if (!socket.value?.connected) return + console.log('[Game] Surrendering:', gameId) + socket.value.emit('surrender', { gameId }) + } + const onTrickEnd = (callback) => { if (socket.value) { + socket.value.off('trick-end') socket.value.on('trick-end', callback) } } const onGameOver = (callback) => { - if (socket.value) { - socket.value.on('game-over', callback) - } - } - - const offTrickEnd = () => { - if (socket.value) { - socket.value.off('trick-end') - } - } - - const offGameOver = () => { if (socket.value) { socket.value.off('game-over') + socket.value.on('game-over', callback) } } @@ -126,13 +118,13 @@ export const useSocketStore = defineStore('websocket', () => { connected, gameState, lastError, + currentGameId, connect, disconnect, joinGame, playCard, + surrender, // Exported onTrickEnd, - onGameOver, - offTrickEnd, - offGameOver + onGameOver } }) diff --git a/websockets/events/game.js b/websockets/events/game.js index 28aaa44..0d21285 100644 --- a/websockets/events/game.js +++ b/websockets/events/game.js @@ -4,6 +4,71 @@ import { getUser } from "../state/connection.js"; const API_URL = "http://localhost:8000/api/v1"; +// --- HELPER: Card Strength for Auto-Play --- +const getStrength = (rank) => { + const strengthMap = { 1: 10, 7: 9, 13: 8, 11: 7, 12: 6, 6: 5, 5: 4, 4: 3, 3: 2, 2: 1 }; + return strengthMap[rank] || 0; +}; + +// --- HELPER: Draw Card Logic --- +const drawCard = (game, playerId) => { + const player = game.players[playerId]; + if (!player) return; + + if (game.deck && game.deck.length > 0) { + const card = game.deck.pop(); + player.hand.push(card); + } else if (game.trumpCard) { + player.hand.push(game.trumpCard); + game.trumpCard = null; + } +}; + +// --- HELPER: Sanitize Data --- +const sanitizeState = (state, game) => { + if (!state) return null; + const p1 = game.player1 || state.player1 || {}; + const p2 = game.player2 || state.player2 || {}; + + return { + id: state.id, + status: state.status || game.status, + player1: { id: p1.id, name: p1.name }, + player2: { id: p2.id, name: p2.name }, + players: state.players, + hand: state.hand, + points: state.points, + opponent: { + id: state.opponent?.id, + name: state.opponent?.name, + points: state.opponent?.points, + cardCount: state.opponent?.cardCount + }, + table: state.table, + trumpCard: state.trumpCard, + deckCount: game.deck ? game.deck.length : (state.deckCount || 0), + currentTurn: state.currentTurn, + turnStartedAt: state.turnStartedAt + }; +}; + +const broadcastState = (io, gameId, game) => { + const roomName = `game_${gameId}`; + const socketsInRoom = io.sockets.adapter.rooms.get(roomName); + + if (socketsInRoom) { + for (const socketId of socketsInRoom) { + const s = io.sockets.sockets.get(socketId); + const u = getUser(socketId); + if (u && game.players[u.id]) { + const rawState = game.getStateForPlayer(u.id); + const cleanState = sanitizeState(rawState, game); + s.emit("game-state", cleanState); + } + } + } +} + async function saveGameResult(gameId, result, token) { try { const payload = { @@ -13,90 +78,105 @@ async function saveGameResult(gameId, result, token) { player1_points: result.player1_points, player2_points: result.player2_points, }; - if (!result.isDraw && result.winnerId) { payload.winner_user_id = result.winnerId; payload.loser_user_id = result.loserId; } - await axios.put(`${API_URL}/games/${gameId}`, payload, { headers: { Authorization: token }, }); - console.log(`[DB] Game ${gameId} saved.`); } catch (error) { console.error(`[DB Error] Game ${gameId}:`, error.message); } } +// --- SHARED END GAME LOGIC --- +const performGameEnd = (io, game, gameId, winnerId, loserId, reason) => { + const result = { + action: "game_ended", + winnerId: parseInt(winnerId), + loserId: parseInt(loserId), + isDraw: false, + player1_points: game.players[Object.keys(game.players)[0]]?.points || 0, + player2_points: game.players[Object.keys(game.players)[1]]?.points || 0, + reason: reason + }; + + game.status = "ended"; + if (game.timer) clearInterval(game.timer); + + io.to(`game_${gameId}`).emit("game-over", { + winnerId: result.winnerId, + isDraw: result.isDraw, + p1Points: result.player1_points, + p2Points: result.player2_points, + message: reason === "surrender" ? "Opponent Surrendered!" : "Game Over" + }); + + const anyId = Object.keys(game.players)[0]; + const token = game.players[anyId]?.token; + if (token) saveGameResult(gameId, result, token); +} + +const handleTimeout = (io, gameId, userId) => { + const game = getGame(gameId); + if (!game || game.status === 'ended') return; + + console.log(`[Timeout] User ${userId} auto-playing lowest card.`); + + const player = game.players[userId]; + if (!player || !player.hand || player.hand.length === 0) return; + + const trumpSuit = game.trumpCard?.suit || ''; + + const sortedHand = [...player.hand].sort((a, b) => { + const strengthA = getStrength(a.rank) + (a.suit === trumpSuit ? 100 : 0); + const strengthB = getStrength(b.rank) + (b.suit === trumpSuit ? 100 : 0); + return strengthA - strengthB; + }); + + const cardToPlay = sortedHand[0]; + if (cardToPlay) { + handleGameMove(io, gameId, userId, cardToPlay.id); + } +}; + const handleGameMove = (io, gameId, userId, cardId) => { const game = getGame(gameId); if (!game) return; const result = game.playCard(userId, cardId); - - if (result.error) { - console.log(`[Game Error] ${result.error}`); - return; - } - const roomName = `game_${gameId}`; - const socketsInRoom = io.sockets.adapter.rooms.get(roomName); - - if (socketsInRoom) { - for (const socketId of socketsInRoom) { - const s = io.sockets.sockets.get(socketId); - const u = getUser(socketId); - if (u && game.players[u.id]) { - s.emit("game-state", game.getStateForPlayer(u.id)); - } - } - } + + broadcastState(io, gameId, game); if (result.action === "trick_resolved") { io.to(roomName).emit("trick-end", result.trickResult); + + setTimeout(() => { + if (game.status !== "ended") { + const canDraw = (game.deck && game.deck.length > 0) || game.trumpCard !== null; + + if (canDraw) { + const winnerId = result.trickResult.winnerId; + const loserId = Object.keys(game.players).find(id => String(id) !== String(winnerId)); + + if (winnerId) drawCard(game, winnerId); + if (loserId) drawCard(game, loserId); + } + broadcastState(io, gameId, game); + } + }, 1500); } if (result.action === "game_ended") { - io.to(roomName).emit("game-over", { - winnerId: result.winnerId, - isDraw: result.isDraw, - p1Points: result.player1_points, - p2Points: result.player2_points, - }); - - let tokenToUse = null; - const playerIds = Object.keys(game.players); - - for (const pid of playerIds) { - if (game.players[pid] && game.players[pid].token) { - tokenToUse = game.players[pid].token; - break; - } - } - - if (tokenToUse) { - saveGameResult(gameId, result, tokenToUse); - console.log(`[DB] Jogo salvo usando o token de um dos jogadores.`); - } else { - console.error( - `[DB Error] CRÍTICO: Nenhum jogador tem token. O jogo ${gameId} não foi salvo.` - ); - } + performGameEnd(io, game, gameId, result.winnerId, result.loserId, "points"); } if (result.action === "next_turn" || result.action === "trick_resolved") { - game.startTurnTimer((timeoutUserId, timeoutCardId) => { - handleGameMove(io, gameId, timeoutUserId, timeoutCardId); + game.startTurnTimer((timeoutUserId) => { + handleTimeout(io, gameId, timeoutUserId); }); - - if (socketsInRoom) { - for (const socketId of socketsInRoom) { - const s = io.sockets.sockets.get(socketId); - const u = getUser(socketId); - if (u && game.players[u.id]) - s.emit("game-state", game.getStateForPlayer(u.id)); - } - } } }; @@ -109,181 +189,92 @@ export default (io, socket) => { } let game = getGame(gameId); + let gameData = null; - if (!game) { - try { + try { const token = socket.handshake.auth.token; const response = await axios.get(`${API_URL}/games/${gameId}`, { headers: { Authorization: token }, }); + gameData = response.data.data || response.data; + } catch (e) { console.error("DB Sync Failed"); } - const gameData = response.data.data || response.data; - - console.log( - `[Join Debug] API Data recebida para Jogo ${gameId}:`, - gameData ? "OK" : "NULL" - ); - - if ( - gameData.player2_user_id == 1 && - user.id != gameData.player1_user_id - ) { - try { - console.log( - `[API Sync] A oficializar User ${user.id} como Player 2 na BD...` - ); - await axios.post( - `${API_URL}/games/${gameId}/join`, - {}, - { - headers: { Authorization: token }, - } - ); - console.log(`[API Sync] Sucesso! O jogo passou a 'Playing' na BD.`); - - gameData.player2_user_id = user.id; - gameData.player2 = { name: user.name }; - gameData.status = "Playing"; - } catch (joinError) { - console.error( - `[API Sync Error] Falha ao fazer join na BD:`, - joinError.message - ); - } - } - - if (gameData.status === "Ended") { - socket.emit("error", { message: "Game already finished." }); - return; - } - - if ( - gameData.player1_user_id != user.id && - gameData.player2_user_id != user.id && - gameData.player2_user_id !== 1 - ) { - socket.emit("error", { message: "You are not in this game." }); - return; - } - - const p1Name = gameData.player1?.name || "Player 1"; - const p2Name = gameData.player2?.name || "Player 2"; + if (!game && gameData) { + const p1Name = gameData.player1?.nickname || "Player 1"; + const p2Name = gameData.player2?.nickname || "Player 2"; const type = gameData.type == "9" ? 9 : 3; - game = createGame( gameId, type, { id: gameData.player1_user_id, name: p1Name }, { id: gameData.player2_user_id, name: p2Name } ); - console.log( - `[Join Debug] Jogo criado?`, - game ? "SIM" : "NÃO (Undefined)" - ); - } catch (error) { - if (error.response) { - console.error(`[Join Error] Status: ${error.response.status}`); - console.error(`[Join Error] Data:`, error.response.data); - } else { - console.error(`[Join Error] Message:`, error.message); - } - - socket.emit("error", { message: "Failed to join game." }); - return; - } + game.status = gameData.status === 'Playing' ? 'playing' : 'pending'; } - const GHOST_ID = 1; + if (!game) { + socket.emit("error", { message: "Game not found." }); + return; + } - if (game && game.players) { - if (game.players[user.id]) { - game.players[user.id].token = socket.handshake.auth.token; - } + const myId = user.id; + const ghostKey = Object.keys(game.players).find(key => key == 1); + const amIDbPlayer2 = gameData && gameData.player2_user_id == myId; - if (!game.players[user.id] && game.players[GHOST_ID]) { - console.log(`[Ghost Swap] User ${user.name} substituiu o Fantasma.`); + if (!game.players[myId] && (ghostKey || amIDbPlayer2)) { + let ghostHand = []; + let ghostPoints = 0; + let ghostTricks = 0; + if (ghostKey && game.players[ghostKey]) { + ghostHand = game.players[ghostKey].hand || []; + ghostPoints = game.players[ghostKey].points || 0; + ghostTricks = game.players[ghostKey].tricks || 0; + delete game.players[ghostKey]; + } - delete game.players[GHOST_ID]; - game.players[user.id] = { - id: user.id, - name: user.name, - hand: [], - points: 0, - tricks: 0, - token: socket.handshake.auth.token, + game.players[myId] = { + id: myId, + name: user.nickname, + hand: ghostHand, + points: ghostPoints, + tricks: ghostTricks, + token: socket.handshake.auth.token, }; - - const token = socket.handshake.auth.token; - - axios - .post( - `${API_URL}/games/${gameId}/join`, - {}, - { - headers: { Authorization: token }, - } - ) - .then(() => - console.log(`[API Sync] Sucesso! BD atualizada para 'Playing'.`) - ) - .catch((err) => console.error(`[API Sync Error]`, err.message)); - } + game.player2 = { id: myId, name: user.nickname }; + game.status = 'playing'; + if(!game.timer) { + game.startTurnTimer((timeoutUserId) => handleTimeout(io, gameId, timeoutUserId)); + } } socket.join(`game_${gameId}`); - - if (game && game.players[user.id]) { - socket.emit("game-state", game.getStateForPlayer(user.id)); - console.log(`--> Estado enviado para User ${user.id}`); - game.players[user.id].token = socket.handshake.auth.token; - if (!game.timer && game.status === "playing") { - game.startTurnTimer((uId, cId) => handleGameMove(io, gameId, uId, cId)); - } - socket.emit("game-state", game.getStateForPlayer(user.id)); - } else { - socket.emit("error", { message: "Error joining game state." }); + + if (game.players[myId]) { + game.players[myId].token = socket.handshake.auth.token; + + const rawState = game.getStateForPlayer(myId); + const cleanState = sanitizeState(rawState, game); + + socket.emit("game-state", cleanState); + broadcastState(io, gameId, game); } }); socket.on("play-card", ({ gameId, cardId }) => { const user = getUser(socket.id); - const game = getGame(gameId); + if (user) handleGameMove(io, gameId, user.id, cardId); + }); - if (!game || !user) return; + // --- NEW: SURRENDER HANDLER --- + socket.on("surrender", ({ gameId }) => { + const user = getUser(socket.id); + const game = getGame(gameId); + + if (!game || !user || !game.players[user.id]) return; - const result = game.playCard(user.id, cardId); - - if (result.error) { - socket.emit("game-error", { message: result.error }); - return; - } - - handleGameMove(io, gameId, user.id, cardId); - - const roomName = `game_${gameId}`; - const socketsInRoom = io.sockets.adapter.rooms.get(roomName); - if (socketsInRoom) { - for (const socketId of socketsInRoom) { - const s = io.sockets.sockets.get(socketId); - const u = getUser(socketId); - if (u && game.players[u.id]) { - s.emit("game-state", game.getStateForPlayer(u.id)); - } - } - } - - if (result.action === "trick_resolved") { - io.to(roomName).emit("trick-end", result.trickResult); - } - - if (result.action === "game_ended") { - io.to(roomName).emit("game-over", { - winnerId: result.winnerId, - isDraw: result.isDraw, - p1Points: result.player1_points, - p2Points: result.player2_points, - }); - saveGameResult(gameId, result, socket.handshake.auth.token); - } + console.log(`[Game] User ${user.nickname} surrendered.`); + + const winnerId = Object.keys(game.players).find(id => String(id) !== String(user.id)); + performGameEnd(io, game, gameId, winnerId, user.id, "surrender"); }); }; diff --git a/websockets/state/game.js b/websockets/state/game.js index 2a3f7d8..3be9fae 100644 --- a/websockets/state/game.js +++ b/websockets/state/game.js @@ -3,31 +3,38 @@ const BiscaGame = require("../classes/BiscaGame"); const activeGames = new Map(); const createGame = (id, type, player1, player2) => { - const game = new BiscaGame(id, type, player1, player2); + const existingGame = activeGames.get(id); + if (existingGame) { + console.log( + `[Game State] Game ${id} already exists, returning existing instance`, + ); + return existingGame; + } + const game = new BiscaGame(id, type, player1, player2); - game.init(); + game.init(); - activeGames.set(id, game); + activeGames.set(id, game); - console.log(`[Game State] Game created: ${id} (Type: ${type})`); - return game; + console.log(`[Game State] Game created: ${id} (Type: ${type})`); + return game; }; const getGame = (id) => { - return activeGames.get(id); + return activeGames.get(id); }; const removeGame = (id) => { -const game = activeGames.get(id); - if (game) { - game.stopTimer(); - activeGames.delete(id); - console.log(`[Game State] Game removed: ${id}`); - } + const game = activeGames.get(id); + if (game) { + game.stopTimer(); + activeGames.delete(id); + console.log(`[Game State] Game removed: ${id}`); + } }; module.exports = { - createGame, - getGame, - removeGame, + createGame, + getGame, + removeGame, };