Improve title box with turn indicator
This commit is contained in:
parent
7cbeef6482
commit
6bb62b9c87
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
@ -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 = '<div id="game-board" class="game-board-grid">';
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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 = `<img src="/icons/disconnected.svg" alt="Disconnected" class="icon" />`;
|
||||
const connections = this.connections.get(gameId);
|
||||
if (connections) {
|
||||
|
@ -254,7 +261,24 @@ export class WebSocketHandler {
|
|||
}
|
||||
});
|
||||
}
|
||||
return `<span>${playerId}${connectionIcon}</span>`;
|
||||
|
||||
// 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 `<span class="${classes}">${playerId}${connectionIcon}</span>`;
|
||||
}
|
||||
|
||||
public getGame(gameId: string): GameInstance | undefined {
|
||||
|
|
Loading…
Reference in New Issue