class RoomTicTacToeGame { constructor() { this.currentRoomId = null; this.roomData = null; this.cells = document.querySelectorAll('.cell'); this.gameStatus = document.getElementById('gameStatus'); this.roomInfo = document.getElementById('roomInfo'); this.chatMessages = document.getElementById('chatMessages'); this.chatInput = document.getElementById('chatInput'); this.sendBtn = document.getElementById('sendBtn'); this.gameArea = document.getElementById('gameArea'); this.noRoom = document.getElementById('noRoom'); this.initGame(); } initGame() { this.cells.forEach((cell, index) => { cell.addEventListener('click', () => this.handleCellClick(index)); }); // Update room state every 2 seconds if in a room setInterval(() => { if (this.currentRoomId) { this.refreshRoomState(); } }, 2000); } async createNewRoom() { try { const response = await fetch('/rooms', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); this.joinRoomById(data.room_id); } catch (error) { console.error('Failed to create room:', error); this.gameStatus.textContent = "Failed to create room. Try again."; } } async joinRoom() { const roomId = document.getElementById('roomIdInput').value.trim(); if (!roomId) { this.gameStatus.textContent = "Please enter a room ID"; return; } await this.joinRoomById(roomId); } async joinRoomById(roomId) { try { const response = await fetch(`/rooms/${roomId}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); this.currentRoomId = roomId; this.roomData = data.room_data; // Clear the input document.getElementById('roomIdInput').value = ''; // Show game area and enable chat this.gameArea.style.display = 'block'; this.noRoom.style.display = 'none'; this.chatInput.disabled = false; this.sendBtn.disabled = false; this.chatInput.placeholder = "Type a message..."; // Update display this.updateDisplay(); this.loadChatHistory(); this.gameStatus.textContent = `Joined room ${roomId}!`; } catch (error) { console.error('Failed to join room:', error); this.gameStatus.textContent = `Failed to join room ${roomId}. Check the room ID.`; } } leaveRoom() { this.currentRoomId = null; this.roomData = null; // Hide game area and disable chat this.gameArea.style.display = 'none'; this.noRoom.style.display = 'block'; this.chatInput.disabled = true; this.sendBtn.disabled = true; this.chatInput.placeholder = "Join a room first..."; // Clear display this.clearBoard(); this.gameStatus.textContent = "Create or join a room to start playing!"; this.updateRoomInfo(); // Clear chat this.chatMessages.innerHTML = `
`; } async refreshRoomState() { if (!this.currentRoomId) return; try { const response = await fetch(`/rooms/${this.currentRoomId}`); if (!response.ok) { if (response.status === 404) { this.gameStatus.textContent = "Room no longer exists!"; this.leaveRoom(); return; } throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); this.roomData = data.room_data; this.updateDisplay(); } catch (error) { console.error('Failed to refresh room:', error); } } async handleCellClick(index) { if (!this.currentRoomId || !this.roomData) { this.gameStatus.textContent = "Join a room first!"; return; } if (this.roomData.game_status !== 'active' || this.roomData.board[index] !== '' || this.roomData.current_player !== 'X') { return; } this.gameStatus.textContent = "Making your move..."; try { const response = await fetch(`/rooms/${this.currentRoomId}/move`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ position: index }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); this.roomData = data.room_data; this.updateDisplay(); this.loadChatHistory(); // Reload chat to get AI's move message if (this.roomData.game_status === 'active') { this.gameStatus.textContent = "Mistral is thinking..."; setTimeout(() => { if (this.roomData.current_player === 'X') { this.gameStatus.textContent = "Your turn! Click a square."; } }, 1000); } } catch (error) { console.error('Move failed:', error); this.gameStatus.textContent = "Move failed. Try again."; } } async sendChatMessage() { if (!this.currentRoomId) { return; } const message = this.chatInput.value.trim(); if (!message) return; this.chatInput.value = ''; try { const response = await fetch(`/rooms/${this.currentRoomId}/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: message }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); this.roomData = data.room_data; this.loadChatHistory(); } catch (error) { console.error('Chat failed:', error); this.addChatMessage("Failed to send message", 'system'); } } updateDisplay() { if (!this.roomData) return; // Update board this.roomData.board.forEach((cell, index) => { this.cells[index].textContent = cell; this.cells[index].className = 'cell'; if (cell) { this.cells[index].classList.add(cell.toLowerCase()); } }); // Update game status if (this.roomData.game_status === 'won') { const winner = this.roomData.winner === 'X' ? 'You' : 'Mistral AI'; this.gameStatus.textContent = `🎉 ${winner} won!`; } else if (this.roomData.game_status === 'draw') { this.gameStatus.textContent = "🤝 It's a draw!"; } else if (this.roomData.current_player === 'X') { this.gameStatus.textContent = "Your turn! Click a square."; } else { this.gameStatus.textContent = "Mistral's turn..."; } this.updateRoomInfo(); } updateRoomInfo() { if (!this.roomData || !this.currentRoomId) { this.roomInfo.innerHTML = `