feat(geom11 ch3 final): Финал Раздела 3 (5 боссов + ачивка)

This commit is contained in:
Maxim Dolgolyov
2026-05-29 14:49:25 +03:00
parent bfa7c46ef5
commit bf794f76a6
+216 -1
View File
@@ -396,7 +396,7 @@ function buildParaSelector(){
}
const BUILT=new Set();
const BUILDERS = { p5:buildP5, p6:buildP6, p7:buildP7, final3:()=>buildStub('final3') };
const BUILDERS = { p5:buildP5, p6:buildP6, p7:buildP7, final3:buildFinal3 };
function ensureBuilt(id){ if(BUILT.has(id)) return; const fn=BUILDERS[id]; if(fn){ fn(); BUILT.add(id); } }
function goTo(id){
STATE.current=id; ensureBuilt(id);
@@ -2083,6 +2083,221 @@ function buildP7(){
wireReadBtn('p7');
}
/* ===== ФИНАЛ РАЗДЕЛА 3 — Сфера, шар, правильные многогранники ===== */
function buildFinal3(){
const box = document.getElementById('final3-body');
if(!box) return;
let html = '';
/* Часть А — Шпаргалка раздела 3 (3 mini-карточки по числу § в разделе) */
html += '<div class="card">'
+ '<div class="card-header">'
+ '<div class="card-icon theory">' + ICONS.theory + '</div>'
+ '<div class="card-title">Шпаргалка раздела 3</div>'
+ '<div class="card-num">Итог</div>'
+ '</div>'
+ '<div class="card-body">'
+ '<p>Ключевые формулы трёх параграфов раздела в одном месте — пробеги глазами перед битвой с боссами.</p>'
+ '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,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="display:flex;align-items:center;gap:8px;margin-bottom:6px">'
+ '<svg viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2" style="width:18px;height:18px"><circle cx="12" cy="12" r="9"/><ellipse cx="12" cy="12" rx="9" ry="3.5"/></svg>'
+ '<div style="font-family:\'Unbounded\',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 5 · Сфера</div>'
+ '</div>'
+ '<div style="font-size:.94rem;line-height:1.55">Уравнение: $(x-a)^2+(y-b)^2+(z-c)^2=R^2$. Касательная плоскость $\\perp$ радиусу в точке касания. Сечение плоскостью — окружность радиуса $r=\\sqrt{R^2-d^2}$, где $d$ — расстояние от центра до плоскости.</div>'
+ '</div>'
+ '<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">'
+ '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">'
+ '<svg viewBox="0 0 24 24" fill="none" stroke="#dc2626" stroke-width="2" style="width:18px;height:18px"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/></svg>'
+ '<div style="font-family:\'Unbounded\',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 6 · Шар</div>'
+ '</div>'
+ '<div style="font-size:.94rem;line-height:1.55">$S=4\\pi R^2$, $V=\\tfrac{4}{3}\\pi R^3$. Сегмент: $V_{сег}=\\tfrac{\\pi h^2(3R-h)}{3}$, $S_{сферич}=2\\pi R h$. Куб со стороной $a$: вписанный шар $r=a/2$, описанный $R=\\tfrac{a\\sqrt{3}}{2}$.</div>'
+ '</div>'
+ '<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">'
+ '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">'
+ '<svg viewBox="0 0 24 24" fill="none" stroke="#7c3aed" stroke-width="2" style="width:18px;height:18px"><polygon points="12,2 22,8 22,16 12,22 2,16 2,8"/><polyline points="2,8 12,12 22,8"/><line x1="12" y1="12" x2="12" y2="22"/></svg>'
+ '<div style="font-family:\'Unbounded\',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 7 · Многогранники</div>'
+ '</div>'
+ '<div style="font-size:.94rem;line-height:1.55">$5$ платоновых тел: тетраэдр, куб, октаэдр, додекаэдр, икосаэдр. Формула Эйлера: $V-E+F=2$. Двойственные пары: тетраэдр$\\leftrightarrow$тетраэдр, куб$\\leftrightarrow$октаэдр, додекаэдр$\\leftrightarrow$икосаэдр.</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>';
/* Часть Б — анонс 5 боссов */
html += '<div class="card">'
+ '<div class="card-header">'
+ '<div class="card-icon rule">' + ICONS.rule + '</div>'
+ '<div class="card-title">Боссы раздела 3</div>'
+ '<div class="card-num">5</div>'
+ '</div>'
+ '<div class="card-body">'
+ '<p>5 интегрированных задач — каждая опирается на темы § 5, § 6 или § 7. За каждого побеждённого босса: <b>+10 XP, +18% к прогрессу</b>. Победишь всех — ачивка <b>«Мастер сферической геометрии»</b> и <b>+50 XP бонус</b>.</p>'
+ '<p style="font-size:.88rem;color:var(--muted);margin-top:6px">Для расчётов с $\\pi$ используй $\\pi\\approx 3{,}14$. Допуск ответа — $\\pm 0{,}05$ (для больших чисел — $\\pm 0{,}5$).</p>'
+ '</div>'
+ '</div>';
html += '<div id="r3-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="r3-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="r3-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="r3-boss-overall-fill" style="height:100%;width:0%;background:linear-gradient(90deg,#7c3aed,#a78bfa)"></div>'
+ '</div>'
+ '<div id="r3-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/geometry-11-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('p7', null);
box.innerHTML = html;
renderMath(box);
/* === Боссы === */
const BOSSES = [
{
n:1, color:'#2563eb',
title:'Циклоп Сферы',
tag:'§ 5',
q:'Сфера задана уравнением $x^2+y^2+z^2=49$. Найдите радиус $R$.',
ans:7, tol:0.05,
hint:'$R=\\sqrt{49}=7$.'
},
{
n:2, color:'#dc2626',
title:'Минотавр Шара',
tag:'§ 6',
q:'Шар с $R=6$. Найдите площадь поверхности (используй $\\pi\\approx 3{,}14$).',
ans:452.16, tol:0.5,
hint:'$S=4\\pi R^2=4\\cdot 3{,}14\\cdot 36=452{,}16$.'
},
{
n:3, color:'#0891b2',
title:'Гарпия Куба и Шара',
tag:'§ 6 + куб',
q:'Шар вписан в куб со стороной $a=8$. Найдите объём шара (используй $\\pi\\approx 3{,}14$).',
ans:267.95, tol:0.5,
hint:'Радиус вписанного шара: $r=a/2=4$. $V=\\tfrac{4}{3}\\pi r^3=\\tfrac{4}{3}\\cdot 3{,}14\\cdot 64\\approx 267{,}95$.'
},
{
n:4, color:'#7c3aed',
title:'Дракон Многогранников',
tag:'§ 7',
q:'Сколько вершин у икосаэдра?',
ans:12, tol:0.05,
hint:'У икосаэдра $V=12$, $E=30$, $F=20$. Проверка Эйлера: $V-E+F=12-30+20=2$.'
},
{
n:5, color:'#f59e0b',
title:'Мастер Сферической Геометрии',
tag:'синтез § 6 + § 7',
q:'Шар описан около куба со стороной $a=4$. Найдите радиус шара (округлите до сотых).',
ans:3.46, tol:0.05,
hint:'Диагональ куба $d=a\\sqrt{3}$. Радиус описанного шара $R=\\tfrac{a\\sqrt{3}}{2}=\\tfrac{4\\sqrt{3}}{2}=2\\sqrt{3}\\approx 3{,}46$.'
}
];
const cont = document.getElementById('r3-bosses-container');
const STATE_KEY = 'geometry11_ch3_bosses';
const BOSS_STATE = (function(){
try{ const s = localStorage.getItem(STATE_KEY); if(s){ const p = JSON.parse(s); if(Array.isArray(p) && p.length === BOSSES.length) return p; } }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=>{
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"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3"/></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 class="boss-q" 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:140px;text-align:center" step="0.01" 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('r3-boss-overall');
const fill = document.getElementById('r3-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('r3-final-reward');
if(reward && reward.style.display === 'none'){
reward.style.display = 'block';
if(!STATE.achievements.has('r3_done')){
achievement('r3_done','Мастер сферической геометрии');
addXp(50, 'r3-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))';
card.classList.add('glow');
goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.innerHTML = '&#10003; Повержен';
ansInp.disabled = true;
}
goBtn.addEventListener('click', ()=>{
if(BOSS_STATE[idx].defeated) return;
const fb = document.getElementById('boss3-'+b.n+'-fb');
const raw = (ansInp.value||'').replace(',', '.').trim();
const val = parseFloat(raw);
if(!isFinite(val)){ feedback(fb, false, '&#10007; Введи число.'); return; }
if(Math.abs(val - b.ans) <= b.tol){
BOSS_STATE[idx].defeated = true; saveBosses();
feedback(fb, true, '&#10003; Босс '+b.n+' повержен! +10 XP. '+b.hint);
addXp(10, 'boss-r3-'+b.n);
bumpProgress('final3', 18);
goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.innerHTML = '&#10003; Повержен';
ansInp.disabled = true;
card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))';
card.classList.add('glow','pulse');
setTimeout(()=>card.classList.remove('pulse'), 900);
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,#fef3c7)';
fb.style.color = '#92400e';
fb.style.borderLeftColor = 'var(--warn,#f59e0b)';
try{ renderMath(fb); }catch(e){}
});
ansInp.addEventListener('keydown', e=>{ if(e.key === 'Enter') goBtn.click(); });
});
refreshOverall();
}
/* ===== STUB BUILDER — единый для всех параграфов раздела (Phase 0) ===== */
function buildStub(id){