diff --git a/public/style.css b/public/style.css index 8a5703d..f17216a 100644 --- a/public/style.css +++ b/public/style.css @@ -97,6 +97,7 @@ body { } #title-box { + font-size: 1.25em; padding-top: 0.25em; padding-bottom: 0.25em; } @@ -184,6 +185,29 @@ body { background-color: var(--color-on-primary); } +.player-name { + font-weight: bold; +} + +.player-name.player-black { + color: var(--color-primary-light); +} + +.player-name.player-white { + color: var(--color-on-primary); + text-shadow: + -1px -1px 0 var(--color-neutral-900), + 1px -1px 0 var(--color-neutral-900), + -1px 1px 0 var(--color-neutral-900), + 1px 1px 0 var(--color-neutral-900); +} + +.player-name.player-to-play { + border: 2px solid var(--color-focus-ring); + border-radius: 10px; + padding: 2px; +} + .last-move { box-shadow: 0 0 5px 3px var(--color-warning-light); } diff --git a/src/game/game-instance.ts b/src/game/game-instance.ts index d57aa0b..9000c38 100644 --- a/src/game/game-instance.ts +++ b/src/game/game-instance.ts @@ -7,7 +7,7 @@ type BoardCell = null | 'black' | 'white'; export class GameInstance { public readonly id: string; public readonly board: BoardCell[][]; - public currentPlayer: PlayerColor | null; + public currentPlayerColor: PlayerColor | null; public status: GameStatus; public winner: null | PlayerColor | 'draw'; public players: { black?: string; white?: string }; @@ -20,12 +20,20 @@ export class GameInstance { this.board = Array.from({ length: this.boardSize }, () => Array(this.boardSize).fill(null), ); - this.currentPlayer = null; + this.currentPlayerColor = null; this.status = 'waiting'; this.winner = null; this.players = {}; } + public getCurrentPlayerId(): string | undefined { + if (this.currentPlayerColor === 'black') { + return this.players.black; + } else { + return this.players.white; + } + } + public getPlayerCount(): number { return Object.values(this.players).filter(Boolean).length; } @@ -52,7 +60,7 @@ export class GameInstance { // If both players have joined, start the game. if (this.players.black && this.players.white) { - this.currentPlayer = 'black'; + this.currentPlayerColor = 'black'; this.status = 'playing'; } return true; @@ -77,7 +85,7 @@ export class GameInstance { } // Validate it's the player's turn - if (this.currentPlayer !== playerColor) { + if (this.currentPlayerColor !== playerColor) { return { success: false, error: 'Not your turn' }; } @@ -99,7 +107,7 @@ export class GameInstance { if (this.checkWin(row, col, playerColor)) { this.winner = playerColor; this.status = 'finished'; - this.currentPlayer = null; + this.currentPlayerColor = null; return { success: true }; } @@ -107,12 +115,12 @@ export class GameInstance { if (this.moveCount === this.boardSize * this.boardSize) { this.winner = 'draw'; this.status = 'finished'; - this.currentPlayer = null; + this.currentPlayerColor = null; return { success: true }; } // Switch turns - this.currentPlayer = playerColor === 'black' ? 'white' : 'black'; + this.currentPlayerColor = playerColor === 'black' ? 'white' : 'black'; return { success: true }; } diff --git a/src/view/board-renderer.ts b/src/view/board-renderer.ts index 51e5090..bf3ee81 100644 --- a/src/view/board-renderer.ts +++ b/src/view/board-renderer.ts @@ -1,26 +1,20 @@ import { GameInstance } from '../game/game-instance'; -export type GameStateType = Pick< - GameInstance, - 'id' | 'board' | 'currentPlayer' | 'status' | 'winner' | 'players' ->; - export function renderGameBoardHtml( - gameState: GameStateType, + game: GameInstance, playerId: string, ): string { let boardHtml = '
'; const currentPlayerColor = - Object.entries(gameState.players).find(([_, id]) => id === playerId)?.[0] || + Object.entries(game.players).find(([_, id]) => id === playerId)?.[0] || null; const isPlayersTurn = - gameState.status === 'playing' && - gameState.currentPlayer === currentPlayerColor; + game.status === 'playing' && game.currentPlayerColor === currentPlayerColor; - for (let row = 0; row < gameState.board.length; row++) { - for (let col = 0; col < gameState.board[row].length; col++) { - const stone = gameState.board[row][col]; + for (let row = 0; row < game.board.length; row++) { + for (let col = 0; col < game.board[row].length; col++) { + const stone = game.board[row][col]; const intersectionId = `intersection-${row}-${col}`; let stoneHtml = ''; if (stone) { diff --git a/src/web-socket-handler.ts b/src/web-socket-handler.ts index 5330b34..22f00e3 100644 --- a/src/web-socket-handler.ts +++ b/src/web-socket-handler.ts @@ -74,7 +74,7 @@ export class WebSocketHandler { return; } - if (game.currentPlayer !== playerColor) { + if (game.currentPlayerColor !== playerColor) { this.sendMessage(ws, "Error: It's not your turn"); return; } @@ -142,22 +142,28 @@ export class WebSocketHandler { ws.send(updatedBoardHtml); if (game.status === 'finished') { - if (game.winner === 'draw') { + if (game.winnerColor === 'draw') { this.sendMessageToGame(gameId, 'Game ended in draw.'); - } else if (game.winner) { + } else if (game.winnerColor) { this.sendMessageToGame( gameId, - `${game.winner.toUpperCase()} wins!`, + `${game.winnerColor.toUpperCase()} wins!`, ); } } else if (game.status === 'playing') { const clientPlayerColor = Object.entries(game.players).find( ([_, id]) => id === playerId, )?.[0] as ('black' | 'white') | undefined; - if (game.currentPlayer && clientPlayerColor === game.currentPlayer) { + if ( + game.currentPlayerColor && + clientPlayerColor === game.currentPlayerColor + ) { this.sendMessage(ws, "It's your turn!"); - } else if (game.currentPlayer) { - this.sendMessage(ws, `Waiting for ${game.currentPlayer}'s move.`); + } else if (game.currentPlayerColor) { + this.sendMessage( + ws, + `Waiting for ${game.currentPlayerColor}'s move.`, + ); } } else if (game.status === 'waiting') { this.sendMessage(ws, 'Waiting for another player...'); @@ -220,7 +226,7 @@ export class WebSocketHandler { break; } case 'finished': { - switch (game.winner) { + switch (game.winnerColor) { case 'draw': { message = 'Game ended in draw.'; break; @@ -244,6 +250,7 @@ export class WebSocketHandler { } private playerTag(gameId: string, playerId: string) { + // Determine whether the player is disconnected var connectionIcon = `Disconnected`; const connections = this.connections.get(gameId); if (connections) { @@ -254,7 +261,24 @@ export class WebSocketHandler { } }); } - return `${playerId}${connectionIcon}`; + + // Set the correct name color for the player + var colorClass = ''; + var turnClass = ''; + const game = this.games.get(gameId); + if (game) { + if (game.players.white === playerId) { + colorClass = 'player-white'; + } else if (game.players.black === playerId) { + colorClass = 'player-black'; + } + if (game.getCurrentPlayerId() === playerId) { + turnClass = 'player-to-play'; + } + } + const classes = `player-name ${colorClass} ${turnClass}`.trim(); + + return `${playerId}${connectionIcon}`; } public getGame(gameId: string): GameInstance | undefined {