// phys9_finals.js — улучшение финалов 1-5 Физики 9: // 1. Расширяет window.checkNum чтобы поддерживать сигнатуру (id, answer, unit, tol) // (раньше legacy checkNum принимал только sec из POOLS — финалы не работали). // 2. Считает решённые задачи каждого финала, рисует прогресс-бар. // 3. При 100% — выдаёт XP + ачивку «Мастер главы N». (function(){ 'use strict'; const FINAL_TASKS = {}; /* finalN → { total, ok: Set } */ const ACHIEVED = new Set(); /* === Расширение checkNum === */ const _origCheckNum = typeof window.checkNum === 'function' ? window.checkNum : null; function patchedCheckNum(arg1, arg2, arg3, arg4){ /* Финальная задача: arg1 = id (например 'fin1-q1'), arg2 = answer, arg3 = unit, arg4 = tol */ if (typeof arg2 === 'number' && /^fin\d+-q\d+/.test(arg1)) { const id = arg1; const answer = arg2; const tol = arg4 || Math.max(0.005, Math.abs(answer) * 0.03); const inp = document.getElementById(id); const fb = document.getElementById('fb-' + id); if (!inp || !fb) return; const val = (inp.value || '').trim().replace(',', '.'); const num = parseFloat(val); if (val === '' || isNaN(num)) { fb.className = 'feedback fail show'; fb.style.display = 'block'; fb.innerHTML = 'Введи число.'; return; } const ok = Math.abs(num - answer) <= tol; if (ok) { fb.className = 'feedback ok show'; fb.style.display = 'block'; fb.innerHTML = '✓ Верно! ' + (arg3 ? '(' + arg3 + ')' : ''); inp.disabled = true; const finalKey = id.match(/^fin(\d+)/)[1]; const finalId = 'final' + finalKey; if (!FINAL_TASKS[finalId]) FINAL_TASKS[finalId] = { total: 0, ok: new Set() }; FINAL_TASKS[finalId].ok.add(id); _updateFinalProgress(finalId); try { if (window.addXp) window.addXp(8, 'phys9-fin-' + id); } catch(e){} } else { fb.className = 'feedback fail show'; fb.style.display = 'block'; fb.innerHTML = '✗ Не то. Перепроверь решение.'; } return; } /* Legacy путь — для POOLS секций */ if (_origCheckNum) return _origCheckNum.apply(this, arguments); } window.checkNum = patchedCheckNum; /* === Прогресс-бар + ачивка === */ function _ensureProgressBar(finalId){ const box = document.getElementById(finalId + '-body'); if (!box) return null; let bar = box.querySelector('.phys9-fin-bar'); if (bar) return bar; /* Подсчёт общего количества задач в финале */ const tasks = box.querySelectorAll('input[id^="' + finalId.replace('final','fin') + '-q"]'); const total = tasks.length; FINAL_TASKS[finalId] = FINAL_TASKS[finalId] || { total: total, ok: new Set() }; FINAL_TASKS[finalId].total = total; /* Вставляем бар как первый дочерний элемент в body */ const wrap = document.createElement('div'); wrap.className = 'phys9-fin-bar'; wrap.style.cssText = 'margin:14px 0 18px;padding:14px 16px;background:linear-gradient(135deg,var(--sec-acc-soft,#dbeafe),var(--card,#fff));border:1.5px solid var(--sec-acc,#2563eb);border-radius:12px'; wrap.innerHTML = '
' + '
Финал главы — задач решено: 0 / ' + total + '
' + '' + '
' + '
'; /* Вставка перед первой task-card или в начало */ const firstTask = box.querySelector('.task-card'); if (firstTask) box.insertBefore(wrap, firstTask); else box.appendChild(wrap); return wrap; } function _updateFinalProgress(finalId){ const bar = _ensureProgressBar(finalId); if (!bar) return; const data = FINAL_TASKS[finalId]; if (!data) return; const pct = data.total > 0 ? Math.round(data.ok.size / data.total * 100) : 0; const cnt = document.getElementById(finalId + '-cnt'); const fill = document.getElementById(finalId + '-fill'); const badge = document.getElementById(finalId + '-badge'); if (cnt) cnt.textContent = data.ok.size; if (fill) fill.style.width = pct + '%'; if (data.total > 0 && data.ok.size === data.total && !ACHIEVED.has(finalId)) { ACHIEVED.add(finalId); if (badge) badge.style.display = 'inline-block'; try { if (window.addXp) window.addXp(50, 'phys9-master-' + finalId); } catch(e){} try { localStorage.setItem('physics9_' + finalId + '_master', '1'); const allDone = ['final1','final2','final3','final4','final5'].every(f => localStorage.getItem('physics9_' + f + '_master') === '1'); if (allDone && !localStorage.getItem('physics9_grandmaster')) { localStorage.setItem('physics9_grandmaster', '1'); if (window.addXp) window.addXp(150, 'phys9-grandmaster'); alert('Поздравляем! Все 5 финалов глав сданы.\nАчивка: МАГИСТР ФИЗИКИ 9 (+150 XP)'); } } catch(e){} } } /* === Инициализация при открытии финала === */ window.PHYS9_FINALS_INIT = function(finalId){ _ensureProgressBar(finalId); /* Восстановить состояние из disabled полей (если перезагрузка/возврат) */ const box = document.getElementById(finalId + '-body'); if (!box) return; box.querySelectorAll('input[id^="' + finalId.replace('final','fin') + '-q"]').forEach(inp=>{ if (inp.disabled) { if (!FINAL_TASKS[finalId]) FINAL_TASKS[finalId] = { total: 0, ok: new Set() }; FINAL_TASKS[finalId].ok.add(inp.id); } }); _updateFinalProgress(finalId); }; })();