From d1dbebcc39ca58167fd4c7dd379c0373e95adadf Mon Sep 17 00:00:00 2001 From: sepia Date: Tue, 15 Jul 2025 21:23:16 -0500 Subject: [PATCH] Make game fully playable with two players --- src/client-entry.ts | 74 +++++++++++++++++++--------------- src/game-client/GameBoardUI.ts | 10 +++-- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/client-entry.ts b/src/client-entry.ts index da4607b..f4a13fb 100644 --- a/src/client-entry.ts +++ b/src/client-entry.ts @@ -26,6 +26,8 @@ let playerId: string; // Declare playerId here, accessible throughout the module const gameStateManager = new GameStateManager(); const wsClient = new WebSocketClient(WS_URL); +let gameBoardUI: GameBoardUI; + const gameBoardElement = document.getElementById('game-board'); console.log('gameBoardElement: ', gameBoardElement); // Log to check if element is found @@ -40,13 +42,6 @@ if (!gameBoardElement || !messagesElement || !playerInfoElement) { '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); @@ -95,35 +90,22 @@ wsClient.onMessage((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)); +// This will be set up inside wsClient.onOpen - // 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 +// Initial board render (empty board until server sends state) +// This initial render is no longer needed as updateBoard is called within onOpen and onMessage - const optimisticState: GameStateType = { - ...currentGameState, - board: newBoard, - currentPlayer: nextPlayer, // Optimistically switch turn - }; - gameStateManager.updateGameState(optimisticState); - gameBoardUI.updateBoard(gameStateManager.getGameState()); -}); - -// WebSocketClient connection status messages +// Initial setup for player info +if (playerInfoElement) { + playerInfoElement.textContent = `You are: (Connecting...)`; +} wsClient.onOpen(() => { console.log('Connected to game server.'); playerId = `player-${Math.random().toString(36).substring(2, 9)}`; + + gameBoardUI = new GameBoardUI(gameBoardElement, playerId); + console.log('GameBoardUI initialized.', gameBoardUI); // Log to confirm GameBoardUI construction + const joinMessage: any = { type: 'join_game', playerId: playerId, @@ -136,6 +118,34 @@ wsClient.onOpen(() => { if (playerInfoElement) { playerInfoElement.textContent = `You are: ${playerId} (Waiting for game state...)`; } + + // Initial board render (empty board until server sends state) + gameBoardUI.updateBoard(gameStateManager.getGameState()); + + 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()); + }); }); wsClient.onClose(() => { @@ -151,8 +161,6 @@ wsClient.onError((error: Event) => { // --- 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...)`; diff --git a/src/game-client/GameBoardUI.ts b/src/game-client/GameBoardUI.ts index 965ee79..ec5d627 100644 --- a/src/game-client/GameBoardUI.ts +++ b/src/game-client/GameBoardUI.ts @@ -8,9 +8,11 @@ export class GameBoardUI { private onCellClickCallback: ((row: number, col: number) => void) | null = null; private isInteractionEnabled: boolean = true; + private thisClientPlayerId: string; - constructor(boardElement: HTMLElement) { + constructor(boardElement: HTMLElement, thisClientPlayerId: string) { this.boardElement = boardElement; + this.thisClientPlayerId = thisClientPlayerId; this.initializeBoard(); } @@ -47,6 +49,8 @@ export class GameBoardUI { const board = gameState.board; const lastMove = { row: -1, col: -1 }; // Placeholder for last move highlighting (needs actual last move from state) + const thisClientColor = Object.entries(gameState.players).find(([color, id]) => id === this.thisClientPlayerId)?.[0] || null; + for (let row = 0; row < 15; row++) { for (let col = 0; col < 15; col++) { const cell = this.cells[row][col]; @@ -76,10 +80,8 @@ export class GameBoardUI { // Disable interaction if it's not our turn or game is over // This logic needs to know which player 'we' are, and the current player from gameState - // For simplicity, let's assume 'black' is the client for now, and enable/disable - // based on if it's black's turn. This will need refinement for multi-player. this.isInteractionEnabled = - gameState.status === 'playing' && gameState.currentPlayer === 'black'; // Simplified for now + gameState.status === 'playing' && gameState.currentPlayer === (thisClientColor as 'black' | 'white'); this.boardElement.style.pointerEvents = this.isInteractionEnabled ? 'auto' : 'none';