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();
});