| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Divvision - Division Practice App</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .progress-ring__circle { |
| transition: stroke-dashoffset 0.5s; |
| transform: rotate(-90deg); |
| transform-origin: 50% 50%; |
| } |
| |
| @keyframes confetti { |
| 0% { transform: translateY(0) rotate(0); opacity: 1; } |
| 100% { transform: translateY(100vh) rotate(360deg); opacity: 0; } |
| } |
| |
| .confetti { |
| position: absolute; |
| width: 10px; |
| height: 10px; |
| background-color: #f00; |
| animation: confetti 2s ease-out forwards; |
| } |
| </style> |
| </head> |
| <body class="bg-gradient-to-br from-blue-50 to-purple-50 min-h-screen font-sans"> |
| <div class="container mx-auto px-4 py-8 max-w-4xl"> |
| |
| <header class="text-center mb-12"> |
| <h1 class="text-4xl md:text-5xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-600 to-purple-600 mb-2"> |
| Divvision |
| </h1> |
| <p class="text-gray-600 text-lg">Master division with fun challenges!</p> |
| </header> |
|
|
| |
| <div class="bg-white rounded-xl shadow-lg overflow-hidden transition-all duration-300"> |
| |
| <div class="flex border-b"> |
| <button id="practice-tab" class="flex-1 py-4 px-6 font-medium text-center border-b-2 border-blue-500 text-blue-600 bg-blue-50"> |
| <i class="fas fa-calculator mr-2"></i> Practice |
| </button> |
| <button id="stats-tab" class="flex-1 py-4 px-6 font-medium text-center text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-chart-line mr-2"></i> Stats |
| </button> |
| <button id="settings-tab" class="flex-1 py-4 px-6 font-medium text-center text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-cog mr-2"></i> Settings |
| </button> |
| </div> |
|
|
| |
| <div id="practice-section" class="p-6 md:p-8"> |
| |
| <div class="mb-8"> |
| <h3 class="text-lg font-semibold text-gray-700 mb-3">Select Difficulty</h3> |
| <div class="flex flex-wrap gap-2"> |
| <button data-difficulty="easy" class="difficulty-btn px-4 py-2 rounded-full bg-green-100 text-green-800 font-medium hover:bg-green-200 transition"> |
| Easy (1-10) |
| </button> |
| <button data-difficulty="medium" class="difficulty-btn px-4 py-2 rounded-full bg-yellow-100 text-yellow-800 font-medium hover:bg-yellow-200 transition"> |
| Medium (1-20) |
| </button> |
| <button data-difficulty="hard" class="difficulty-btn px-4 py-2 rounded-full bg-red-100 text-red-800 font-medium hover:bg-red-200 transition active-difficulty"> |
| Hard (1-50) |
| </button> |
| <button data-difficulty="expert" class="difficulty-btn px-4 py-2 rounded-full bg-purple-100 text-purple-800 font-medium hover:bg-purple-200 transition"> |
| Expert (1-100) |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-gray-50 rounded-lg p-6 mb-8"> |
| <div class="flex justify-between items-center mb-4"> |
| <div class="flex items-center"> |
| <span class="text-gray-500 mr-2">Question:</span> |
| <span id="question-count" class="font-bold">1/10</span> |
| </div> |
| <div class="flex items-center"> |
| <span class="text-gray-500 mr-2">Score:</span> |
| <span id="score" class="font-bold">0</span> |
| </div> |
| </div> |
|
|
| |
| <div class="flex justify-center mb-6"> |
| <div class="relative w-24 h-24"> |
| <svg class="w-full h-full" viewBox="0 0 100 100"> |
| <circle class="text-gray-200" stroke-width="8" stroke="currentColor" fill="transparent" r="40" cx="50" cy="50" /> |
| <circle id="progress-ring" class="progress-ring__circle text-blue-500" stroke-width="8" stroke-linecap="round" stroke="currentColor" fill="transparent" r="40" cx="50" cy="50" stroke-dasharray="251.2" stroke-dashoffset="251.2" /> |
| </svg> |
| <div class="absolute inset-0 flex items-center justify-center"> |
| <span id="time-left" class="text-xl font-bold">30</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="text-center mb-8"> |
| <div class="text-4xl md:text-5xl font-bold mb-6"> |
| <span id="dividend">24</span> ÷ <span id="divisor">6</span> = ? |
| </div> |
| <div class="relative"> |
| <input type="number" id="answer-input" class="w-full md:w-64 px-4 py-3 text-center text-2xl border-2 border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Your answer"> |
| <button id="submit-answer" class="absolute right-2 top-1/2 transform -translate-y-1/2 bg-blue-500 text-white p-2 rounded-lg hover:bg-blue-600 transition"> |
| <i class="fas fa-arrow-right"></i> |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-3 gap-2 md:hidden"> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">1</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">2</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">3</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">4</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">5</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">6</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">7</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">8</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">9</button> |
| <button class="clear-btn bg-red-100 hover:bg-red-200 py-3 rounded-lg font-medium text-xl">C</button> |
| <button class="number-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl">0</button> |
| <button class="backspace-btn bg-gray-100 hover:bg-gray-200 py-3 rounded-lg font-medium text-xl"> |
| <i class="fas fa-backspace"></i> |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div id="feedback-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> |
| <div class="bg-white rounded-xl p-8 max-w-md w-full mx-4 text-center"> |
| <div id="feedback-icon" class="text-6xl mb-4"> |
| <i class="fas fa-check-circle text-green-500"></i> |
| </div> |
| <h3 id="feedback-title" class="text-2xl font-bold mb-2">Correct!</h3> |
| <p id="feedback-message" class="text-gray-600 mb-6">Great job! You earned 10 points.</p> |
| <button id="next-question" class="bg-blue-500 text-white px-6 py-2 rounded-lg hover:bg-blue-600 transition"> |
| Next Question <i class="fas fa-arrow-right ml-2"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="stats-section" class="p-6 md:p-8 hidden"> |
| <h2 class="text-2xl font-bold mb-6 text-gray-800">Your Statistics</h2> |
| |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"> |
| <div class="bg-blue-50 p-6 rounded-xl"> |
| <div class="flex items-center mb-2"> |
| <div class="bg-blue-100 p-3 rounded-full mr-4"> |
| <i class="fas fa-star text-blue-600"></i> |
| </div> |
| <div> |
| <p class="text-gray-500">Total Questions</p> |
| <p id="total-questions" class="text-2xl font-bold">0</p> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-green-50 p-6 rounded-xl"> |
| <div class="flex items-center mb-2"> |
| <div class="bg-green-100 p-3 rounded-full mr-4"> |
| <i class="fas fa-check-circle text-green-600"></i> |
| </div> |
| <div> |
| <p class="text-gray-500">Correct Answers</p> |
| <p id="correct-answers" class="text-2xl font-bold">0</p> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-purple-50 p-6 rounded-xl"> |
| <div class="flex items-center mb-2"> |
| <div class="bg-purple-100 p-3 rounded-full mr-4"> |
| <i class="fas fa-percentage text-purple-600"></i> |
| </div> |
| <div> |
| <p class="text-gray-500">Accuracy</p> |
| <p id="accuracy" class="text-2xl font-bold">0%</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-white border border-gray-200 rounded-xl p-6"> |
| <h3 class="text-lg font-semibold mb-4">Performance by Difficulty</h3> |
| <div class="space-y-4"> |
| <div> |
| <div class="flex justify-between mb-1"> |
| <span class="text-sm font-medium text-green-700">Easy</span> |
| <span id="easy-stats" class="text-sm font-medium">0/0 (0%)</span> |
| </div> |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> |
| <div id="easy-progress" class="bg-green-500 h-2.5 rounded-full" style="width: 0%"></div> |
| </div> |
| </div> |
| |
| <div> |
| <div class="flex justify-between mb-1"> |
| <span class="text-sm font-medium text-yellow-600">Medium</span> |
| <span id="medium-stats" class="text-sm font-medium">0/0 (0%)</span> |
| </div> |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> |
| <div id="medium-progress" class="bg-yellow-500 h-2.5 rounded-full" style="width: 0%"></div> |
| </div> |
| </div> |
| |
| <div> |
| <div class="flex justify-between mb-1"> |
| <span class="text-sm font-medium text-red-600">Hard</span> |
| <span id="hard-stats" class="text-sm font-medium">0/0 (0%)</span> |
| </div> |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> |
| <div id="hard-progress" class="bg-red-500 h-2.5 rounded-full" style="width: 0%"></div> |
| </div> |
| </div> |
| |
| <div> |
| <div class="flex justify-between mb-1"> |
| <span class="text-sm font-medium text-purple-600">Expert</span> |
| <span id="expert-stats" class="text-sm font-medium">0/0 (0%)</span> |
| </div> |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> |
| <div id="expert-progress" class="bg-purple-500 h-2.5 rounded-full" style="width: 0%"></div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="settings-section" class="p-6 md:p-8 hidden"> |
| <h2 class="text-2xl font-bold mb-6 text-gray-800">Settings</h2> |
| |
| <div class="space-y-6"> |
| <div class="bg-white border border-gray-200 rounded-xl p-6"> |
| <h3 class="text-lg font-semibold mb-4">Game Settings</h3> |
| |
| <div class="space-y-4"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="font-medium">Time per question</p> |
| <p class="text-sm text-gray-500">Adjust how many seconds you have to answer</p> |
| </div> |
| <select id="time-setting" class="bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2"> |
| <option value="15">15 seconds</option> |
| <option value="30" selected>30 seconds</option> |
| <option value="45">45 seconds</option> |
| <option value="60">60 seconds</option> |
| </select> |
| </div> |
| |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="font-medium">Questions per round</p> |
| <p class="text-sm text-gray-500">How many questions in a practice session</p> |
| </div> |
| <select id="questions-setting" class="bg-gray-50 border border-gray-300 text-gray-900 rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2"> |
| <option value="5">5 questions</option> |
| <option value="10" selected>10 questions</option> |
| <option value="15">15 questions</option> |
| <option value="20">20 questions</option> |
| </select> |
| </div> |
| |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="font-medium">Sound effects</p> |
| <p class="text-sm text-gray-500">Enable or disable sound feedback</p> |
| </div> |
| <label class="relative inline-flex items-center cursor-pointer"> |
| <input type="checkbox" id="sound-setting" class="sr-only peer" checked> |
| <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> |
| </label> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-white border border-gray-200 rounded-xl p-6"> |
| <h3 class="text-lg font-semibold mb-4">Appearance</h3> |
| |
| <div class="space-y-4"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="font-medium">Dark mode</p> |
| <p class="text-sm text-gray-500">Toggle between light and dark theme</p> |
| </div> |
| <label class="relative inline-flex items-center cursor-pointer"> |
| <input type="checkbox" id="dark-mode" class="sr-only peer"> |
| <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> |
| </label> |
| </div> |
| |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="font-medium">Animation effects</p> |
| <p class="text-sm text-gray-500">Enable or disable animations</p> |
| </div> |
| <label class="relative inline-flex items-center cursor-pointer"> |
| <input type="checkbox" id="animations-setting" class="sr-only peer" checked> |
| <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> |
| </label> |
| </div> |
| </div> |
| </div> |
| |
| <button id="reset-stats" class="w-full bg-red-100 text-red-600 py-3 rounded-lg font-medium hover:bg-red-200 transition"> |
| <i class="fas fa-trash-alt mr-2"></i> Reset All Statistics |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <footer class="mt-12 text-center text-gray-500 text-sm"> |
| <p>Divvision - A fun way to practice division © 2023</p> |
| </footer> |
| </div> |
|
|
| <script> |
| |
| const state = { |
| currentDifficulty: 'hard', |
| currentQuestion: 1, |
| totalQuestions: 10, |
| score: 0, |
| correctAnswers: 0, |
| timeLeft: 30, |
| timer: null, |
| stats: { |
| easy: { correct: 0, total: 0 }, |
| medium: { correct: 0, total: 0 }, |
| hard: { correct: 0, total: 0 }, |
| expert: { correct: 0, total: 0 } |
| }, |
| settings: { |
| timePerQuestion: 30, |
| questionsPerRound: 10, |
| soundEnabled: true, |
| darkMode: false, |
| animations: true |
| } |
| }; |
| |
| |
| const elements = { |
| practiceTab: document.getElementById('practice-tab'), |
| statsTab: document.getElementById('stats-tab'), |
| settingsTab: document.getElementById('settings-tab'), |
| practiceSection: document.getElementById('practice-section'), |
| statsSection: document.getElementById('stats-section'), |
| settingsSection: document.getElementById('settings-section'), |
| difficultyBtns: document.querySelectorAll('.difficulty-btn'), |
| questionCount: document.getElementById('question-count'), |
| score: document.getElementById('score'), |
| timeLeft: document.getElementById('time-left'), |
| dividend: document.getElementById('dividend'), |
| divisor: document.getElementById('divisor'), |
| answerInput: document.getElementById('answer-input'), |
| submitAnswer: document.getElementById('submit-answer'), |
| numberBtns: document.querySelectorAll('.number-btn'), |
| clearBtn: document.querySelector('.clear-btn'), |
| backspaceBtn: document.querySelector('.backspace-btn'), |
| feedbackModal: document.getElementById('feedback-modal'), |
| feedbackIcon: document.getElementById('feedback-icon'), |
| feedbackTitle: document.getElementById('feedback-title'), |
| feedbackMessage: document.getElementById('feedback-message'), |
| nextQuestion: document.getElementById('next-question'), |
| progressRing: document.getElementById('progress-ring'), |
| totalQuestionsStat: document.getElementById('total-questions'), |
| correctAnswersStat: document.getElementById('correct-answers'), |
| accuracyStat: document.getElementById('accuracy'), |
| easyStats: document.getElementById('easy-stats'), |
| mediumStats: document.getElementById('medium-stats'), |
| hardStats: document.getElementById('hard-stats'), |
| expertStats: document.getElementById('expert-stats'), |
| easyProgress: document.getElementById('easy-progress'), |
| mediumProgress: document.getElementById('medium-progress'), |
| hardProgress: document.getElementById('hard-progress'), |
| expertProgress: document.getElementById('expert-progress'), |
| timeSetting: document.getElementById('time-setting'), |
| questionsSetting: document.getElementById('questions-setting'), |
| soundSetting: document.getElementById('sound-setting'), |
| darkMode: document.getElementById('dark-mode'), |
| animationsSetting: document.getElementById('animations-setting'), |
| resetStats: document.getElementById('reset-stats') |
| }; |
| |
| |
| function init() { |
| |
| loadState(); |
| |
| |
| setupEventListeners(); |
| |
| |
| updateUI(); |
| |
| |
| generateQuestion(); |
| |
| |
| startTimer(); |
| } |
| |
| |
| function loadState() { |
| const savedStats = localStorage.getItem('divvision_stats'); |
| const savedSettings = localStorage.getItem('divvision_settings'); |
| |
| if (savedStats) { |
| state.stats = JSON.parse(savedStats); |
| } |
| |
| if (savedSettings) { |
| state.settings = JSON.parse(savedSettings); |
| |
| |
| elements.timeSetting.value = state.settings.timePerQuestion; |
| elements.questionsSetting.value = state.settings.questionsPerRound; |
| elements.soundSetting.checked = state.settings.soundEnabled; |
| elements.darkMode.checked = state.settings.darkMode; |
| elements.animationsSetting.checked = state.settings.animations; |
| |
| |
| if (state.settings.darkMode) { |
| document.documentElement.classList.add('dark'); |
| } |
| } |
| |
| |
| state.timeLeft = state.settings.timePerQuestion; |
| state.totalQuestions = state.settings.questionsPerRound; |
| } |
| |
| |
| function saveState() { |
| localStorage.setItem('divvision_stats', JSON.stringify(state.stats)); |
| localStorage.setItem('divvision_settings', JSON.stringify(state.settings)); |
| } |
| |
| |
| function setupEventListeners() { |
| |
| elements.practiceTab.addEventListener('click', () => switchTab('practice')); |
| elements.statsTab.addEventListener('click', () => switchTab('stats')); |
| elements.settingsTab.addEventListener('click', () => switchTab('settings')); |
| |
| |
| elements.difficultyBtns.forEach(btn => { |
| btn.addEventListener('click', () => { |
| const difficulty = btn.dataset.difficulty; |
| setDifficulty(difficulty); |
| }); |
| }); |
| |
| |
| elements.submitAnswer.addEventListener('click', checkAnswer); |
| elements.answerInput.addEventListener('keypress', (e) => { |
| if (e.key === 'Enter') { |
| checkAnswer(); |
| } |
| }); |
| |
| |
| elements.numberBtns.forEach(btn => { |
| btn.addEventListener('click', () => { |
| elements.answerInput.value += btn.textContent; |
| elements.answerInput.focus(); |
| }); |
| }); |
| |
| |
| elements.clearBtn.addEventListener('click', () => { |
| elements.answerInput.value = ''; |
| elements.answerInput.focus(); |
| }); |
| |
| |
| elements.backspaceBtn.addEventListener('click', () => { |
| elements.answerInput.value = elements.answerInput.value.slice(0, -1); |
| elements.answerInput.focus(); |
| }); |
| |
| |
| elements.nextQuestion.addEventListener('click', nextQuestion); |
| |
| |
| elements.timeSetting.addEventListener('change', () => { |
| state.settings.timePerQuestion = parseInt(elements.timeSetting.value); |
| state.timeLeft = state.settings.timePerQuestion; |
| updateTimerDisplay(); |
| saveState(); |
| }); |
| |
| elements.questionsSetting.addEventListener('change', () => { |
| state.settings.questionsPerRound = parseInt(elements.questionsSetting.value); |
| state.totalQuestions = state.settings.questionsPerRound; |
| updateQuestionCount(); |
| saveState(); |
| }); |
| |
| elements.soundSetting.addEventListener('change', () => { |
| state.settings.soundEnabled = elements.soundSetting.checked; |
| saveState(); |
| }); |
| |
| elements.darkMode.addEventListener('change', () => { |
| state.settings.darkMode = elements.darkMode.checked; |
| if (state.settings.darkMode) { |
| document.documentElement.classList.add('dark'); |
| } else { |
| document.documentElement.classList.remove('dark'); |
| } |
| saveState(); |
| }); |
| |
| elements.animationsSetting.addEventListener('change', () => { |
| state.settings.animations = elements.animationsSetting.checked; |
| saveState(); |
| }); |
| |
| elements.resetStats.addEventListener('click', resetStatistics); |
| } |
| |
| |
| function switchTab(tab) { |
| |
| elements.practiceTab.classList.remove('border-b-2', 'border-blue-500', 'text-blue-600', 'bg-blue-50'); |
| elements.statsTab.classList.remove('border-b-2', 'border-blue-500', 'text-blue-600', 'bg-blue-50'); |
| elements.settingsTab.classList.remove('border-b-2', 'border-blue-500', 'text-blue-600', 'bg-blue-50'); |
| |
| |
| elements.practiceSection.classList.add('hidden'); |
| elements.statsSection.classList.add('hidden'); |
| elements.settingsSection.classList.add('hidden'); |
| |
| |
| if (tab === 'practice') { |
| elements.practiceSection.classList.remove('hidden'); |
| elements.practiceTab.classList.add('border-b-2', 'border-blue-500', 'text-blue-600', 'bg-blue-50'); |
| } else if (tab === 'stats') { |
| elements.statsSection.classList.remove('hidden'); |
| elements.statsTab.classList.add('border-b-2', 'border-blue-500', 'text-blue-600', 'bg-blue-50'); |
| updateStatsDisplay(); |
| } else if (tab === 'settings') { |
| elements.settingsSection.classList.remove('hidden'); |
| elements.settingsTab.classList.add('border-b-2', 'border-blue-500', 'text-blue-600', 'bg-blue-50'); |
| } |
| } |
| |
| |
| function setDifficulty(difficulty) { |
| state.currentDifficulty = difficulty; |
| |
| |
| elements.difficultyBtns.forEach(btn => { |
| btn.classList.remove('active-difficulty'); |
| if (btn.dataset.difficulty === difficulty) { |
| btn.classList.add('active-difficulty'); |
| } |
| }); |
| |
| |
| state.currentQuestion = 1; |
| state.score = 0; |
| state.correctAnswers = 0; |
| updateQuestionCount(); |
| updateScore(); |
| generateQuestion(); |
| |
| |
| clearInterval(state.timer); |
| state.timeLeft = state.settings.timePerQuestion; |
| updateTimerDisplay(); |
| startTimer(); |
| } |
| |
| |
| function generateQuestion() { |
| let dividend, divisor; |
| |
| |
| switch (state.currentDifficulty) { |
| case 'easy': |
| dividend = Math.floor(Math.random() * 10) + 1; |
| divisor = Math.floor(Math.random() * 10) + 1; |
| break; |
| case 'medium': |
| dividend = Math.floor(Math.random() * 20) + 1; |
| divisor = Math.floor(Math.random() * 20) + 1; |
| break; |
| case 'hard': |
| dividend = Math.floor(Math.random() * 50) + 1; |
| divisor = Math.floor(Math.random() * 50) + 1; |
| break; |
| case 'expert': |
| dividend = Math.floor(Math.random() * 100) + 1; |
| divisor = Math.floor(Math.random() * 100) + 1; |
| break; |
| } |
| |
| |
| while (dividend % divisor !== 0) { |
| dividend++; |
| } |
| |
| |
| state.currentAnswer = dividend / divisor; |
| |
| |
| elements.dividend.textContent = dividend; |
| elements.divisor.textContent = divisor; |
| elements.answerInput.value = ''; |
| elements.answerInput.focus(); |
| } |
| |
| |
| function checkAnswer() { |
| const userAnswer = parseInt(elements.answerInput.value); |
| |
| if (isNaN(userAnswer)) { |
| return; |
| } |
| |
| |
| clearInterval(state.timer); |
| |
| |
| const isCorrect = userAnswer === state.currentAnswer; |
| |
| |
| state.stats[state.currentDifficulty].total++; |
| |
| if (isCorrect) { |
| state.correctAnswers++; |
| const pointsEarned = calculatePoints(); |
| state.score += pointsEarned; |
| |
| |
| state.stats[state.currentDifficulty].correct++; |
| |
| |
| showFeedback(true, pointsEarned); |
| |
| |
| if (state.settings.soundEnabled) { |
| playSound('correct'); |
| } |
| |
| |
| if (state.settings.animations) { |
| showConfetti(); |
| } |
| } else { |
| |
| showFeedback(false, 0); |
| |
| |
| if (state.settings.soundEnabled) { |
| playSound('incorrect'); |
| } |
| } |
| |
| |
| saveState(); |
| } |
| |
| |
| function calculatePoints() { |
| const timePercentage = (state.timeLeft / state.settings.timePerQuestion) * 100; |
| let points; |
| |
| if (timePercentage > 80) { |
| points = 10; |
| } else if (timePercentage > 50) { |
| points = 7; |
| } else if (timePercentage > 20) { |
| points = 5; |
| } else { |
| points = 3; |
| } |
| |
| |
| if (state.currentDifficulty === 'medium') points += 2; |
| else if (state.currentDifficulty === 'hard') points += 5; |
| else if (state.currentDifficulty === 'expert') points += 8; |
| |
| return points; |
| } |
| |
| |
| function showFeedback(isCorrect, pointsEarned) { |
| if (isCorrect) { |
| elements.feedbackIcon.className = 'fas fa-check-circle text-green-500 text-6xl mb-4'; |
| elements.feedbackTitle.textContent = 'Correct!'; |
| elements.feedbackMessage.textContent = `Great job! You earned ${pointsEarned} points.`; |
| } else { |
| elements.feedbackIcon.className = 'fas fa-times-circle text-red-500 text-6xl mb-4'; |
| elements.feedbackTitle.textContent = 'Incorrect'; |
| elements.feedbackMessage.textContent = `The correct answer was ${state.currentAnswer}. Try the next one!`; |
| } |
| |
| elements.feedbackModal.classList.remove('hidden'); |
| } |
| |
| |
| function nextQuestion() { |
| elements.feedbackModal.classList.add('hidden'); |
| |
| |
| if (state.currentQuestion >= state.totalQuestions) { |
| endGame(); |
| return; |
| } |
| |
| |
| state.currentQuestion++; |
| updateQuestionCount(); |
| |
| |
| generateQuestion(); |
| |
| |
| state.timeLeft = state.settings.timePerQuestion; |
| updateTimerDisplay(); |
| startTimer(); |
| } |
| |
| |
| function endGame() { |
| |
| alert(`Game over! Your final score is ${state.score} with ${state.correctAnswers}/${state.totalQuestions} correct answers.`); |
| |
| |
| state.currentQuestion = 1; |
| state.score = 0; |
| state.correctAnswers = 0; |
| updateQuestionCount(); |
| updateScore(); |
| generateQuestion(); |
| |
| |
| clearInterval(state.timer); |
| state.timeLeft = state.settings.timePerQuestion; |
| updateTimerDisplay(); |
| startTimer(); |
| } |
| |
| |
| function startTimer() { |
| clearInterval(state.timer); |
| |
| state.timer = setInterval(() => { |
| state.timeLeft--; |
| updateTimerDisplay(); |
| |
| if (state.timeLeft <= 0) { |
| clearInterval(state.timer); |
| checkAnswer(); |
| } |
| }, 1000); |
| } |
| |
| |
| function updateTimerDisplay() { |
| elements.timeLeft.textContent = state.timeLeft; |
| |
| |
| const circumference = 2 * Math.PI * 40; |
| const offset = circumference - (state.timeLeft / state.settings.timePerQuestion) * circumference; |
| elements.progressRing.style.strokeDashoffset = offset; |
| |
| |
| const timePercentage = (state.timeLeft / state.settings.timePerQuestion) * 100; |
| |
| if (timePercentage > 50) { |
| elements.progressRing.classList.remove('text-yellow-500', 'text-red-500'); |
| elements.progressRing.classList.add('text-blue-500'); |
| } else if (timePercentage > 20) { |
| elements.progressRing.classList.remove('text-blue-500', 'text-red-500'); |
| elements.progressRing.classList.add('text-yellow-500'); |
| } else { |
| elements.progressRing.classList.remove('text-blue-500', 'text-yellow-500'); |
| elements.progressRing.classList.add('text-red-500'); |
| } |
| } |
| |
| |
| function updateQuestionCount() { |
| elements.questionCount.textContent = `${state.currentQuestion}/${state.totalQuestions}`; |
| } |
| |
| |
| function updateScore() { |
| elements.score.textContent = state.score; |
| } |
| |
| |
| function updateStatsDisplay() { |
| |
| const totalQuestions = Object.values(state.stats).reduce((sum, diff) => sum + diff.total, 0); |
| const totalCorrect = Object.values(state.stats).reduce((sum, diff) => sum + diff.correct, 0); |
| const accuracy = totalQuestions > 0 ? Math.round((totalCorrect / totalQuestions) * 100) : 0; |
| |
| |
| elements.totalQuestionsStat.textContent = totalQuestions; |
| elements.correctAnswersStat.textContent = totalCorrect; |
| elements.accuracyStat.textContent = `${accuracy}%`; |
| |
| |
| updateDifficultyStats('easy'); |
| updateDifficultyStats('medium'); |
| updateDifficultyStats('hard'); |
| updateDifficultyStats('expert'); |
| } |
| |
| |
| function updateDifficultyStats(difficulty) { |
| const diffStats = state.stats[difficulty]; |
| const elementId = `${difficulty}-stats`; |
| const progressId = `${difficulty}-progress`; |
| |
| const accuracy = diffStats.total > 0 ? Math.round((diffStats.correct / diffStats.total) * 100) : 0; |
| |
| document.getElementById(elementId).textContent = `${diffStats.correct}/${diffStats.total} (${accuracy}%)`; |
| document.getElementById(progressId).style.width = `${accuracy}%`; |
| } |
| |
| |
| function resetStatistics() { |
| if (confirm('Are you sure you want to reset all your statistics? This cannot be undone.')) { |
| |
| state.stats = { |
| easy: { correct: 0, total: 0 }, |
| medium: { correct: 0, total: 0 }, |
| hard: { correct: 0, total: 0 }, |
| expert: { correct: 0, total: 0 } |
| }; |
| |
| |
| saveState(); |
| |
| |
| updateStatsDisplay(); |
| |
| |
| alert('All statistics have been reset.'); |
| } |
| } |
| |
| |
| function playSound(type) { |
| |
| console.log(`Playing ${type} sound`); |
| } |
| |
| |
| function showConfetti() { |
| const colors = ['#f00', '#0f0', '#00f', '#ff0', '#f0f', '#0ff']; |
| |
| for (let i = 0; i < 50; i++) { |
| const confetti = document.createElement('div'); |
| confetti.className = 'confetti'; |
| |
| |
| const size = Math.random() * 10 + 5; |
| const color = colors[Math.floor(Math.random() * colors.length)]; |
| const left = Math.random() * 100; |
| const animationDuration = Math.random() * 2 + 1; |
| |
| confetti.style.width = `${size}px`; |
| confetti.style.height = `${size}px`; |
| confetti.style.backgroundColor = color; |
| confetti.style.left = `${left}%`; |
| confetti.style.animationDuration = `${animationDuration}s`; |
| confetti.style.borderRadius = Math.random() > 0.5 ? '50%' : '0'; |
| |
| document.body.appendChild(confetti); |
| |
| |
| setTimeout(() => { |
| confetti.remove(); |
| }, animationDuration * 1000); |
| } |
| } |
| |
| |
| function updateUI() { |
| updateQuestionCount(); |
| updateScore(); |
| updateTimerDisplay(); |
| |
| |
| elements.difficultyBtns.forEach(btn => { |
| btn.classList.remove('active-difficulty'); |
| if (btn.dataset.difficulty === state.currentDifficulty) { |
| btn.classList.add('active-difficulty'); |
| } |
| }); |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded', init); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=FAROU71/cryp2-2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |