Add dist/ to .gitignore, and prevent new games from having a broken gameId
This commit is contained in:
parent
e8e982c3d6
commit
e984172918
|
@ -39,4 +39,6 @@ yarn-error.log*
|
||||||
**/*.tgz
|
**/*.tgz
|
||||||
**/*.log
|
**/*.log
|
||||||
package-lock.json
|
package-lock.json
|
||||||
**/*.bun
|
**/*.bun
|
||||||
|
|
||||||
|
dist/
|
||||||
|
|
|
@ -1,307 +0,0 @@
|
||||||
// src/game-client/WebSocketClient.ts
|
|
||||||
class WebSocketClient {
|
|
||||||
ws = null;
|
|
||||||
url;
|
|
||||||
messageQueue = [];
|
|
||||||
isConnected = false;
|
|
||||||
reconnectCount = 0;
|
|
||||||
options;
|
|
||||||
manualClose = false;
|
|
||||||
onMessageHandler = () => {};
|
|
||||||
onOpenHandler = () => {};
|
|
||||||
onCloseHandler = () => {};
|
|
||||||
onErrorHandler = () => {};
|
|
||||||
constructor(url, options) {
|
|
||||||
this.url = url;
|
|
||||||
this.options = {
|
|
||||||
reconnectAttempts: 5,
|
|
||||||
reconnectInterval: 3000,
|
|
||||||
...options,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
connect() {
|
|
||||||
this.manualClose = false;
|
|
||||||
this.ws = new WebSocket(this.url);
|
|
||||||
this.ws.onopen = this.handleOpen.bind(this);
|
|
||||||
this.ws.onmessage = this.handleMessage.bind(this);
|
|
||||||
this.ws.onclose = this.handleClose.bind(this);
|
|
||||||
this.ws.onerror = this.handleError.bind(this);
|
|
||||||
}
|
|
||||||
send(message) {
|
|
||||||
if (this.isConnected && this.ws) {
|
|
||||||
this.ws.send(message);
|
|
||||||
} else {
|
|
||||||
this.messageQueue.push(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close() {
|
|
||||||
this.manualClose = true;
|
|
||||||
if (this.ws) {
|
|
||||||
this.ws.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onMessage(handler) {
|
|
||||||
this.onMessageHandler = handler;
|
|
||||||
}
|
|
||||||
onOpen(handler) {
|
|
||||||
this.onOpenHandler = handler;
|
|
||||||
}
|
|
||||||
onClose(handler) {
|
|
||||||
this.onCloseHandler = handler;
|
|
||||||
}
|
|
||||||
onError(handler) {
|
|
||||||
this.onErrorHandler = handler;
|
|
||||||
}
|
|
||||||
handleOpen() {
|
|
||||||
this.isConnected = true;
|
|
||||||
this.reconnectCount = 0;
|
|
||||||
this.onOpenHandler();
|
|
||||||
this.flushMessageQueue();
|
|
||||||
}
|
|
||||||
handleMessage(event) {
|
|
||||||
this.onMessageHandler(event.data);
|
|
||||||
}
|
|
||||||
handleClose(event) {
|
|
||||||
this.isConnected = false;
|
|
||||||
this.onCloseHandler(event.code, event.reason);
|
|
||||||
if (
|
|
||||||
!this.manualClose &&
|
|
||||||
this.reconnectCount < this.options.reconnectAttempts
|
|
||||||
) {
|
|
||||||
this.reconnectCount++;
|
|
||||||
setTimeout(() => this.connect(), this.options.reconnectInterval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handleError(event) {
|
|
||||||
this.onErrorHandler(event);
|
|
||||||
}
|
|
||||||
flushMessageQueue() {
|
|
||||||
while (this.messageQueue.length > 0 && this.isConnected && this.ws) {
|
|
||||||
const message = this.messageQueue.shift();
|
|
||||||
if (message) {
|
|
||||||
this.ws.send(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/game-client/GameStateManager.ts
|
|
||||||
class GameStateManager {
|
|
||||||
gameState;
|
|
||||||
stateHistory;
|
|
||||||
constructor() {
|
|
||||||
this.gameState = this.getDefaultGameState();
|
|
||||||
this.stateHistory = [];
|
|
||||||
}
|
|
||||||
getDefaultGameState() {
|
|
||||||
const emptyBoard = Array(15)
|
|
||||||
.fill(null)
|
|
||||||
.map(() => Array(15).fill(null));
|
|
||||||
return {
|
|
||||||
id: '',
|
|
||||||
board: emptyBoard,
|
|
||||||
currentPlayer: 'black',
|
|
||||||
status: 'waiting',
|
|
||||||
winner: null,
|
|
||||||
players: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
getGameState() {
|
|
||||||
return this.gameState;
|
|
||||||
}
|
|
||||||
updateGameState(newState) {
|
|
||||||
this.stateHistory.push(JSON.parse(JSON.stringify(this.gameState)));
|
|
||||||
this.gameState = newState;
|
|
||||||
}
|
|
||||||
rollbackGameState() {
|
|
||||||
if (this.stateHistory.length > 0) {
|
|
||||||
this.gameState = this.stateHistory.pop();
|
|
||||||
} else {
|
|
||||||
console.warn('No previous state to rollback to.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/game-client/GameBoardUI.ts
|
|
||||||
class GameBoardUI {
|
|
||||||
boardElement;
|
|
||||||
cells = [];
|
|
||||||
onCellClickCallback = null;
|
|
||||||
isInteractionEnabled = true;
|
|
||||||
constructor(boardElement) {
|
|
||||||
this.boardElement = boardElement;
|
|
||||||
this.initializeBoard();
|
|
||||||
}
|
|
||||||
initializeBoard() {
|
|
||||||
this.boardElement.innerHTML = '';
|
|
||||||
this.boardElement.style.display = 'grid';
|
|
||||||
this.boardElement.style.gridTemplateColumns = 'repeat(15, 1fr)';
|
|
||||||
this.boardElement.style.width = '450px';
|
|
||||||
this.boardElement.style.height = '450px';
|
|
||||||
this.boardElement.style.border = '1px solid black';
|
|
||||||
for (let row = 0; row < 15; row++) {
|
|
||||||
this.cells[row] = [];
|
|
||||||
for (let col = 0; col < 15; col++) {
|
|
||||||
const cell = document.createElement('div');
|
|
||||||
cell.classList.add('board-cell');
|
|
||||||
cell.style.width = '30px';
|
|
||||||
cell.style.height = '30px';
|
|
||||||
cell.style.border = '1px solid #ccc';
|
|
||||||
cell.style.boxSizing = 'border-box';
|
|
||||||
cell.style.display = 'flex';
|
|
||||||
cell.style.justifyContent = 'center';
|
|
||||||
cell.style.alignItems = 'center';
|
|
||||||
cell.dataset.row = row.toString();
|
|
||||||
cell.dataset.col = col.toString();
|
|
||||||
cell.addEventListener('click', () => this.handleCellClick(row, col));
|
|
||||||
this.boardElement.appendChild(cell);
|
|
||||||
this.cells[row][col] = cell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateBoard(gameState) {
|
|
||||||
const board = gameState.board;
|
|
||||||
const lastMove = { row: -1, col: -1 };
|
|
||||||
for (let row = 0; row < 15; row++) {
|
|
||||||
for (let col = 0; col < 15; col++) {
|
|
||||||
const cell = this.cells[row][col];
|
|
||||||
cell.innerHTML = '';
|
|
||||||
const stone = board[row][col];
|
|
||||||
if (stone) {
|
|
||||||
const stoneElement = document.createElement('div');
|
|
||||||
stoneElement.style.width = '24px';
|
|
||||||
stoneElement.style.height = '24px';
|
|
||||||
stoneElement.style.borderRadius = '50%';
|
|
||||||
stoneElement.style.backgroundColor =
|
|
||||||
stone === 'black' ? 'black' : 'white';
|
|
||||||
stoneElement.style.border = '1px solid #333';
|
|
||||||
cell.appendChild(stoneElement);
|
|
||||||
}
|
|
||||||
cell.classList.remove('last-move');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.isInteractionEnabled =
|
|
||||||
gameState.status === 'playing' && gameState.currentPlayer === 'black';
|
|
||||||
this.boardElement.style.pointerEvents = this.isInteractionEnabled
|
|
||||||
? 'auto'
|
|
||||||
: 'none';
|
|
||||||
this.boardElement.style.opacity = this.isInteractionEnabled ? '1' : '0.7';
|
|
||||||
console.log(
|
|
||||||
`Current Player: ${gameState.currentPlayer}, Status: ${gameState.status}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
setOnCellClick(callback) {
|
|
||||||
this.onCellClickCallback = callback;
|
|
||||||
}
|
|
||||||
handleCellClick(row, col) {
|
|
||||||
if (this.isInteractionEnabled && this.onCellClickCallback) {
|
|
||||||
this.onCellClickCallback(row, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/client-entry.ts
|
|
||||||
console.log('Gomoku client entry point loaded.');
|
|
||||||
var WS_URL = 'ws://localhost:3000/ws';
|
|
||||||
var gameStateManager = new GameStateManager();
|
|
||||||
var wsClient = new WebSocketClient(WS_URL);
|
|
||||||
var gameBoardElement = document.getElementById('game-board');
|
|
||||||
console.log('gameBoardElement: ', gameBoardElement);
|
|
||||||
var messagesElement = document.getElementById('messages');
|
|
||||||
var 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)',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
var gameBoardUI = new GameBoardUI(gameBoardElement);
|
|
||||||
console.log('GameBoardUI initialized.', 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);
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
console.log('Game state updated: ', gameStateManager.getGameState());
|
|
||||||
break;
|
|
||||||
case 'move_result':
|
|
||||||
if (msg.success) {
|
|
||||||
console.log('Move successful!');
|
|
||||||
} else {
|
|
||||||
console.error(`Move failed: ${msg.error}`);
|
|
||||||
gameStateManager.rollbackGameState();
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
}
|
|
||||||
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.setOnCellClick((row, col) => {
|
|
||||||
const moveMessage = {
|
|
||||||
type: 'make_move',
|
|
||||||
row,
|
|
||||||
col,
|
|
||||||
};
|
|
||||||
console.log('Sending move:', moveMessage);
|
|
||||||
wsClient.send(JSON.stringify(moveMessage));
|
|
||||||
const currentGameState = gameStateManager.getGameState();
|
|
||||||
const nextPlayer =
|
|
||||||
currentGameState.currentPlayer === 'black' ? 'white' : 'black';
|
|
||||||
const newBoard = currentGameState.board.map((rowArr) => [...rowArr]);
|
|
||||||
newBoard[row][col] = currentGameState.currentPlayer;
|
|
||||||
const optimisticState = {
|
|
||||||
...currentGameState,
|
|
||||||
board: newBoard,
|
|
||||||
currentPlayer: nextPlayer,
|
|
||||||
};
|
|
||||||
gameStateManager.updateGameState(optimisticState);
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
});
|
|
||||||
wsClient.onOpen(() => {
|
|
||||||
console.log('Connected to game server.');
|
|
||||||
const playerId = `player-${Math.random().toString(36).substring(2, 9)}`;
|
|
||||||
const joinMessage = {
|
|
||||||
type: 'join_game',
|
|
||||||
gameId: 'some-game-id',
|
|
||||||
playerId,
|
|
||||||
};
|
|
||||||
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) => {
|
|
||||||
console.error(
|
|
||||||
`WebSocket error: ${error instanceof ErrorEvent ? error.message : String(error)}`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
wsClient.connect();
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
if (playerInfoElement) {
|
|
||||||
playerInfoElement.textContent = `You are: (Connecting...)`;
|
|
||||||
}
|
|
|
@ -1,305 +0,0 @@
|
||||||
// src/game-client/WebSocketClient.ts
|
|
||||||
class WebSocketClient {
|
|
||||||
ws = null;
|
|
||||||
url;
|
|
||||||
messageQueue = [];
|
|
||||||
isConnected = false;
|
|
||||||
reconnectCount = 0;
|
|
||||||
options;
|
|
||||||
manualClose = false;
|
|
||||||
onMessageHandler = () => {};
|
|
||||||
onOpenHandler = () => {};
|
|
||||||
onCloseHandler = () => {};
|
|
||||||
onErrorHandler = () => {};
|
|
||||||
constructor(url, options) {
|
|
||||||
this.url = url;
|
|
||||||
this.options = {
|
|
||||||
reconnectAttempts: 5,
|
|
||||||
reconnectInterval: 3000,
|
|
||||||
...options,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
connect() {
|
|
||||||
this.manualClose = false;
|
|
||||||
this.ws = new WebSocket(this.url);
|
|
||||||
this.ws.onopen = this.handleOpen.bind(this);
|
|
||||||
this.ws.onmessage = this.handleMessage.bind(this);
|
|
||||||
this.ws.onclose = this.handleClose.bind(this);
|
|
||||||
this.ws.onerror = this.handleError.bind(this);
|
|
||||||
}
|
|
||||||
send(message) {
|
|
||||||
if (this.isConnected && this.ws) {
|
|
||||||
this.ws.send(message);
|
|
||||||
} else {
|
|
||||||
this.messageQueue.push(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close() {
|
|
||||||
this.manualClose = true;
|
|
||||||
if (this.ws) {
|
|
||||||
this.ws.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onMessage(handler) {
|
|
||||||
this.onMessageHandler = handler;
|
|
||||||
}
|
|
||||||
onOpen(handler) {
|
|
||||||
this.onOpenHandler = handler;
|
|
||||||
}
|
|
||||||
onClose(handler) {
|
|
||||||
this.onCloseHandler = handler;
|
|
||||||
}
|
|
||||||
onError(handler) {
|
|
||||||
this.onErrorHandler = handler;
|
|
||||||
}
|
|
||||||
handleOpen() {
|
|
||||||
this.isConnected = true;
|
|
||||||
this.reconnectCount = 0;
|
|
||||||
this.onOpenHandler();
|
|
||||||
this.flushMessageQueue();
|
|
||||||
}
|
|
||||||
handleMessage(event) {
|
|
||||||
this.onMessageHandler(event.data);
|
|
||||||
}
|
|
||||||
handleClose(event) {
|
|
||||||
this.isConnected = false;
|
|
||||||
this.onCloseHandler(event.code, event.reason);
|
|
||||||
if (
|
|
||||||
!this.manualClose &&
|
|
||||||
this.reconnectCount < this.options.reconnectAttempts
|
|
||||||
) {
|
|
||||||
this.reconnectCount++;
|
|
||||||
setTimeout(() => this.connect(), this.options.reconnectInterval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handleError(event) {
|
|
||||||
this.onErrorHandler(event);
|
|
||||||
}
|
|
||||||
flushMessageQueue() {
|
|
||||||
while (this.messageQueue.length > 0 && this.isConnected && this.ws) {
|
|
||||||
const message = this.messageQueue.shift();
|
|
||||||
if (message) {
|
|
||||||
this.ws.send(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/game-client/GameStateManager.ts
|
|
||||||
class GameStateManager {
|
|
||||||
gameState;
|
|
||||||
stateHistory;
|
|
||||||
constructor() {
|
|
||||||
this.gameState = this.getDefaultGameState();
|
|
||||||
this.stateHistory = [];
|
|
||||||
}
|
|
||||||
getDefaultGameState() {
|
|
||||||
const emptyBoard = Array(15)
|
|
||||||
.fill(null)
|
|
||||||
.map(() => Array(15).fill(null));
|
|
||||||
return {
|
|
||||||
id: '',
|
|
||||||
board: emptyBoard,
|
|
||||||
currentPlayer: 'black',
|
|
||||||
status: 'waiting',
|
|
||||||
winner: null,
|
|
||||||
players: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
getGameState() {
|
|
||||||
return this.gameState;
|
|
||||||
}
|
|
||||||
updateGameState(newState) {
|
|
||||||
this.stateHistory.push(JSON.parse(JSON.stringify(this.gameState)));
|
|
||||||
this.gameState = newState;
|
|
||||||
}
|
|
||||||
rollbackGameState() {
|
|
||||||
if (this.stateHistory.length > 0) {
|
|
||||||
this.gameState = this.stateHistory.pop();
|
|
||||||
} else {
|
|
||||||
console.warn('No previous state to rollback to.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/game-client/GameBoardUI.ts
|
|
||||||
class GameBoardUI {
|
|
||||||
boardElement;
|
|
||||||
cells = [];
|
|
||||||
onCellClickCallback = null;
|
|
||||||
isInteractionEnabled = true;
|
|
||||||
constructor(boardElement) {
|
|
||||||
this.boardElement = boardElement;
|
|
||||||
this.initializeBoard();
|
|
||||||
}
|
|
||||||
initializeBoard() {
|
|
||||||
this.boardElement.innerHTML = '';
|
|
||||||
this.boardElement.style.display = 'grid';
|
|
||||||
this.boardElement.style.gridTemplateColumns = 'repeat(15, 1fr)';
|
|
||||||
this.boardElement.style.width = '450px';
|
|
||||||
this.boardElement.style.height = '450px';
|
|
||||||
this.boardElement.style.border = '1px solid black';
|
|
||||||
for (let row = 0; row < 15; row++) {
|
|
||||||
this.cells[row] = [];
|
|
||||||
for (let col = 0; col < 15; col++) {
|
|
||||||
const cell = document.createElement('div');
|
|
||||||
cell.classList.add('board-cell');
|
|
||||||
cell.style.width = '30px';
|
|
||||||
cell.style.height = '30px';
|
|
||||||
cell.style.border = '1px solid #ccc';
|
|
||||||
cell.style.boxSizing = 'border-box';
|
|
||||||
cell.style.display = 'flex';
|
|
||||||
cell.style.justifyContent = 'center';
|
|
||||||
cell.style.alignItems = 'center';
|
|
||||||
cell.dataset.row = row.toString();
|
|
||||||
cell.dataset.col = col.toString();
|
|
||||||
cell.addEventListener('click', () => this.handleCellClick(row, col));
|
|
||||||
this.boardElement.appendChild(cell);
|
|
||||||
this.cells[row][col] = cell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateBoard(gameState) {
|
|
||||||
const board = gameState.board;
|
|
||||||
const lastMove = { row: -1, col: -1 };
|
|
||||||
for (let row = 0; row < 15; row++) {
|
|
||||||
for (let col = 0; col < 15; col++) {
|
|
||||||
const cell = this.cells[row][col];
|
|
||||||
cell.innerHTML = '';
|
|
||||||
const stone = board[row][col];
|
|
||||||
if (stone) {
|
|
||||||
const stoneElement = document.createElement('div');
|
|
||||||
stoneElement.style.width = '24px';
|
|
||||||
stoneElement.style.height = '24px';
|
|
||||||
stoneElement.style.borderRadius = '50%';
|
|
||||||
stoneElement.style.backgroundColor =
|
|
||||||
stone === 'black' ? 'black' : 'white';
|
|
||||||
stoneElement.style.border = '1px solid #333';
|
|
||||||
cell.appendChild(stoneElement);
|
|
||||||
}
|
|
||||||
cell.classList.remove('last-move');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.isInteractionEnabled =
|
|
||||||
gameState.status === 'playing' && gameState.currentPlayer === 'black';
|
|
||||||
this.boardElement.style.pointerEvents = this.isInteractionEnabled
|
|
||||||
? 'auto'
|
|
||||||
: 'none';
|
|
||||||
this.boardElement.style.opacity = this.isInteractionEnabled ? '1' : '0.7';
|
|
||||||
console.log(
|
|
||||||
`Current Player: ${gameState.currentPlayer}, Status: ${gameState.status}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
setOnCellClick(callback) {
|
|
||||||
this.onCellClickCallback = callback;
|
|
||||||
}
|
|
||||||
handleCellClick(row, col) {
|
|
||||||
if (this.isInteractionEnabled && this.onCellClickCallback) {
|
|
||||||
this.onCellClickCallback(row, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/client-entry.ts
|
|
||||||
console.log('Gomoku client entry point loaded.');
|
|
||||||
var WS_URL = process.env.WS_URL || 'ws://localhost:3000/ws';
|
|
||||||
var gameStateManager = new GameStateManager();
|
|
||||||
var wsClient = new WebSocketClient(WS_URL);
|
|
||||||
var gameBoardElement = document.getElementById('game-board');
|
|
||||||
console.log('gameBoardElement: ', gameBoardElement);
|
|
||||||
var messagesElement = document.getElementById('messages');
|
|
||||||
var 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)',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
var gameBoardUI = new GameBoardUI(gameBoardElement);
|
|
||||||
console.log('GameBoardUI initialized.', 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);
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
console.log('Game state updated: ', gameStateManager.getGameState());
|
|
||||||
break;
|
|
||||||
case 'move_result':
|
|
||||||
if (msg.success) {
|
|
||||||
console.log('Move successful!');
|
|
||||||
} else {
|
|
||||||
console.error(`Move failed: ${msg.error}`);
|
|
||||||
gameStateManager.rollbackGameState();
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
}
|
|
||||||
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.setOnCellClick((row, col) => {
|
|
||||||
const moveMessage = {
|
|
||||||
type: 'make_move',
|
|
||||||
row,
|
|
||||||
col,
|
|
||||||
};
|
|
||||||
console.log('Sending move:', moveMessage);
|
|
||||||
wsClient.send(JSON.stringify(moveMessage));
|
|
||||||
const currentGameState = gameStateManager.getGameState();
|
|
||||||
const nextPlayer =
|
|
||||||
currentGameState.currentPlayer === 'black' ? 'white' : 'black';
|
|
||||||
const newBoard = currentGameState.board.map((rowArr) => [...rowArr]);
|
|
||||||
newBoard[row][col] = currentGameState.currentPlayer;
|
|
||||||
const optimisticState = {
|
|
||||||
...currentGameState,
|
|
||||||
board: newBoard,
|
|
||||||
currentPlayer: nextPlayer,
|
|
||||||
};
|
|
||||||
gameStateManager.updateGameState(optimisticState);
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
});
|
|
||||||
wsClient.onOpen(() => {
|
|
||||||
console.log('Connected to game server.');
|
|
||||||
const playerId = `player-${Math.random().toString(36).substring(2, 9)}`;
|
|
||||||
const joinMessage = {
|
|
||||||
type: 'join_game',
|
|
||||||
gameId: 'some-game-id',
|
|
||||||
playerId,
|
|
||||||
};
|
|
||||||
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) => {
|
|
||||||
console.error(`WebSocket error: ${error.message}`);
|
|
||||||
});
|
|
||||||
wsClient.connect();
|
|
||||||
gameBoardUI.updateBoard(gameStateManager.getGameState());
|
|
||||||
if (playerInfoElement) {
|
|
||||||
playerInfoElement.textContent = `You are: (Connecting...)`;
|
|
||||||
}
|
|
|
@ -109,7 +109,6 @@ wsClient.onOpen(() => {
|
||||||
const playerId = `player-${Math.random().toString(36).substring(2, 9)}`;
|
const playerId = `player-${Math.random().toString(36).substring(2, 9)}`;
|
||||||
const joinMessage = {
|
const joinMessage = {
|
||||||
type: 'join_game',
|
type: 'join_game',
|
||||||
gameId: 'some-game-id',
|
|
||||||
playerId: playerId,
|
playerId: playerId,
|
||||||
};
|
};
|
||||||
wsClient.send(JSON.stringify(joinMessage));
|
wsClient.send(JSON.stringify(joinMessage));
|
||||||
|
|
Loading…
Reference in New Issue