cryp2-2 / index.html
FAROU71's picture
Add 3 files
bbf2fd5 verified
Raw
History Blame Contribute Delete
45.2 kB
<!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 -->
<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>