diff --git a/frontend/textbooks/geometry_11_ch1.html b/frontend/textbooks/geometry_11_ch1.html
index 03f367a..4ad49eb 100644
--- a/frontend/textbooks/geometry_11_ch1.html
+++ b/frontend/textbooks/geometry_11_ch1.html
@@ -306,7 +306,8 @@ const ACH_LABELS = {
p1_done:"Призма освоено!",
p2_done:"Цилиндр освоено!",
start:"Начало раздела 1!",
- ch1_done:"Раздел 1 пройден!"
+ ch1_done:"Раздел 1 пройден!",
+ r1_done:"Мастер призмы и цилиндра"
};
function loadProgress(){
@@ -392,7 +393,7 @@ function buildParaSelector(){
}
const BUILT=new Set();
-const BUILDERS = { p1:()=>buildP1(), p2:()=>buildP2(), final1:()=>buildStub('final1') };
+const BUILDERS = { p1:()=>buildP1(), p2:()=>buildP2(), final1:()=>buildFinal1() };
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);
@@ -409,7 +410,7 @@ function goTo(id){
const SIDEBARS = {
p1:{title:"Шпаргалка § 1", rows:[["Тема","Призма"],["Прямая","$S_{бок}=P_{осн}\\\\cdot h$"],["Наклонная","$S_{бок}=P_{пер}\\\\cdot l$"],["Объём","$V=S_{осн}\\\\cdot h$"],["Диагональ пар.","$d=\\\\sqrt{a^2+b^2+c^2}$"]]},
p2:{title:"Шпаргалка § 2", rows:[["Тема", "Цилиндр"],["$S_{осн}$","$\\\\pi R^2$"],["$S_{бок}$","$2\\\\pi Rh$"],["$S_{полн}$","$2\\\\pi R(R+h)$"],["$V$","$\\\\pi R^2 h$"],["Развёртка","прямоуг. $2\\\\pi R \\\\times h$"],["Осевое сеч.","прямоуг. $2R \\\\times h$"],["Наклон. сеч.","эллипс, $a=R/\\\\cos\\\\alpha$, $b=R$"]]},
- final1:{title:"Финал раздела 1", rows:[["§ 1–§ 2","теория раздела 1"],["Награда","+50 XP"]]}
+ final1:{title:"Финал раздела 1", rows:[["§ 1","Призма"],["§ 2","Цилиндр"],["Боссы","5 интегрированных"],["Награда","+50 XP + ачивка"]]}
};
const TIPS=[
@@ -1406,6 +1407,213 @@ function buildP2(){
wireReadBtn('p2');
}
+/* ===== ФИНАЛ РАЗДЕЛА 1 — Шпаргалка + 5 боссов + ачивка ===== */
+function buildFinal1(){
+ const box = document.getElementById('final1-body');
+ if(!box) return;
+ let html = '';
+
+ /* Часть А — Шпаргалка раздела (2 mini-карточки по числу § в разделе) */
+ html += '
'
+ + ''
+ + '
'
+ + '
Ключевые формулы обоих параграфов раздела в одном месте — пробеги глазами перед битвой с боссами.
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
§ 1 · Призма
'
+ + '
'
+ + '
$V = S_{осн}\\cdot h$ — для любой призмы. Для прямой: $S_{бок}=P_{осн}\\cdot h$. Прямоугольный параллелепипед: $d^2=a^2+b^2+c^2$. Виды: прямая, правильная, наклонная, параллелепипед, куб.
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
§ 2 · Цилиндр
'
+ + '
'
+ + '
$V=\\pi R^2 h$, $S_{бок}=2\\pi Rh$, $S_{полн}=2\\pi R(R+h)$. Сечения: круг ($\\perp$ оси), прямоугольник (через ось или $\\parallel$ оси), эллипс (наклонная плоскость).
'
+ + '
'
+ + '
'
+ + '
'
+ + '
';
+
+ /* Часть Б — анонс 5 боссов */
+ html += ''
+ + ''
+ + '
'
+ + '
5 интегрированных задач — каждая комбинирует темы § 1 и § 2. За каждого побеждённого босса: +10 XP, +18% к прогрессу . Победишь всех — ачивка «Мастер призмы и цилиндра» и +50 XP бонус .
'
+ + '
Для расчётов с $\\pi$ используй $\\pi\\approx 3{,}14$. Допуск ответа — $\\pm 0{,}05$ (для боссов 2 и 5 указан в условии).
'
+ + '
'
+ + '
';
+
+ html += '
';
+
+ /* Прогресс-итог + ачивка */
+ html += ''
+ + '
Прогресс по боссам
'
+ + '
0 / 5 боссов побеждено
'
+ + '
'
+ + '
'
+ + '
Мастер призмы и цилиндра
'
+ + '
Раздел 1 пройден! Все 5 боссов повержены. +50 XP бонус.
'
+ + '
Дальше: Раздел 2 '
+ + '
'
+ + '
';
+
+ html += secNav('p2', null);
+
+ box.innerHTML = html;
+ renderMath(box);
+
+ /* === Боссы === */
+ const BOSSES = [
+ {
+ n:1, color:'#0891b2',
+ title:'Циклоп Параллелепипеда',
+ tag:'§ 1',
+ q:'В прямоугольном параллелепипеде $a=3$, $b=4$, $c=12$. Найдите длину главной диагонали.',
+ ans:13, tol:0.05,
+ hint:'$d=\\sqrt{a^2+b^2+c^2}=\\sqrt{9+16+144}=\\sqrt{169}=13$.'
+ },
+ {
+ n:2, color:'#10b981',
+ title:'Минотавр Куба',
+ tag:'§ 1',
+ q:'Куб со стороной $4$. Найдите длину диагонали куба (допуск $\\pm 0{,}05$).',
+ ans:6.93, tol:0.05,
+ hint:'Диагональ куба: $d=a\\sqrt{3}=4\\sqrt{3}\\approx 6{,}928$.'
+ },
+ {
+ n:3, color:'#7c3aed',
+ title:'Гарпия Цилиндра',
+ tag:'§ 2',
+ q:'Цилиндр с $R=5$, $h=10$. Найдите объём (используйте $\\pi=3{,}14$).',
+ ans:785, tol:0.05,
+ hint:'$V=\\pi R^2 h = 3{,}14\\cdot 25\\cdot 10 = 785$.'
+ },
+ {
+ n:4, color:'#dc2626',
+ title:'Дракон Сечений',
+ tag:'§ 2 + § 1',
+ q:'Цилиндр с $R=6$ пересечён плоскостью под углом $60°$ к плоскости основания (плоскость пересекает обе окружности оснований). Найдите большую полуось эллипса в сечении.',
+ ans:12, tol:0.05,
+ hint:'При наклоне на угол $\\alpha$ малая полуось эллипса равна $R$, большая — $a=R/\\cos\\alpha = 6/\\cos 60° = 6/0{,}5 = 12$.'
+ },
+ {
+ n:5, color:'#f59e0b',
+ title:'Мастер 3D-форм',
+ tag:'синтез § 1 + § 2',
+ q:'В цилиндр с $R=6$ и $h=8$ вписана правильная шестиугольная призма (вершины основания лежат на окружности). Найдите объём призмы (допуск $\\pm 0{,}1$).',
+ ans:748.25, tol:0.1,
+ hint:'Сторона правильного 6-угольника, вписанного в окружность радиуса $R$, равна $R=6$. Его площадь: $S=\\tfrac{3\\sqrt{3}}{2}\\cdot 36 = 54\\sqrt{3}$. Объём: $V=S\\cdot h=54\\sqrt{3}\\cdot 8 = 432\\sqrt{3}\\approx 748{,}25$.'
+ }
+ ];
+
+ const cont = document.getElementById('r1-bosses-container');
+ const STATE_KEY = 'geometry11_ch1_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 ''
+ + '
'
+ + '
'
+ + '
Босс '+b.n+': '+b.title+'
'
+ + '
'+b.tag+'
'
+ + '
'
+ + '
'+b.q+'
'
+ + '
'
+ + 'ответ = '
+ + ' '
+ + 'Атаковать '
+ + 'Подсказка '
+ + '
'
+ + '
'
+ + '
';
+ }).join('');
+ renderMath(cont);
+
+ function refreshOverall(){
+ const won = BOSS_STATE.filter(s => s.defeated).length;
+ const txt = document.getElementById('r1-boss-overall');
+ const fill = document.getElementById('r1-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('r1-final-reward');
+ if(reward && reward.style.display === 'none'){
+ reward.style.display = 'block';
+ if(!STATE.achievements.has('r1_done')){
+ achievement('r1_done','Мастер призмы и цилиндра');
+ addXp(50, 'r1-bonus');
+ bumpProgress('final1', 30);
+ if(window.confetti){ try{ confetti(); }catch(e){} }
+ }
+ }
+ }
+ }
+
+ BOSSES.forEach((b, idx)=>{
+ const card = document.getElementById('boss1-'+b.n+'-card');
+ const goBtn = document.getElementById('boss1-'+b.n+'-go');
+ const hintBtn= document.getElementById('boss1-'+b.n+'-hint');
+ const ansInp = document.getElementById('boss1-'+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 = '✓ Повержен';
+ ansInp.disabled = true;
+ }
+ goBtn.addEventListener('click', ()=>{
+ if(BOSS_STATE[idx].defeated) return;
+ const fb = document.getElementById('boss1-'+b.n+'-fb');
+ const raw = (ansInp.value||'').replace(',', '.').trim();
+ const val = parseFloat(raw);
+ if(!isFinite(val)){ feedback(fb, false, '✗ Введи число.'); return; }
+ if(Math.abs(val - b.ans) <= b.tol){
+ BOSS_STATE[idx].defeated = true; saveBosses();
+ feedback(fb, true, '✓ Босс '+b.n+' повержен! +10 XP. '+b.hint);
+ addXp(10, 'boss-r1-'+b.n);
+ bumpProgress('final1', 18);
+ goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.innerHTML = '✓ Повержен';
+ 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, '✗ Промах. Попробуй ещё. Подсказка доступна.');
+ }
+ });
+ hintBtn.addEventListener('click', ()=>{
+ const fb = document.getElementById('boss1-'+b.n+'-fb');
+ fb.className = 'feedback ok';
+ fb.innerHTML = 'Подсказка: '+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){