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 += '
' + + '
' + + '
' + ICONS.theory + '
' + + '
Шпаргалка раздела 1
' + + '
Итог
' + + '
' + + '
' + + '

Ключевые формулы обоих параграфов раздела в одном месте — пробеги глазами перед битвой с боссами.

' + + '
' + + '
' + + '
' + + '' + + '
§ 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 += '
' + + '
' + + '
' + ICONS.rule + '
' + + '
Боссы раздела 1
' + + '
5
' + + '
' + + '
' + + '

5 интегрированных задач — каждая комбинирует темы § 1 и § 2. За каждого побеждённого босса: +10 XP, +18% к прогрессу. Победишь всех — ачивка «Мастер призмы и цилиндра» и +50 XP бонус.

' + + '

Для расчётов с $\\pi$ используй $\\pi\\approx 3{,}14$. Допуск ответа — $\\pm 0{,}05$ (для боссов 2 и 5 указан в условии).

' + + '
' + + '
'; + + html += '
'; + + /* Прогресс-итог + ачивка */ + html += '
' + + '
Прогресс по боссам
' + + '
0 / 5 боссов побеждено
' + + '
' + + '
' + + '
' + + '' + + '
'; + + 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){