Download index.html from FAROU71/cryp2-2: direct link, hf CLI and curl.
- Browser
- Download file 45.2 kB
-
https://huggingface.co/spaces/FAROU71/cryp2-2/resolve/main/index.html
- Command line
-
hf download hf://spaces/FAROU71/cryp2-2/index.html
-
curl -L -o index.html https://huggingface.co/spaces/FAROU71/cryp2-2/resolve/main/index.html
45.2 kB
| <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 --> | |
| <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> | |
| <!-- Main App --> | |
| <div class="bg-white rounded-xl shadow-lg overflow-hidden transition-all duration-300"> | |
| <!-- App Tabs --> | |
| <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> | |
| <!-- Practice Section --> | |
| <div id="practice-section" class="p-6 md:p-8"> | |
| <!-- Difficulty Selector --> | |
| <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> | |
| <!-- Problem Display --> | |
| <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> | |
| <!-- Progress Ring --> | |
| <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> | |
| <!-- Division Problem --> | |
| <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> | |
| <!-- Keypad (for mobile) --> | |
| <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> | |
| <!-- Feedback Modal (hidden by default) --> | |
| <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> | |
| <!-- Stats Section --> | |
| <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> | |
| <!-- Settings Section --> | |
| <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 --> | |
| <footer class="mt-12 text-center text-gray-500 text-sm"> | |
| <p>Divvision - A fun way to practice division © 2023</p> | |
| </footer> | |
| </div> | |
| <script> | |
| // App State | |
| 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 | |
| } | |
| }; | |
| // DOM Elements | |
| 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') | |
| }; | |
| // Initialize the app | |
| function init() { | |
| // Load saved state from localStorage | |
| loadState(); | |
| // Set up event listeners | |
| setupEventListeners(); | |
| // Update UI based on loaded state | |
| updateUI(); | |
| // Generate first question | |
| generateQuestion(); | |
| // Start timer | |
| startTimer(); | |
| } | |
| // Load state from localStorage | |
| 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); | |
| // Update settings UI | |
| 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; | |
| // Apply dark mode if enabled | |
| if (state.settings.darkMode) { | |
| document.documentElement.classList.add('dark'); | |
| } | |
| } | |
| // Update state with settings | |
| state.timeLeft = state.settings.timePerQuestion; | |
| state.totalQuestions = state.settings.questionsPerRound; | |
| } | |
| // Save state to localStorage | |
| function saveState() { | |
| localStorage.setItem('divvision_stats', JSON.stringify(state.stats)); | |
| localStorage.setItem('divvision_settings', JSON.stringify(state.settings)); | |
| } | |
| // Set up event listeners | |
| function setupEventListeners() { | |
| // Tab navigation | |
| elements.practiceTab.addEventListener('click', () => switchTab('practice')); | |
| elements.statsTab.addEventListener('click', () => switchTab('stats')); | |
| elements.settingsTab.addEventListener('click', () => switchTab('settings')); | |
| // Difficulty selection | |
| elements.difficultyBtns.forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| const difficulty = btn.dataset.difficulty; | |
| setDifficulty(difficulty); | |
| }); | |
| }); | |
| // Answer submission | |
| elements.submitAnswer.addEventListener('click', checkAnswer); | |
| elements.answerInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| checkAnswer(); | |
| } | |
| }); | |
| // Number buttons | |
| elements.numberBtns.forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| elements.answerInput.value += btn.textContent; | |
| elements.answerInput.focus(); | |
| }); | |
| }); | |
| // Clear button | |
| elements.clearBtn.addEventListener('click', () => { | |
| elements.answerInput.value = ''; | |
| elements.answerInput.focus(); | |
| }); | |
| // Backspace button | |
| elements.backspaceBtn.addEventListener('click', () => { | |
| elements.answerInput.value = elements.answerInput.value.slice(0, -1); | |
| elements.answerInput.focus(); | |
| }); | |
| // Next question button | |
| elements.nextQuestion.addEventListener('click', nextQuestion); | |
| // Settings changes | |
| 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); | |
| } | |
| // Switch between tabs | |
| function switchTab(tab) { | |
| // Update active tab styling | |
| 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'); | |
| // Hide all sections | |
| elements.practiceSection.classList.add('hidden'); | |
| elements.statsSection.classList.add('hidden'); | |
| elements.settingsSection.classList.add('hidden'); | |
| // Show selected section and update tab styling | |
| 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'); | |
| } | |
| } | |
| // Set difficulty level | |
| function setDifficulty(difficulty) { | |
| state.currentDifficulty = difficulty; | |
| // Update active difficulty button styling | |
| elements.difficultyBtns.forEach(btn => { | |
| btn.classList.remove('active-difficulty'); | |
| if (btn.dataset.difficulty === difficulty) { | |
| btn.classList.add('active-difficulty'); | |
| } | |
| }); | |
| // Reset current question and generate new one | |
| state.currentQuestion = 1; | |
| state.score = 0; | |
| state.correctAnswers = 0; | |
| updateQuestionCount(); | |
| updateScore(); | |
| generateQuestion(); | |
| // Reset timer | |
| clearInterval(state.timer); | |
| state.timeLeft = state.settings.timePerQuestion; | |
| updateTimerDisplay(); | |
| startTimer(); | |
| } | |
| // Generate a new division question | |
| function generateQuestion() { | |
| let dividend, divisor; | |
| // Generate numbers based on difficulty | |
| 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; | |
| } | |
| // Make sure the division results in a whole number | |
| while (dividend % divisor !== 0) { | |
| dividend++; | |
| } | |
| // Store the correct answer | |
| state.currentAnswer = dividend / divisor; | |
| // Update the UI | |
| elements.dividend.textContent = dividend; | |
| elements.divisor.textContent = divisor; | |
| elements.answerInput.value = ''; | |
| elements.answerInput.focus(); | |
| } | |
| // Check the user's answer | |
| function checkAnswer() { | |
| const userAnswer = parseInt(elements.answerInput.value); | |
| if (isNaN(userAnswer)) { | |
| return; // No answer provided | |
| } | |
| // Stop the timer | |
| clearInterval(state.timer); | |
| // Check if answer is correct | |
| const isCorrect = userAnswer === state.currentAnswer; | |
| // Update stats | |
| state.stats[state.currentDifficulty].total++; | |
| if (isCorrect) { | |
| state.correctAnswers++; | |
| const pointsEarned = calculatePoints(); | |
| state.score += pointsEarned; | |
| // Update stats | |
| state.stats[state.currentDifficulty].correct++; | |
| // Show correct feedback | |
| showFeedback(true, pointsEarned); | |
| // Play sound if enabled | |
| if (state.settings.soundEnabled) { | |
| playSound('correct'); | |
| } | |
| // Show confetti if animations enabled | |
| if (state.settings.animations) { | |
| showConfetti(); | |
| } | |
| } else { | |
| // Show incorrect feedback | |
| showFeedback(false, 0); | |
| // Play sound if enabled | |
| if (state.settings.soundEnabled) { | |
| playSound('incorrect'); | |
| } | |
| } | |
| // Save updated stats | |
| saveState(); | |
| } | |
| // Calculate points based on time left | |
| 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; | |
| } | |
| // Bonus points for higher difficulties | |
| if (state.currentDifficulty === 'medium') points += 2; | |
| else if (state.currentDifficulty === 'hard') points += 5; | |
| else if (state.currentDifficulty === 'expert') points += 8; | |
| return points; | |
| } | |
| // Show feedback modal | |
| 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'); | |
| } | |
| // Move to next question or end game | |
| function nextQuestion() { | |
| elements.feedbackModal.classList.add('hidden'); | |
| // Check if we've reached the total questions | |
| if (state.currentQuestion >= state.totalQuestions) { | |
| endGame(); | |
| return; | |
| } | |
| // Increment question counter | |
| state.currentQuestion++; | |
| updateQuestionCount(); | |
| // Generate new question | |
| generateQuestion(); | |
| // Reset timer | |
| state.timeLeft = state.settings.timePerQuestion; | |
| updateTimerDisplay(); | |
| startTimer(); | |
| } | |
| // End the current game session | |
| function endGame() { | |
| // Show completion message | |
| alert(`Game over! Your final score is ${state.score} with ${state.correctAnswers}/${state.totalQuestions} correct answers.`); | |
| // Reset for new game | |
| state.currentQuestion = 1; | |
| state.score = 0; | |
| state.correctAnswers = 0; | |
| updateQuestionCount(); | |
| updateScore(); | |
| generateQuestion(); | |
| // Reset timer | |
| clearInterval(state.timer); | |
| state.timeLeft = state.settings.timePerQuestion; | |
| updateTimerDisplay(); | |
| startTimer(); | |
| } | |
| // Start the timer | |
| function startTimer() { | |
| clearInterval(state.timer); | |
| state.timer = setInterval(() => { | |
| state.timeLeft--; | |
| updateTimerDisplay(); | |
| if (state.timeLeft <= 0) { | |
| clearInterval(state.timer); | |
| checkAnswer(); // Auto-submit when time runs out | |
| } | |
| }, 1000); | |
| } | |
| // Update timer display | |
| function updateTimerDisplay() { | |
| elements.timeLeft.textContent = state.timeLeft; | |
| // Update progress ring | |
| const circumference = 2 * Math.PI * 40; | |
| const offset = circumference - (state.timeLeft / state.settings.timePerQuestion) * circumference; | |
| elements.progressRing.style.strokeDashoffset = offset; | |
| // Change color based on time left | |
| 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'); | |
| } | |
| } | |
| // Update question count display | |
| function updateQuestionCount() { | |
| elements.questionCount.textContent = `${state.currentQuestion}/${state.totalQuestions}`; | |
| } | |
| // Update score display | |
| function updateScore() { | |
| elements.score.textContent = state.score; | |
| } | |
| // Update stats display | |
| function updateStatsDisplay() { | |
| // Calculate totals | |
| 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; | |
| // Update general stats | |
| elements.totalQuestionsStat.textContent = totalQuestions; | |
| elements.correctAnswersStat.textContent = totalCorrect; | |
| elements.accuracyStat.textContent = `${accuracy}%`; | |
| // Update difficulty-specific stats | |
| updateDifficultyStats('easy'); | |
| updateDifficultyStats('medium'); | |
| updateDifficultyStats('hard'); | |
| updateDifficultyStats('expert'); | |
| } | |
| // Update stats for a specific difficulty | |
| 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}%`; | |
| } | |
| // Reset all statistics | |
| function resetStatistics() { | |
| if (confirm('Are you sure you want to reset all your statistics? This cannot be undone.')) { | |
| // Reset stats in state | |
| state.stats = { | |
| easy: { correct: 0, total: 0 }, | |
| medium: { correct: 0, total: 0 }, | |
| hard: { correct: 0, total: 0 }, | |
| expert: { correct: 0, total: 0 } | |
| }; | |
| // Save to localStorage | |
| saveState(); | |
| // Update UI | |
| updateStatsDisplay(); | |
| // Show confirmation | |
| alert('All statistics have been reset.'); | |
| } | |
| } | |
| // Play sound effect | |
| function playSound(type) { | |
| // In a real app, you would play actual sound files here | |
| console.log(`Playing ${type} sound`); | |
| } | |
| // Show confetti animation | |
| 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'; | |
| // Random properties | |
| 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); | |
| // Remove after animation completes | |
| setTimeout(() => { | |
| confetti.remove(); | |
| }, animationDuration * 1000); | |
| } | |
| } | |
| // Update UI based on state | |
| function updateUI() { | |
| updateQuestionCount(); | |
| updateScore(); | |
| updateTimerDisplay(); | |
| // Set active difficulty button | |
| elements.difficultyBtns.forEach(btn => { | |
| btn.classList.remove('active-difficulty'); | |
| if (btn.dataset.difficulty === state.currentDifficulty) { | |
| btn.classList.add('active-difficulty'); | |
| } | |
| }); | |
| } | |
| // Initialize the app when DOM is loaded | |
| 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> |