feat(alg9 ch3 final): Финал Главы 3 (5 боссов + ачивка)

This commit is contained in:
Maxim Dolgolyov
2026-05-29 08:45:17 +03:00
parent 8ecb8409eb
commit d0cfff38c1
+197 -14
View File
@@ -1741,21 +1741,204 @@ function buildP13(){
}
function buildFinal3(){
const root = document.getElementById('final3-body');
root.innerHTML = `
<div class="card">
<div class="card-header">
<span class="card-icon theory">${ICONS.theory}</span>
<span class="card-title">В разработке</span>
<span class="card-num">★</span>
const box = document.getElementById('final3-body');
let html = '';
/* Часть А — Шпаргалка главы (4 mini-карточки) */
html += `<div class="card">
<div class="card-header">
<span class="card-icon theory">${ICONS.theory}</span>
<span class="card-title">Шпаргалка главы 3</span>
<span class="card-num">Итог</span>
</div>
<div class="card-body">
<p>Все ключевые правила главы — в одном месте. Просмотри перед боссами!</p>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-top:10px">
<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);margin-bottom:6px;font-size:.92rem">§ 10 · Дробно-рац. уравнения</div>
<div style="font-size:.95rem">$\\dfrac{P(x)}{Q(x)} = 0 \\Leftrightarrow P(x) = 0,\\ Q(x) \\ne 0$. Корни, при которых знаменатель $=0$ — <b>посторонние</b>!</div>
</div>
<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);margin-bottom:6px;font-size:.92rem">§ 11 · Системы нелинейных</div>
<div style="font-size:.95rem">Подстановка (выразить переменную) или сложение. Решения — <b>точки пересечения</b> графиков.</div>
</div>
<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);margin-bottom:6px;font-size:.92rem">§ 12 · Окружность</div>
<div style="font-size:.95rem">$|AB| = \\sqrt{(x_2-x_1)^2 + (y_2-y_1)^2}$. Окр.: $(x-a)^2 + (y-b)^2 = R^2$, центр $(a;b)$, радиус $R$.</div>
</div>
<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);margin-bottom:6px;font-size:.92rem">§ 13 · Метод интервалов</div>
<div style="font-size:.95rem">Корни на прямой $\\to$ знаки чередуются $\\to$ выбрать подходящие интервалы. Корни знаменателя — <b>выколоты</b>!</div>
</div>
</div>
<div class="card-body">
<p>Содержание финала главы <b>Финал главы — в разработке</b> будет добавлено в следующих обновлениях.</p>
<p style="color:var(--muted);font-size:.9rem">Боссы и итоговые задания будут добавлены в Phase 1.</p>
</div>
</div>` + secNav('p13', null) + readButton('final3');
renderMath(root);
wireReadBtn('final3');
</div>
</div>`;
/* Часть Б — 5 боссов */
html += `<div class="card">
<div class="card-header">
<span class="card-icon rule">${ICONS.rule}</span>
<span class="card-title">Боссы главы 3</span>
<span class="card-num">5</span>
</div>
<div class="card-body">
<p>5 интегрированных задач. Каждая комбинирует несколько тем главы 3. За каждого побеждённого босса — <b>+10 XP</b>. Победишь всех — <b>+50 XP бонус</b> и ачивка «Мастер дробно-рациональных»!</p>
</div>
</div>`;
html += '<div id="ch3-bosses-container"></div>';
html += `<div style="margin-top:18px;padding:18px 20px;background:linear-gradient(135deg,var(--pri-soft),var(--sec-acc-soft));border-radius:14px;border:1.5px solid var(--pri);text-align:center" id="ch3-final-summary">
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:var(--pri2);font-size:1.1rem;margin-bottom:6px">Прогресс по боссам</div>
<div id="ch3-boss-overall" style="font-size:.95rem;color:var(--text);margin-bottom:10px">0 / 5 боссов побеждено</div>
<div style="height:12px;background:var(--card);border-radius:8px;overflow:hidden;border:1px solid var(--border)">
<div id="ch3-boss-overall-fill" style="height:100%;width:0%;background:linear-gradient(90deg,#7c3aed,#a78bfa);transition:width .35s"></div>
</div>
<div id="ch3-final-reward" style="margin-top:14px;display:none;padding:14px;background:var(--card);border-radius:11px;border:2px solid #f59e0b">
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:#92400e;font-size:1.05rem;margin-bottom:6px">Мастер дробно-рациональных</div>
<div style="font-size:.92rem;margin-bottom:10px">Глава 3 пройдена! Все 5 боссов повержены. +50 XP бонус.</div>
<a class="btn primary" href="/textbook/algebra-9-ch4" style="text-decoration:none">Дальше: Глава 4 <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></a>
</div>
</div>`;
html += secNav('p13', null);
box.innerHTML = html;
renderMath(box);
/* Боссы */
const BOSSES = [
{
n:1, color:'#10b981',
title:'Циклоп Уравнений',
tag:'§ 10 + § 13',
q:'Реши уравнение $\\dfrac{x^2 - 9}{x - 3} = 0$. Сколько корней у уравнения?',
ans:1,
hint:'$x^2 - 9 = 0 \\Rightarrow x = \\pm 3$. ОДЗ: $x \\ne 3$. Значит $x = 3$ — посторонний. Остаётся $x = -3$. Итого: <b>1 корень</b>.'
},
{
n:2, color:'#0891b2',
title:'Гарпия Систем',
tag:'§ 11 + § 12',
q:'Сколько решений у системы $\\begin{cases} x^2 + y^2 = 25 \\\\ y = x + 1 \\end{cases}$?',
ans:2,
hint:'Подставим: $x^2 + (x+1)^2 = 25 \\Rightarrow 2x^2 + 2x - 24 = 0 \\Rightarrow x^2 + x - 12 = 0 \\Rightarrow x = 3$ или $x = -4$. <b>2 решения</b>.'
},
{
n:3, color:'#7c3aed',
title:'Сирена Окружности',
tag:'§ 12 + основы',
q:'Найди радиус $R$ окружности $x^2 + y^2 - 6x + 4y - 12 = 0$.',
ans:5,
hint:'Выделим полные квадраты: $(x-3)^2 + (y+2)^2 = 12 + 9 + 4 = 25 \\Rightarrow R^2 = 25 \\Rightarrow R = 5$.'
},
{
n:4, color:'#dc2626',
title:'Минотавр Интервалов',
tag:'§ 13 + § 10',
q:'Реши $\\dfrac{x(x-4)}{x+2} \\ge 0$. Сколько <b>целых</b> значений $x$ из отрезка $[-5;\\ 5]$ удовлетворяют неравенству?',
ans:4,
hint:'Корни числителя $0, 4$ (закрашены), корень знаменателя $-2$ (выколота). Знак справа $(x=10)$: $+$. Чередование: $-, +, -, +$. Решение: $(-2;\\ 0] \\cup [4;\\ +\\infty)$. Целые в $[-5;5]$: $\\{-1, 0, 4, 5\\}$ — <b>4 значения</b>.'
},
{
n:5, color:'#f59e0b',
title:'Мастер Глубин',
tag:'§§ 1013 — синтез',
q:'Сколько решений у системы $\\begin{cases} (x-1)^2 + (y-2)^2 = 25 \\\\ y = x + 1 \\end{cases}$?',
ans:2,
hint:'Подставим $y = x + 1$: $(x-1)^2 + (x-1)^2 = 25 \\Rightarrow 2(x-1)^2 = 25 \\Rightarrow (x-1)^2 = 12{,}5$. Корней <b>2</b> (квадратное с $D > 0$).'
},
];
const cont = document.getElementById('ch3-bosses-container');
const STATE_KEY = 'algebra9_ch3_bosses';
const BOSS_STATE = (function(){
try{ const s = localStorage.getItem(STATE_KEY); if(s) return JSON.parse(s); }catch(e){}
return BOSSES.map(()=>({defeated:false}));
})();
function saveBosses(){ try{ localStorage.setItem(STATE_KEY, JSON.stringify(BOSS_STATE)); }catch(e){} }
cont.innerHTML = BOSSES.map((b, idx)=>{
return '<div class="boss-card" id="boss3-'+b.n+'-card" style="padding:16px;background:var(--card);border-radius:12px;border:2px solid '+b.color+';margin-bottom:14px">'
+'<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap">'
+'<svg viewBox="0 0 24 24" fill="none" stroke="'+b.color+'" stroke-width="2.2" style="width:28px;height:28px;flex-shrink:0"><polygon points="12,2 22,20 2,20"/></svg>'
+'<div style="font-family:\'Unbounded\',sans-serif;font-weight:800;color:'+b.color+';font-size:1.05rem">Босс '+b.n+': '+b.title+'</div>'
+'<div style="margin-left:auto;font-size:.78rem;color:var(--muted);padding:3px 8px;background:var(--sec-acc-soft);border-radius:6px">'+b.tag+'</div>'
+'</div>'
+'<div id="boss3-'+b.n+'-q" style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:1rem;line-height:1.5;margin-bottom:10px">'+b.q+'</div>'
+'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">'
+'<span style="font-family:\'JetBrains Mono\',monospace;font-size:.92rem">ответ =</span>'
+'<input type="number" id="boss3-'+b.n+'-ans" class="tinp" style="width:120px;text-align:center" placeholder="число">'
+'<button class="btn primary" id="boss3-'+b.n+'-go" style="background:'+b.color+';border-color:'+b.color+'">Атаковать</button>'
+'<button class="btn" id="boss3-'+b.n+'-hint">Подсказка</button>'
+'</div>'
+'<div class="feedback" id="boss3-'+b.n+'-fb"></div>'
+'</div>';
}).join('');
renderMath(cont);
function refreshOverall(){
const won = BOSS_STATE.filter(s => s.defeated).length;
const txt = document.getElementById('ch3-boss-overall');
const fill = document.getElementById('ch3-boss-overall-fill');
if(txt) txt.textContent = won + ' / ' + BOSSES.length + ' боссов побеждено';
if(fill) fill.style.width = (won * 100 / BOSSES.length) + '%';
if(won >= BOSSES.length){
const reward = document.getElementById('ch3-final-reward');
if(reward && reward.style.display === 'none'){
reward.style.display = 'block';
if(!STATE.achievements.has('ch3_done')){
achievement('ch3_done','Мастер дробно-рациональных');
addXp(50, 'ch3-bonus');
bumpProgress('final3', 30);
if(window.confetti){ try{ confetti(); }catch(e){} }
}
}
}
}
BOSSES.forEach((b, idx)=>{
const card = document.getElementById('boss3-'+b.n+'-card');
const goBtn = document.getElementById('boss3-'+b.n+'-go');
const hintBtn = document.getElementById('boss3-'+b.n+'-hint');
const ansInp = document.getElementById('boss3-'+b.n+'-ans');
if(BOSS_STATE[idx].defeated){
card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))';
goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.textContent = '✓ Повержен';
ansInp.disabled = true;
}
goBtn.addEventListener('click', ()=>{
if(BOSS_STATE[idx].defeated) return;
const fb = document.getElementById('boss3-'+b.n+'-fb');
const val = parseInt(ansInp.value, 10);
if(isNaN(val)){ feedback(fb, false, '&#10007; Введи целое число.'); return; }
if(val === b.ans){
BOSS_STATE[idx].defeated = true; saveBosses();
feedback(fb, true, '&#10003; Босс '+b.n+' повержен! +10 XP. '+b.hint);
addXp(10, 'boss-ch3-'+b.n);
bumpProgress('final3', 18);
goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.textContent = '✓ Повержен';
ansInp.disabled = true;
card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))';
refreshOverall();
} else {
feedback(fb, false, '&#10007; Промах. Попробуй ещё. Подсказка доступна.');
}
});
hintBtn.addEventListener('click', ()=>{
const fb = document.getElementById('boss3-'+b.n+'-fb');
fb.className = 'feedback ok';
fb.innerHTML = '<b>Подсказка:</b> '+b.hint;
fb.style.display = 'block';
fb.style.background = 'var(--warn-bg)';
fb.style.color = '#92400e';
fb.style.borderLeftColor = 'var(--warn)';
renderMath(fb);
});
ansInp.addEventListener('keydown', e=>{ if(e.key === 'Enter') goBtn.click(); });
});
refreshOverall();
}
/* ===== Search ===== */