// Code snippets for typing test grouped by language const codeSnippets = { html: [ ` Document

Hello World

`, `
`, `
` ], javascript: [ `function calculateTotal(items) { return items.reduce((total, item) => { return total + (item.price * item.quantity); }, 0); } const cart = [ { name: 'Shirt', price: 25, quantity: 2 }, { name: 'Pants', price: 40, quantity: 1 } ]; const total = calculateTotal(cart); console.log('Total:', total);`, `class Person { constructor(name, age) { this.name = name; this.age = age; } greet() { console.log(\`Hello, my name is \${this.name}\`); } } const person1 = new Person('Alice', 30); person1.greet();`, `const fetchData = async () => { try { const response = await fetch('api/data'); const data = await response.json(); return data; } catch (error) { console.error('Error:', error); return null; } };` ], css: [ `.container { max-width: 1200px; margin: 0 auto; padding: 0 20px; } .header { background: #333; color: white; padding: 1rem; } .nav-list { display: flex; gap: 1rem; list-style: none; }`, `body { font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; } h1, h2, h3 { color: #222; margin-bottom: 1rem; } a { color: #0066cc; text-decoration: none; }`, `@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; animation: fadeIn 0.3s ease; }` ] }; // Get all snippets as one array for "all languages" option function getAllSnippets() { return Object.values(codeSnippets).flat(); } // DOM elements const codeDisplay = document.getElementById('code-display'); const inputField = document.getElementById('input-field'); const timerElement = document.getElementById('timer'); const speedElement = document.getElementById('speed'); const resultsSection = document.getElementById('results'); const finalWPM = document.getElementById('final-wpm'); const finalAccuracy = document.getElementById('final-accuracy'); const finalTime = document.getElementById('final-time'); const tryAgainBtn = document.getElementById('try-again-btn'); // Game variables let timeLeft = parseInt(document.getElementById('time-select').value); let timer; let isPlaying = false; let startTime; let endTime; let correctChars = 0; let totalChars = 0; // Initialize the game function initGame() { // Get selected time const timeSelect = document.getElementById('time-select'); const selectedTime = parseInt(timeSelect.value); timeLeft = selectedTime; timerElement.textContent = `${timeLeft}s`; // Get selected language const languageSelect = document.getElementById('language-select'); const selectedLanguage = languageSelect.value; // Get appropriate snippets array const snippets = selectedLanguage === 'all' ? getAllSnippets() : codeSnippets[selectedLanguage] || getAllSnippets(); // Select a random code snippet from the filtered list const randomSnippet = snippets[Math.floor(Math.random() * snippets.length)]; totalChars = randomSnippet.length; // Display the code with spans for each character codeDisplay.innerHTML = ''; randomSnippet.split('').forEach(char => { const span = document.createElement('span'); span.textContent = char; codeDisplay.appendChild(span); }); // Highlight the first character codeDisplay.children[0].classList.add('current'); // Reset game state inputField.value = ''; inputField.disabled = false; inputField.focus(); timeLeft = parseInt(document.getElementById('time-select').value); timerElement.textContent = `${timeLeft}s`; correctChars = 0; isPlaying = false; resultsSection.classList.add('hidden'); } // Start the game function startGame() { if (isPlaying) return; isPlaying = true; startTime = new Date(); let lastUpdate = Date.now(); timer = setInterval(() => { const now = Date.now(); const elapsed = now - lastUpdate; if (elapsed >= 1000) { timeLeft--; timerElement.textContent = `${timeLeft}s`; lastUpdate = now; if (timeLeft <= 0) { endGame(); } } }, 100); } // Update the display as user types function updateDisplay() { const inputText = inputField.value; const codeSpans = codeDisplay.children; // Reset all spans for (let i = 0; i < codeSpans.length; i++) { codeSpans[i].className = ''; } // Mark correct/incorrect characters let allCorrect = true; for (let i = 0; i < inputText.length; i++) { if (i < codeSpans.length) { if (inputText[i] === codeSpans[i].textContent) { codeSpans[i].classList.add('correct'); if (i === inputText.length - 1) { codeSpans[i].classList.add('current'); } } else { codeSpans[i].classList.add('incorrect'); allCorrect = false; } } } // Highlight next character if all correct so far if (allCorrect && inputText.length < codeSpans.length) { codeSpans[inputText.length].classList.add('current'); } // Calculate and display typing speed if (isPlaying) { const elapsedTime = (new Date() - startTime) / 60000; // in minutes const wordsTyped = inputText.length / 5; // standard word length const wpm = Math.round(wordsTyped / elapsedTime) || 0; speedElement.textContent = `${wpm} WPM`; } // Count correct characters for accuracy correctChars = 0; for (let i = 0; i < inputText.length && i < codeSpans.length; i++) { if (inputText[i] === codeSpans[i].textContent) { correctChars++; } } // End game if all characters are typed correctly if (inputText.length === codeSpans.length && allCorrect) { endGame(true); } } // End the game function endGame(isCompleted = false) { clearInterval(timer); isPlaying = false; inputField.disabled = true; endTime = new Date(); // Calculate results const timeTaken = Math.max(1, parseInt(document.getElementById('time-select').value) - timeLeft); // at least 1 second to avoid division by zero const wordsTyped = correctChars / 5; const wpm = Math.round((wordsTyped / timeTaken) * 60); const accuracy = Math.round((correctChars / totalChars) * 100); // Only show results if code was completed or time ran out if (isCompleted || timeLeft <= 0) { const totalTime = parseInt(document.getElementById('time-select').value); // Display results finalWPM.textContent = wpm; finalAccuracy.textContent = `${accuracy}%`; finalTime.textContent = `${totalTime - timeLeft}s`; resultsSection.classList.remove('hidden'); // Save results to database const language = document.getElementById('language-select').value; saveResults(language, wpm, accuracy, timeTaken); } } // Mock save results function for local testing async function saveResults(language, wpm, accuracy, timeTaken) { const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}'); const result = { language, wpm, accuracy, time_taken: timeTaken, name: userInfo.name || 'Anonymous', grade: userInfo.grade || 'N/A', section: userInfo.section || 'N/A', created_at: new Date().toISOString() }; console.log('Results would be saved:', result); // In a real app, you would send this to your backend // await fetch('/api/results', { // method: 'POST', // headers: { 'Content-Type': 'application/json' }, // body: JSON.stringify(result) // }); return { success: true, data: result }; } // Mock leaderboard data for local testing async function fetchLeaderboard() { // Try to get from localStorage if no backend const savedResults = JSON.parse(localStorage.getItem('savedResults') || '[]'); // Add some sample data if empty if (savedResults.length === 0) { return [ { name: 'John Doe', grade: '10', section: 'A', language: 'javascript', wpm: 85, accuracy: 98, time_taken: 120, created_at: new Date().toISOString() }, { name: 'Jane Smith', grade: '11', section: 'B', language: 'html', wpm: 75, accuracy: 95, time_taken: 180, created_at: new Date().toISOString() }, { name: 'Alex Johnson', grade: '9', section: 'C', language: 'css', wpm: 65, accuracy: 92, time_taken: 150, created_at: new Date().toISOString() } ]; } return savedResults; } // Event listeners inputField.addEventListener('input', updateDisplay); inputField.addEventListener('focus', startGame); tryAgainBtn.addEventListener('click', initGame); // Reset game when time selection changes document.getElementById('time-select').addEventListener('change', initGame); // Initialize the game on page load and when language changes document.addEventListener('DOMContentLoaded', () => { initGame(); document.getElementById('language-select').addEventListener('change', initGame); });