gomoku/src/client-entry.ts

160 lines
5.0 KiB
TypeScript

// 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}<br/>Game ID: ${msg.state.id}<br/>Share this link: <a href="${gameLink}">${gameLink}</a>`;
}
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...)`;
}