// src/client-entry.ts import { WebSocketClient } from './game-client/WebSocketClient'; import { GameStateManager, GameStateType, } from './game-client/GameStateManager'; import { GameBoardUI } from './game-client/GameBoardUI'; console.log('Gomoku client entry point loaded.'); const WS_URL = process.env.WS_URL || 'ws://localhost:3000/ws'; // Function to get a query parameter from the URL function getQueryParam(name: string): string | null { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(name); } // Get gameId from URL, if present const gameIdFromUrl = getQueryParam('gameId'); let playerId: string; // Declare playerId here, accessible throughout the module // Initialize components const gameStateManager = new GameStateManager(); const wsClient = new WebSocketClient(WS_URL); const gameBoardElement = document.getElementById('game-board'); console.log('gameBoardElement: ', gameBoardElement); // Log to check if element is found const messagesElement = document.getElementById('messages'); const playerInfoElement = document.getElementById('player-info'); if (!gameBoardElement || !messagesElement || !playerInfoElement) { console.error( 'Missing essential DOM elements (game-board, messages, or player-info)', ); throw new Error( 'Missing essential DOM elements (game-board, messages, or player-info)', ); } const gameBoardUI = new GameBoardUI(gameBoardElement); console.log('GameBoardUI initialized.', gameBoardUI); // Log to confirm GameBoardUI construction // --- Event Handlers and Wiring --- // WebSocketClient -> GameStateManager -> GameBoardUI wsClient.onMessage((message) => { try { const msg = JSON.parse(message); console.log('Parsed message:', msg); switch (msg.type) { case 'game_state': gameStateManager.updateGameState(msg.state as GameStateType); gameBoardUI.updateBoard(gameStateManager.getGameState()); console.log('Game state updated: ', gameStateManager.getGameState()); // Update player info with game ID and shareable link if (playerInfoElement && msg.state.id) { const gameLink = `${window.location.origin}/?gameId=${msg.state.id}`; playerInfoElement.innerHTML = `You are: ${playerId}
Game ID: ${msg.state.id}
Share this link: ${gameLink}`; } break; case 'move_result': if (msg.success) { console.log('Move successful!'); } else { console.error(`Move failed: ${msg.error}`); gameStateManager.rollbackGameState(); gameBoardUI.updateBoard(gameStateManager.getGameState()); // Re-render after rollback } break; case 'player_joined': console.log(`${msg.playerId} joined the game.`); break; case 'player_disconnected': console.log(`${msg.playerId} disconnected.`); break; case 'ping': break; default: console.log(`Unknown message type: ${msg.type}`); } } catch (e) { console.error( 'Error parsing WebSocket message:', e, 'Message was:', message, ); } }); // GameBoardUI -> WebSocketClient (for making moves) gameBoardUI.setOnCellClick((row, col) => { const moveMessage = { type: 'make_move', row: row, col: col, }; console.log('Sending move:', moveMessage); wsClient.send(JSON.stringify(moveMessage)); // Optimistic Update: Apply the move to local state immediately const currentGameState = gameStateManager.getGameState(); const nextPlayer = currentGameState.currentPlayer === 'black' ? 'white' : 'black'; const newBoard = currentGameState.board.map((rowArr) => [...rowArr]); // Deep copy board newBoard[row][col] = currentGameState.currentPlayer; // Place stone optimistically const optimisticState: GameStateType = { ...currentGameState, board: newBoard, currentPlayer: nextPlayer, // Optimistically switch turn }; gameStateManager.updateGameState(optimisticState); gameBoardUI.updateBoard(gameStateManager.getGameState()); }); // WebSocketClient connection status messages wsClient.onOpen(() => { console.log('Connected to game server.'); playerId = `player-${Math.random().toString(36).substring(2, 9)}`; const joinMessage: any = { type: 'join_game', playerId: playerId, }; if (gameIdFromUrl) { joinMessage.gameId = gameIdFromUrl; } wsClient.send(JSON.stringify(joinMessage)); if (playerInfoElement) { playerInfoElement.textContent = `You are: ${playerId} (Waiting for game state...)`; } }); wsClient.onClose(() => { console.log('Disconnected from game server. Attempting to reconnect...'); }); wsClient.onError((error: Event) => { console.error( `WebSocket error: ${error instanceof ErrorEvent ? error.message : String(error)}`, ); }); // --- Start Connection --- wsClient.connect(); // Initial board render (empty board until server sends state) gameBoardUI.updateBoard(gameStateManager.getGameState()); // Initial setup for player info if (playerInfoElement) { playerInfoElement.textContent = `You are: (Connecting...)`; }