59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
import { GameInstance } from '../game/game-instance';
|
|
|
|
export type GameStateType = Pick<
|
|
GameInstance,
|
|
'id' | 'board' | 'currentPlayer' | 'status' | 'winner' | 'players'
|
|
>;
|
|
|
|
export function renderGameBoardHtml(
|
|
gameState: GameStateType,
|
|
playerId: string,
|
|
): string {
|
|
let boardHtml = '<div id="game-board" class="game-board-grid">';
|
|
|
|
const currentPlayerColor =
|
|
Object.entries(gameState.players).find(([_, id]) => id === playerId)?.[0] ||
|
|
null;
|
|
const isPlayersTurn =
|
|
gameState.status === 'playing' &&
|
|
gameState.currentPlayer === 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];
|
|
const intersectionId = `intersection-${row}-${col}`;
|
|
let stoneHtml = '';
|
|
if (stone) {
|
|
const colorClass =
|
|
stone === 'black' ? 'stone-black-heart' : 'stone-white-heart';
|
|
stoneHtml = `<div class="${colorClass}"></div>`;
|
|
}
|
|
|
|
// Calculate top and left for absolute positioning, offset by half the intersection div size
|
|
const top = row * 30;
|
|
const left = col * 30;
|
|
|
|
// HTMX attributes for making a move
|
|
const wsAttrs = isPlayersTurn && !stone ? `ws-send="click"` : '';
|
|
|
|
boardHtml += `
|
|
<div
|
|
id="${intersectionId}"
|
|
class="intersection"
|
|
data-row="${row}"
|
|
data-col="${col}"
|
|
style="top: ${top}px; left: ${left}px;"
|
|
${wsAttrs}
|
|
>
|
|
${stoneHtml}
|
|
</div>`;
|
|
}
|
|
}
|
|
boardHtml += `</div>`;
|
|
return boardHtml;
|
|
}
|
|
|
|
export function renderTitleBoxHtml(gameId: string, playerId: string): string {
|
|
return `<div id="title-box">You are: ${playerId}<br/>Game ID: ${gameId}</div>`;
|
|
}
|