document.addEventListener('DOMContentLoaded', function() { // Элементы DOM const roomForm = document.getElementById('roomForm'); const usernameInput = document.getElementById('username'); const roomInput = document.getElementById('room'); const joinBtn = document.getElementById('joinBtn'); const readyBtn = document.getElementById('readyBtn'); const gameContainer = document.getElementById('gameContainer'); const textDisplay = document.getElementById('textDisplay'); const inputArea = document.getElementById('inputArea'); const playersList = document.getElementById('playersList'); const countdown = document.getElementById('countdown'); // Переменные для игры let socket; let username = ''; let room = ''; let text = ''; let startTime = null; let currentPosition = 0; let mistakes = 0; let totalChars = 0; let gameActive = false; let playerReady = false; // Инициализация Socket.IO function initSocket() { socket = io(); // Обработчики событий Socket.IO socket.on('connect', () => { console.log('Connected to server'); }); socket.on('room_update', (data) => { updatePlayersList(data.players); // Если игра началась, но текст еще не отображен if (data.started && !gameActive) { startGame(data.text); } }); socket.on('countdown_start', () => { // Начинаем обратный отсчет startCountdown(); }); socket.on('game_started', (data) => { startGame(data.text); }); socket.on('progress_update', (players) => { updatePlayersProgress(players); // Проверяем, закончили ли все игроки let allFinished = true; for (const id in players) { if (!players[id].finished) { allFinished = false; break; } } // Если все закончили, показываем результаты if (allFinished) { showResults(players); } }); socket.on('disconnect', () => { console.log('Disconnected from server'); }); } // Присоединение к комнате function joinRoom() { username = usernameInput.value.trim(); room = roomInput.value.trim(); if (!username || !room) { alert('Пожалуйста, введите имя пользователя и название комнаты'); return; } socket.emit('join', { username: username, room: room }); // Скрываем форму и показываем игровой контейнер roomForm.style.display = 'none'; gameContainer.style.display = 'block'; } // Обновление списка игроков function updatePlayersList(players) { playersList.innerHTML = ''; for (const id in players) { const player = players[id]; const playerItem = document.createElement('div'); playerItem.className = 'player-item'; playerItem.id = 'player-' + id; const playerName = document.createElement('div'); playerName.className = 'player-name'; playerName.textContent = player.username; // Добавляем индикатор готовности if (player.ready) { playerName.textContent += ' ✓'; playerName.classList.add('player-ready'); } const playerProgress = document.createElement('div'); playerProgress.className = 'player-progress'; const progressBar = document.createElement('div'); progressBar.className = 'progress-bar'; progressBar.style.width = player.progress + '%'; const playerStats = document.createElement('div'); playerStats.className = 'player-stats'; playerStats.innerHTML = ` WPM: ${player.wpm || 0} Точность: ${player.accuracy || 0}% `; playerProgress.appendChild(progressBar); playerItem.appendChild(playerName); playerItem.appendChild(playerProgress); playerItem.appendChild(playerStats); playersList.appendChild(playerItem); } } // Обновление прогресса игроков function updatePlayersProgress(players) { for (const id in players) { const player = players[id]; const playerItem = document.getElementById('player-' + id); if (playerItem) { const progressBar = playerItem.querySelector('.progress-bar'); progressBar.style.width = player.progress + '%'; const playerStats = playerItem.querySelector('.player-stats'); playerStats.innerHTML = ` WPM: ${player.wpm || 0} Точность: ${player.accuracy || 0}% `; } } } // Обратный отсчет перед началом игры function startCountdown() { readyBtn.disabled = true; countdown.style.display = 'block'; let count = 3; countdown.textContent = count; const countdownInterval = setInterval(() => { count--; countdown.textContent = count; if (count <= 0) { clearInterval(countdownInterval); countdown.style.display = 'none'; socket.emit('start_game', { room: room }); } }, 1000); } // Начало игры function startGame(textContent) { text = textContent; displayText(); inputArea.value = ''; inputArea.disabled = false; inputArea.focus(); mistakes = 0; totalChars = 0; currentPosition = 0; startTime = new Date(); gameActive = true; } // Отображение текста function displayText() { textDisplay.innerHTML = ''; for (let i = 0; i < text.length; i++) { const span = document.createElement('span'); span.textContent = text[i]; textDisplay.appendChild(span); } // Выделяем первый символ как текущий if (textDisplay.firstChild) { textDisplay.firstChild.classList.add('current'); } } // Показ результатов function showResults(players) { let winner = null; let maxWpm = 0; for (const id in players) { const player = players[id]; if (player.wpm > maxWpm) { maxWpm = player.wpm; winner = player; } } if (winner) { alert(`Игра окончена! Победитель: ${winner.username} со скоростью ${winner.wpm} WPM и точностью ${winner.accuracy}%`); } } // Обработка ввода inputArea.addEventListener('input', function(e) { if (!gameActive) return; const inputValue = e.target.value; const currentChar = text[currentPosition]; // Проверяем, правильно ли введен символ if (inputValue.charAt(inputValue.length - 1) === currentChar) { // Правильный символ const spans = textDisplay.querySelectorAll('span'); spans[currentPosition].classList.remove('current'); spans[currentPosition].classList.add('correct'); currentPosition++; totalChars++; // Если есть следующий символ, делаем его текущим if (currentPosition < text.length) { spans[currentPosition].classList.add('current'); } else { // Текст закончился, завершаем игру gameActive = false; inputArea.disabled = true; } } else { // Неправильный символ mistakes++; totalChars++; } // Обновляем статистику и отправляем на сервер updateStats(); }); // Обновление статистики function updateStats() { if (!gameActive && currentPosition < text.length) return; const currentTime = new Date(); const timeElapsed = (currentTime - startTime) / 1000; // в секундах // Расчет WPM (слов в минуту) // Считаем, что среднее слово - 5 символов const wpm = Math.round((currentPosition / 5) / (timeElapsed / 60)); // Расчет точности const accuracy = totalChars > 0 ? Math.round(((totalChars - mistakes) / totalChars) * 100) : 100; // Расчет прогресса const progress = Math.round((currentPosition / text.length) * 100); // Отправляем данные на сервер socket.emit('update_progress', { room: room, progress: progress, wpm: wpm, accuracy: accuracy }); } // Обработчики кнопок joinBtn.addEventListener('click', function(e) { e.preventDefault(); joinRoom(); }); readyBtn.addEventListener('click', function() { if (!playerReady) { playerReady = true; readyBtn.textContent = 'Готов!'; readyBtn.classList.add('ready'); socket.emit('player_ready', { room: room }); } }); // Инициализация initSocket(); });