Add tracking for correct and incorrect answers in FlagQuiz and implement adaptive learning settings

This commit is contained in:
sHa
2025-08-11 18:06:43 +03:00
parent 317d953a78
commit 118f7e9399
2 changed files with 151 additions and 26 deletions

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="1.5"/>
<path d="M3.66122 10.6392C4.13377 10.9361 4.43782 11.4419 4.43782 11.9999C4.43781 12.558 4.13376 13.0638 3.66122 13.3607C3.33966 13.5627 3.13248 13.7242 2.98508 13.9163C2.66217 14.3372 2.51966 14.869 2.5889 15.3949C2.64082 15.7893 2.87379 16.1928 3.33973 16.9999C3.80568 17.8069 4.03865 18.2104 4.35426 18.4526C4.77508 18.7755 5.30694 18.918 5.83284 18.8488C6.07287 18.8172 6.31628 18.7185 6.65196 18.5411C7.14544 18.2803 7.73558 18.2699 8.21895 18.549C8.70227 18.8281 8.98827 19.3443 9.00912 19.902C9.02332 20.2815 9.05958 20.5417 9.15224 20.7654C9.35523 21.2554 9.74458 21.6448 10.2346 21.8478C10.6022 22 11.0681 22 12 22C12.9319 22 13.3978 22 13.7654 21.8478C14.2554 21.6448 14.6448 21.2554 14.8478 20.7654C14.9404 20.5417 14.9767 20.2815 14.9909 19.9021C15.0117 19.3443 15.2977 18.8281 15.7811 18.549C16.2644 18.27 16.8545 18.2804 17.3479 18.5412C17.6837 18.7186 17.9271 18.8173 18.1671 18.8489C18.693 18.9182 19.2249 18.7756 19.6457 18.4527C19.9613 18.2106 20.1943 17.807 20.6603 17C20.8677 16.6407 21.029 16.3614 21.1486 16.1272M20.3387 13.3608C19.8662 13.0639 19.5622 12.5581 19.5621 12.0001C19.5621 11.442 19.8662 10.9361 20.3387 10.6392C20.6603 10.4372 20.8674 10.2757 21.0148 10.0836C21.3377 9.66278 21.4802 9.13092 21.411 8.60502C21.3591 8.2106 21.1261 7.80708 20.6601 7.00005C20.1942 6.19301 19.9612 5.7895 19.6456 5.54732C19.2248 5.22441 18.6929 5.0819 18.167 5.15113C17.927 5.18274 17.6836 5.2814 17.3479 5.45883C16.8544 5.71964 16.2643 5.73004 15.781 5.45096C15.2977 5.1719 15.0117 4.6557 14.9909 4.09803C14.9767 3.71852 14.9404 3.45835 14.8478 3.23463C14.6448 2.74458 14.2554 2.35523 13.7654 2.15224C13.3978 2 12.9319 2 12 2C11.0681 2 10.6022 2 10.2346 2.15224C9.74458 2.35523 9.35523 2.74458 9.15224 3.23463C9.05958 3.45833 9.02332 3.71848 9.00912 4.09794C8.98826 4.65566 8.70225 5.17191 8.21891 5.45096C7.73557 5.73002 7.14548 5.71959 6.65205 5.4588C6.31633 5.28136 6.0729 5.18269 5.83285 5.15108C5.30695 5.08185 4.77509 5.22436 4.35427 5.54727C4.03866 5.78945 3.80569 6.19297 3.33974 7C3.13231 7.35929 2.97105 7.63859 2.85138 7.87273" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -29,6 +29,8 @@
// Scoring
let score = { correct: 0, total: 0, skipped: 0 };
let gameStats = { correct: 0, wrong: 0, total: 0, skipped: 0 };
let wrongAnswers = new Map(); // Track flags answered incorrectly: flag.name -> count
let correctAnswers = new Map(); // Track flags answered correctly: flag.name -> count
// Achievement System
let currentStreak = 0;
@@ -41,6 +43,8 @@
let showSettings = false;
let settingsLoaded = false;
let showResetConfirmation = false;
let focusWrongAnswers = false;
let reduceCorrectAnswers = false;
// Theme
let theme = 'system';
@@ -51,16 +55,16 @@
theme = t;
}
// Save settings when they change (after initial load)
$: if (settingsLoaded) {
localStorage.setItem('flagQuizSettings', JSON.stringify({ autoAdvance }));
}
// Update achievement count when achievements component is available
$: if (achievementsComponent) {
updateAchievementCount();
}
// Save settings when they change (after initial load)
$: if (settingsLoaded && typeof reduceCorrectAnswers !== 'undefined') {
localStorage.setItem('flagQuizSettings', JSON.stringify({ autoAdvance, focusWrongAnswers, reduceCorrectAnswers }));
}
// Load game stats from localStorage
onMount(async () => {
// Initialize theme
@@ -94,12 +98,36 @@
}
}
// Load wrong answers tracking
const savedWrongAnswers = localStorage.getItem('flagQuizWrongAnswers');
if (savedWrongAnswers) {
try {
const loadedWrongAnswers = JSON.parse(savedWrongAnswers);
wrongAnswers = new Map(Object.entries(loadedWrongAnswers));
} catch (e) {
console.error('Error loading wrong answers:', e);
}
}
// Load correct answers tracking
const savedCorrectAnswers = localStorage.getItem('flagQuizCorrectAnswers');
if (savedCorrectAnswers) {
try {
const loadedCorrectAnswers = JSON.parse(savedCorrectAnswers);
correctAnswers = new Map(Object.entries(loadedCorrectAnswers));
} catch (e) {
console.error('Error loading correct answers:', e);
}
}
// Load settings
const savedSettings = localStorage.getItem('flagQuizSettings');
if (savedSettings) {
try {
const settings = JSON.parse(savedSettings);
autoAdvance = settings.autoAdvance !== undefined ? settings.autoAdvance : true;
focusWrongAnswers = settings.focusWrongAnswers !== undefined ? settings.focusWrongAnswers : false;
reduceCorrectAnswers = settings.reduceCorrectAnswers !== undefined ? settings.reduceCorrectAnswers : false;
} catch (e) {
console.error('Error loading settings:', e);
}
@@ -107,8 +135,8 @@
}
await loadFlags();
generateQuestion();
settingsLoaded = true;
generateQuestion();
});
function applyTheme(theme) {
@@ -169,38 +197,73 @@
// Randomly choose question type
questionType = Math.random() < 0.5 ? 'flag-to-country' : 'country-to-flag';
// Pick a random correct answer
const correctFlag = flags[Math.floor(Math.random() * flags.length)];
// Pick correct answer with adaptive learning settings
let correctFlag;
// Simple fallback to avoid uninitialized variable errors
if (settingsLoaded && (focusWrongAnswers || reduceCorrectAnswers)) { // Re-enable adaptive learning
// Create weighted array based on learning settings
const weightedFlags = [];
for (const flag of flags) {
const wrongCount = wrongAnswers.get(flag.name) || 0;
const correctCount = correctAnswers.get(flag.name) || 0;
let weight = 1; // Base weight
// Increase weight for flags with wrong answers (if setting enabled)
if (focusWrongAnswers && wrongCount > 0) {
weight = Math.min(wrongCount + 1, 4); // Max 4x weight for wrong answers
}
// Decrease weight for flags with correct answers (if setting enabled)
if (reduceCorrectAnswers && correctCount > 0) {
weight = weight / Math.min(correctCount + 1, 4); // Reduce weight, min 0.25x
}
// Add flag to weighted array based on calculated weight
const finalWeight = Math.max(0.25, weight); // Minimum weight to ensure variety
const timesToAdd = Math.ceil(finalWeight);
for (let i = 0; i < timesToAdd; i++) {
weightedFlags.push(flag);
}
}
if (weightedFlags.length > 0) {
correctFlag = weightedFlags[Math.floor(Math.random() * weightedFlags.length)];
} else {
correctFlag = flags[Math.floor(Math.random() * flags.length)];
}
} else {
// Normal random selection
correctFlag = flags[Math.floor(Math.random() * flags.length)];
}
const correctCountry = getCountryName(correctFlag).toLowerCase();
// Generate 3 wrong answers ensuring no duplicate country names
const wrongAnswers = [];
const wrongOptions = [];
const usedCountries = new Set([correctCountry]);
while (wrongAnswers.length < 3 && wrongAnswers.length < flags.length - 1) {
while (wrongOptions.length < 3 && wrongOptions.length < flags.length - 1) {
const randomFlag = flags[Math.floor(Math.random() * flags.length)];
const randomCountry = getCountryName(randomFlag).toLowerCase();
if (randomFlag !== correctFlag &&
!wrongAnswers.includes(randomFlag) &&
!usedCountries.has(randomCountry)) {
wrongAnswers.push(randomFlag);
if (!usedCountries.has(randomCountry)) {
wrongOptions.push(randomFlag);
usedCountries.add(randomCountry);
}
}
// Ensure we have enough options
if (wrongAnswers.length < 3) {
console.warn(`Only found ${wrongAnswers.length + 1} unique countries, regenerating...`);
// Try again
generateQuestion();
return;
// If we couldn't find 3 unique countries, fill with random flags
while (wrongOptions.length < 3) {
const randomFlag = flags[Math.floor(Math.random() * flags.length)];
if (randomFlag !== correctFlag && !wrongOptions.includes(randomFlag)) {
wrongOptions.push(randomFlag);
}
}
// Shuffle all options
const allOptions = [correctFlag, ...wrongAnswers].sort(() => Math.random() - 0.5);
currentQuestion = {
// Combine correct and wrong answers
const allOptions = [correctFlag, ...wrongOptions].sort(() => Math.random() - 0.5); currentQuestion = {
type: questionType,
correct: correctFlag,
options: allOptions,
@@ -225,6 +288,14 @@
gameStats.correct++;
currentStreak++;
// Track correct answer for this flag
if (currentQuestion.correct?.name) {
const flagName = currentQuestion.correct.name;
correctAnswers.set(flagName, (correctAnswers.get(flagName) || 0) + 1);
// Save correct answers to localStorage
localStorage.setItem('flagQuizCorrectAnswers', JSON.stringify(Object.fromEntries(correctAnswers)));
}
// Track continent progress for correct answers
if (achievementsComponent && currentQuestion.correct?.tags) {
const continent = currentQuestion.correct.tags.find(tag =>
@@ -242,6 +313,15 @@
} else {
gameStats.wrong++;
currentStreak = 0; // Reset streak on wrong answer
// Track wrong answer for this flag
if (currentQuestion.correct?.name) {
const flagName = currentQuestion.correct.name;
wrongAnswers.set(flagName, (wrongAnswers.get(flagName) || 0) + 1);
// Save wrong answers to localStorage
localStorage.setItem('flagQuizWrongAnswers', JSON.stringify(Object.fromEntries(wrongAnswers)));
}
if (achievementsComponent) {
achievementsComponent.resetConsecutiveSkips();
}
@@ -330,6 +410,14 @@
currentStreak = 0;
localStorage.setItem('flagQuizStats', JSON.stringify(gameStats));
// Reset wrong answers tracking
wrongAnswers = new Map();
localStorage.removeItem('flagQuizWrongAnswers');
// Reset correct answers tracking
correctAnswers = new Map();
localStorage.removeItem('flagQuizCorrectAnswers');
// Reset achievements
if (achievementsComponent) {
localStorage.removeItem('flagQuizAchievements');
@@ -369,6 +457,10 @@
}
</script>
<svelte:head>
<title>Flag Quiz</title>
</svelte:head>
<Header
{theme}
{setTheme}
@@ -399,7 +491,8 @@
aria-labelledby="settings-title"
>
<div class="settings-header">
<h2 id="settings-title">⚙️ Game Settings</h2>
<InlineSvg path="/icons/settings.svg" alt="Settings" />
<h2 id="settings-title">Game Settings</h2>
<button class="close-btn" on:click={toggleSettings}>✕</button>
</div>
@@ -414,6 +507,26 @@
</label>
</div>
<div class="setting-item">
<label>
<input
type="checkbox"
bind:checked={focusWrongAnswers}
/>
Focus on previously answered incorrectly flags
</label>
</div>
<div class="setting-item">
<label>
<input
type="checkbox"
bind:checked={reduceCorrectAnswers}
/>
Show correctly answered flags less frequently
</label>
</div>
<div class="setting-actions">
<button class="reset-stats-btn" on:click={resetAllStats}>
Reset All Statistics
@@ -449,6 +562,7 @@
<li>✗ Current session score</li>
<li>✗ All unlocked achievements</li>
<li>✗ Achievement progress</li>
<li>✗ Wrong answer tracking data</li>
</ul>
<p><strong>This cannot be undone!</strong></p>
</div>
@@ -637,11 +751,17 @@
border-bottom: 2px solid var(--color-border);
}
.settings-header :global(.svg-wrapper) {
width: 24px;
height: 24px;
display: inline-flex;
flex-shrink: 0;
}
.settings-header h2 {
margin: 0;
color: var(--color-text-primary);
}
.close-btn {
background: none;
border: none;