diff --git a/frontend/textbooks/geometry_8_ch2.html b/frontend/textbooks/geometry_8_ch2.html index dc0683b..36f6874 100644 --- a/frontend/textbooks/geometry_8_ch2.html +++ b/frontend/textbooks/geometry_8_ch2.html @@ -376,7 +376,7 @@ const BUILDERS={ p1:()=>buildP1(),p2:()=>buildP2(),p3:()=>buildP3(),p4:()=>buildP4(),p5:()=>buildP5(), p6:()=>buildP6(),p7:()=>buildP7(),p8:()=>buildP8(),p9:()=>buildP9(),p10:()=>buildP10(), p11:()=>buildP11(),p12:()=>buildP12(),p13:()=>buildP13(),p14:()=>buildP14(),p15:()=>buildP15(), - final2:()=>buildFinal2stub(), + final2:()=>buildFinal2(), }; function ensureBuilt(id){ if(BUILT.has(id))return;const fn=BUILDERS[id];if(fn){fn();BUILT.add(id);} } function goTo(id){ @@ -6513,7 +6513,621 @@ function buildP15(){ if(window.renderMathInElement) renderMath(bossBox); })(); } -function buildFinal2stub(){ document.getElementById('final2-body').innerHTML='

Финал главы 2 — Волна 1: боссы и итоги появятся в следующем обновлении.

'+secNav('p15',null); } +function buildFinal2(){ + const box = document.getElementById('final2-body'); + let html = ''; + + /* === ЧАСТЬ 1: Итоговая шпаргалка === */ + html += `
+
+
+ +
+
Итоговая шпаргалка · Вся Глава 2 «Площади»
+
+
+
+ +
+
§1 Квадрат
+
+ aa +
+

$S = a^2$

+

$P = 4a$

+
+
+
+ +
+
§2 Прямоугольник
+
+ ab +
+

$S = a \cdot b$

+

$P = 2(a+b)$

+
+
+
+ +
+
§3 Параллелограмм
+
+ ah +
+

$S = a \cdot h$

+

$h$ — высота

+
+
+
+ +
+
§4 Треугольник
+
+ ha +
+

$S = \\dfrac{1}{2}ah$

+

$a$ — основание

+
+
+
+ +
+
§5 Трапеция
+
+ ba +
+

$S = \\dfrac{(a+b)}{2} h$

+

$a,b$ — основания

+
+
+
+ +
+
§6 Ромб
+
+ d₁d₂ +
+

$S = \\dfrac{d_1 d_2}{2}$

+

$= ah = a^2 \\sin\\alpha$

+
+
+
+ +
+
§7 Прям. треугольник
+
+ ab +
+

$S = \\dfrac{1}{2}ab$

+

$a,b$ — катеты

+
+
+
+ +
+
§8 Высота к гипотенузе
+
+ h_c +
+

$h_c = \\dfrac{ab}{c}$

+

$c$ — гипотенуза

+
+
+
+ +
+
§9 Общая высота
+
+

$\\dfrac{S_1}{S_2} = \\dfrac{a_1}{a_2}$

+

Треугольники с общей высотой

+
+
+ +
+
§10 Медиана
+
+

$S_{\\text{под}} = \\dfrac{S}{2}$ (медиана)

+

$S_{\\text{части}} = \\dfrac{S}{6}$ (центроид)

+

3 медианы → 6 равных

+
+
+ +
+
§11 Теорема Пифагора
+
+ abc +
+

$c^2 = a^2 + b^2$

+

$c$ — гипотенуза

+
+
+
+ +
+
§12 Равносторонний
+
+

$h = \\dfrac{a\\sqrt{3}}{2}$

+

$S = \\dfrac{a^2\\sqrt{3}}{4}$

+
+
+ +
+
§13 Диагональ квадрата
+
+

$d = a\\sqrt{2}$

+

из теор. Пифагора

+
+
+ +
+
§14 Обратная теорема
+
+

$a^2+b^2=c^2$

+

$\\Rightarrow$ угол при $c$ прямой

+
+
+ +
+
§15 Пифагоровы тройки
+
+

(3, 4, 5)

+

(5, 12, 13)

+

(8, 15, 17), (7, 24, 25)

+
+
+ +
+
+
`; + + /* === ЧАСТЬ 2: Карта связей фигур === */ + html += `
+
КАРТА СВЯЗЕЙ
Фигуры и их формулы площади
+
Нажми на фигуру, чтобы увидеть формулу площади и ключевые свойства.
+
+
Нажми на фигуру в схеме выше
+
`; + + /* === ЧАСТЬ 3: 7 боссов === */ + html += `
+
+ 7 БОССОВ ГЛАВЫ 2 +
Интегрированные задачи
+
+
Каждая задача объединяет 2–3 темы главы. +10 XP за каждого побеждённого босса. Победи всех семерых — получишь +50 XP и достижение «Мастер площадей»!
+
+
`; + + /* === ЧАСТЬ 4: Финальная плашка === */ + html += ``; + + html += `
+ +
`; + + html += secNav('p15', null); + box.innerHTML = html; + + /* === JS: Карта связей SVG === */ + (function(){ + const W = 620, H = 340; + const nodes = [ + { id:'area', x:310, y:28, rx:58, label:'Площадь', + props:'Площадь — мера части плоскости, занятой фигурой. Выражается в кв. единицах.' }, + { id:'rect', x:100, y:120, rx:54, label:'Прямоуг. фигуры', + props:'Квадрат: $S=a^2$. Прямоугольник: $S=ab$. Прямоугольный треугольник: $S=\\frac{1}{2}ab$ (катеты).' }, + { id:'para', x:310, y:120, rx:56, label:'Параллелограммы', + props:'Параллелограмм: $S=ah$. Ромб: $S=\\frac{d_1 d_2}{2}$. Прямоугольник: $S=ab$. Квадрат: $S=a^2$.' }, + { id:'tri', x:510, y:120, rx:48, label:'Треугольники', + props:'Произвольный: $S=\\frac{1}{2}ah$. Прямоугольный: $S=\\frac{1}{2}ab$. Равносторонний: $S=\\frac{a^2\\sqrt{3}}{4}$.' }, + { id:'sq', x:60, y:230, rx:40, label:'Квадрат', + props:'$S=a^2$, $P=4a$, диагональ $d=a\\sqrt{2}$. Частный случай прямоугольника и ромба.' }, + { id:'recta', x:160, y:230, rx:44, label:'Прямоугольник', + props:'$S=ab$, $P=2(a+b)$, $d=\\sqrt{a^2+b^2}$.' }, + { id:'rhomb', x:280, y:230, rx:42, label:'Ромб', + props:'$S=\\frac{d_1 d_2}{2}=ah=a^2\\sin\\alpha$. Диагонали перпендикулярны.' }, + { id:'trap', x:400, y:230, rx:42, label:'Трапеция', + props:'$S=\\frac{(a+b)}{2}h$. Средняя линия $m=\\frac{a+b}{2}$.' }, + { id:'eqtri', x:520, y:230, rx:44, label:'Равносторонний', + props:'$h=\\frac{a\\sqrt{3}}{2}$, $S=\\frac{a^2\\sqrt{3}}{4}$. Все углы $60°$.' }, + { id:'pytri', x:560, y:310, rx:44, label:'Прям. треугольник', + props:'$S=\\frac{1}{2}ab$ (катеты). Теорема Пифагора: $c^2=a^2+b^2$. Высота: $h_c=\\frac{ab}{c}$.' }, + ]; + const edges = [ + ['area','rect'],['area','para'],['area','tri'], + ['rect','sq'],['rect','recta'], + ['para','sq'],['para','recta'],['para','rhomb'], + ['tri','eqtri'],['tri','pytri'],['para','trap'], + ]; + let sel = null; + function draw(selId){ + const colors = { area:'#059669', rect:'#0891b2', para:'#8b5cf6', tri:'#d97706', sq:'#14b8a6', recta:'#2563eb', rhomb:'#ec4899', trap:'#f97316', eqtri:'#e11d48', pytri:'#16a34a' }; + let s = ``; + s += ``; + edges.forEach(([a,b])=>{ + const na=nodes.find(n=>n.id===a), nb=nodes.find(n=>n.id===b); + if(!na||!nb) return; + const dx=nb.x-na.x, dy=nb.y-na.y, len=Math.sqrt(dx*dx+dy*dy); + if(len<1) return; + const sy_r=na.rx*0.52; + const sx=na.x+dx/len*na.rx, sy2=na.y+dy/len*sy_r; + const ex=nb.x-dx/len*(nb.rx+7), ey=nb.y-dy/len*(nb.rx*0.52+7); + const isAct = selId===a||selId===b; + s += ``; + }); + nodes.forEach(n=>{ + const isS = selId===n.id; + const col = colors[n.id] || '#059669'; + const ry = n.rx * 0.52; + s += ``; + const words = n.label.split(' '); + const line1 = words.slice(0,2).join(' '), line2 = words.slice(2).join(' '); + const tc = isS ? '#fff' : col; + if(line2){ + s += `${line1}`; + s += `${line2}`; + } else { + s += `${line1}`; + } + }); + s += ''; + document.getElementById('final2-hier-svg').innerHTML = s; + document.getElementById('final2-hier-svg').querySelector('svg').addEventListener('click', function(e){ + const el = e.target.closest('[data-nid]'); + if(!el) return; + const nid = el.dataset.nid; + sel = (sel===nid) ? null : nid; + const nd = nodes.find(n=>n.id===nid); + if(sel && nd){ document.getElementById('final2-hier-info').innerHTML = '' + nd.label + ': ' + nd.props; renderMath(document.getElementById('final2-hier-info')); } + else document.getElementById('final2-hier-info').textContent = 'Нажми на фигуру в схеме выше'; + draw(sel); + }); + } + draw(null); + })(); + + /* === JS: 7 боссов === */ + (function(){ + const bosses = [ + { + n: 1, + title: 'Прямоугольный треугольник: Пифагор + высота', + color: '#059669', + svg: ` + + + + + + + + + + + + + + + + A + B + C + H + + a=9 + b=12 + h_c + `, + cond: 'В прямоугольном треугольнике $ABC$ с прямым углом $A$ катеты $a = AC = 9$ и $b = AB = 12$.', + parts: [ + { label: 'Найди гипотенузу $c = BC$.', ans: 15, hint: '$c=\\sqrt{9^2+12^2}=\\sqrt{81+144}=\\sqrt{225}=15$' }, + { label: 'Найди высоту $h_c$ к гипотенузе (десятичный ответ допустим).', ans: 7.2, tol: 0.05, hint: '$h_c=\\dfrac{ab}{c}=\\dfrac{9\\cdot12}{15}=\\dfrac{108}{15}=7.2$' }, + { label: 'Найди площадь треугольника $ABC$.', ans: 54, hint: '$S=\\dfrac{1}{2}\\cdot9\\cdot12=54$' }, + ], + }, + { + n: 2, + title: 'Параллелограмм через угол', + color: '#8b5cf6', + svg: ` + + + + + + + + 30° + + + + + + A + B + C + D + + 14 см + 8 см + h + `, + cond: 'В параллелограмме $ABCD$ сторона $AB = 14$ см, смежная сторона $AD = 8$ см, угол при вершине $A$ равен $30°$.', + parts: [ + { label: 'Найди высоту $h$ параллелограмма ($h = AD \\cdot \\sin 30°$, в сантиметрах).', ans: 4, hint: '$h = AD \\cdot \\sin 30° = 8 \\cdot 0.5 = 4$ см' }, + { label: 'Найди площадь параллелограмма $S$ (кв. см).', ans: 56, hint: '$S = AB \\cdot h = 14 \\cdot 4 = 56$ кв. см' }, + ], + }, + { + n: 3, + title: 'Трапеция и средняя линия', + color: '#f97316', + svg: ` + + + + + + + + + + M + N + + + + + + A + B + C + D + + a=18 + b=12 + h=5 + m=? + `, + cond: 'В трапеции основания $a = 18$ см и $b = 12$ см, высота $h = 5$ см.', + parts: [ + { label: 'Найди среднюю линию $m$ трапеции (см).', ans: 15, hint: '$m = \\dfrac{a+b}{2} = \\dfrac{18+12}{2} = 15$ см' }, + { label: 'Найди площадь трапеции $S$ (кв. см).', ans: 75, hint: '$S = \\dfrac{(a+b)}{2} \\cdot h = 15 \\cdot 5 = 75$ кв. см' }, + ], + }, + { + n: 4, + title: 'Ромб: диагонали, сторона, площадь', + color: '#ec4899', + svg: ` + + + + + + + + + + + + + A + B + C + D + + d₁=16 + d₂=12 + `, + cond: 'В ромбе $ABCD$ диагонали $d_1 = 16$ см и $d_2 = 12$ см.', + parts: [ + { label: 'Найди площадь ромба $S$ (кв. см).', ans: 96, hint: '$S = \\dfrac{d_1 d_2}{2} = \\dfrac{16 \\cdot 12}{2} = 96$ кв. см' }, + { label: 'Найди сторону ромба $a$ (полудиагонали: $8$ и $6$, теорема Пифагора).', ans: 10, hint: '$a = \\sqrt{8^2 + 6^2} = \\sqrt{64+36} = \\sqrt{100} = 10$ см' }, + { label: 'Найди периметр ромба $P$ (см).', ans: 40, hint: '$P = 4a = 4 \\cdot 10 = 40$ см' }, + ], + }, + { + n: 5, + title: 'Медиана и центроид', + color: '#2563eb', + svg: ` + + + + + + + + + G + + + + + + + + + A + B + C + S=36 + `, + cond: 'Площадь треугольника $ABC = 36$ кв. см. Точка $G$ — центроид (пересечение медиан).', + parts: [ + { label: 'Найди площадь треугольника, образованного центроидом $G$ и двумя вершинами (например, $\\triangle ABG$).', ans: 12, hint: 'Медиана делит треугольник на 2 равные части: $S/2=18$. Все 6 малых треугольников равны: $S_6 = 36/6 = 12$ кв. см' }, + { label: 'Одна медиана делит треугольник на 2 треугольника. Какова площадь каждого из них?', ans: 18, hint: 'Медиана делит треугольник на 2 равновеликих: $S/2 = 36/2 = 18$ кв. см' }, + ], + }, + { + n: 6, + title: 'Равносторонний треугольник и центроид', + color: '#e11d48', + svg: ` + + + + + + h=? + + + G + + + + + + + A + B + C + a=10 + `, + cond: 'В равностороннем треугольнике $ABC$ сторона $a = 10$ см. Точка $G$ — центроид.', + parts: [ + { label: 'Найди высоту $h$ равностороннего треугольника (введи значение, умноженное на 10, как целое: $h \\cdot 10 = ?$)', ans: 87, hint: '$h = \\dfrac{10\\sqrt{3}}{2} \\approx \\dfrac{10 \\cdot 1.732}{2} = 8.66$, умноженное на 10 = 86.6 \\approx 87', tol: 1 }, + { label: 'Найди площадь треугольника (введи значение, умноженное на 10, как целое: $S \\cdot 10 = ?$)', ans: 433, hint: '$S = \\dfrac{a^2\\sqrt{3}}{4} = \\dfrac{100\\sqrt{3}}{4} \\approx 43.3$, умноженное на 10 = 433', tol: 2 }, + { label: 'Найди расстояние от центроида $G$ до основания $BC$ (центроид делит высоту в отношении $2:1$, введи значение в целых мм: расстояние $\\cdot 10$)', ans: 29, hint: 'Расстояние = $h/3 = 8.66/3 \\approx 2.89$, умноженное на 10 = 28.9 \\approx 29', tol: 1 }, + ], + }, + { + n: 7, + title: 'Пифагоровы тройки в задаче', + color: '#7c3aed', + svg: ` + + + + + + + + A + B + C + + a=? + b=? + c=13 + + P=30 + `, + cond: 'Прямоугольный треугольник имеет периметр $P = 30$ см и гипотенузу $c = 13$ см. Используй пифагорову тройку $(5, 12, 13)$.', + parts: [ + { label: 'Найди сумму катетов $a + b$ (см).', ans: 17, hint: '$a + b = P - c = 30 - 13 = 17$ см' }, + { label: 'Используя тройку $(5, 12, 13)$: найди меньший катет $a$ (см).', ans: 5, hint: 'Тройка $(5, 12, 13)$: катеты $5$ и $12$, $5+12=17$. Меньший катет $a = 5$ см' }, + { label: 'Найди площадь треугольника $S$ (кв. см).', ans: 30, hint: '$S = \\dfrac{1}{2} \\cdot 5 \\cdot 12 = 30$ кв. см' }, + ], + }, + ]; + + window.final2BossSolved = new Set(); + const bossBox = document.getElementById('final2-bosses'); + bossBox.innerHTML = bosses.map(b => { + const partsHtml = b.parts.map((p,pi) => { + const labelText = p._label_fix || p.label; + return `
+
${labelText}
+
+ + + +
+ +
`; + }).join(''); + + const svgHtml = b.svg ? `
${b.svg}
` : ''; + + return `
+
+ БОСС ${b.n} + ${b.title} + +
+
${b.cond}
+ ${svgHtml} + ${partsHtml} +
`; + }).join(''); + + function checkPart(bi, pi){ + const boss = bosses[bi]; + const part = boss.parts[pi]; + const inp = bossBox.querySelector(`.final2-boss-inp[data-b="${bi}"][data-p="${pi}"]`); + const fb = bossBox.querySelector(`.final2-boss-fb[data-b="${bi}"][data-p="${pi}"]`); + const ok = bossBox.querySelector(`.final2-boss-ok[data-b="${bi}"][data-p="${pi}"]`); + if(!inp) return; + const val = parseFloat(inp.value); + const useExact = part._override && part._ans_exact !== undefined; + const ansCheck = useExact ? part._ans_exact : part.ans; + const tolCheck = useExact ? part._tol_exact : (part.tol !== undefined ? part.tol : 0); + const hintText = useExact ? part._hint_fix : part.hint; + if(Math.abs(val - ansCheck) <= tolCheck){ + feedback(fb, true, 'Верно! ' + (hintText ? '
' + hintText + '' : '')); + inp.disabled = true; + const btn = bossBox.querySelector(`.final2-boss-check[data-b="${bi}"][data-p="${pi}"]`); + if(btn) btn.disabled = true; + if(ok) ok.style.display = 'inline'; + const allDone = boss.parts.every((_,pj) => { + const el = bossBox.querySelector(`.final2-boss-inp[data-b="${bi}"][data-p="${pj}"]`); + return el && el.disabled; + }); + if(allDone && !window.final2BossSolved.has(bi)){ + window.final2BossSolved.add(bi); + addXp(10, 'final2-boss-' + (bi+1)); + const xpBadge = document.getElementById('final2-boss-xp-' + bi); + if(xpBadge) xpBadge.style.display = 'inline'; + bumpProgress('final2', 8); + if(window.final2BossSolved.size === bosses.length){ + setTimeout(()=>{ + confetti(); + if(!STATE.achievements.has('final2-master')){ + STATE.achievements.set('final2-master', 'Мастер площадей Главы 2'); + saveProgress(); + const pop = document.getElementById('ach-popup'); + if(pop){ document.getElementById('ach-text').textContent = 'Мастер площадей Главы 2!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'), 4000); } + } + addXp(50, 'final2-all-bosses'); + bumpProgress('final2', 20); + const fin = document.getElementById('final2-finish'); + if(fin) fin.style.display = 'block'; + }, 500); + } + } + } else { + feedback(fb, false, 'Неверно. Подсказка: ' + (hintText || part.hint)); + } + } + + bossBox.querySelectorAll('.final2-boss-check').forEach(btn=>{ + btn.addEventListener('click', ()=>{ checkPart(+btn.dataset.b, +btn.dataset.p); }); + }); + bossBox.querySelectorAll('.final2-boss-inp').forEach(inp=>{ + inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ const btn=bossBox.querySelector(`.final2-boss-check[data-b="${inp.dataset.b}"][data-p="${inp.dataset.p}"]`); if(btn)btn.click(); } }); + }); + })(); + + renderMath(box); +}