diff --git a/frontend/textbooks/geometry_11_ch4.html b/frontend/textbooks/geometry_11_ch4.html
index 111e503..978a60a 100644
--- a/frontend/textbooks/geometry_11_ch4.html
+++ b/frontend/textbooks/geometry_11_ch4.html
@@ -400,7 +400,7 @@ function buildParaSelector(){
}
const BUILT=new Set();
-const BUILDERS = { p8:()=>buildStub('p8'), p9:()=>buildStub('p9'), p10:()=>buildStub('p10'), p11:()=>buildStub('p11'), final4:()=>buildStub('final4') };
+const BUILDERS = { p8:()=>buildP8(), p9:()=>buildP9(), p10:()=>buildStub('p10'), p11:()=>buildStub('p11'), final4:()=>buildStub('final4') };
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);
@@ -415,16 +415,16 @@ function goTo(id){
}
const SIDEBARS = {
- p8:{title:"Шпаргалка § 8", rows:[["Тема", "Геометрические фигуры и их свойства"],["Формула","планиметрия"]]},
- p9:{title:"Шпаргалка § 9", rows:[["Тема", "Геометрические величины"],["Формула","площади, объёмы"]]},
+ p8:{title:"Шпаргалка § 8", rows:[["Сумма углов $\\triangle$","$180°$"],["Пифагор","$a^2+b^2=c^2$"],["Синусов","$\\dfrac{a}{\\sin A}=2R$"],["Косинусов","$c^2=a^2+b^2-2ab\\cos C$"],["Длина окр.","$C=2\\pi R$"],["$S$ круга","$\\pi R^2$"]]},
+ p9:{title:"Шпаргалка § 9", rows:[["$S_\\triangle$","$\\frac{1}{2}ab\\sin C$"],["Герон","$\\sqrt{p(p-a)(p-b)(p-c)}$"],["$S$ трап.","$\\frac{a+b}{2}h$"],["$V$ призмы","$S_{осн}h$"],["$V$ пир.","$\\frac{1}{3}S_{осн}h$"],["$V$ шара","$\\frac{4}{3}\\pi R^3$"]]},
p10:{title:"Шпаргалка § 10", rows:[["Тема", "Координаты и векторы"],["Формула","3D: $\\\\vec{a}=(x;y;z)$"]]},
p11:{title:"Шпаргалка § 11", rows:[["Тема", "Геометрические построения"],["Формула","циркуль и линейка"]]},
final4:{title:"Финал раздела 4", rows:[["§ 8–§ 11","теория раздела 4"],["Награда","+50 XP"]]}
};
const TIPS=[
- {sec:'p8',html:"§ 8 «Геометрические фигуры и их свойства» — содержание в разработке. планиметрия"},
- {sec:'p9',html:"§ 9 «Геометрические величины» — содержание в разработке. площади, объёмы"},
+ {sec:'p8',html:"§ 8: обзор планиметрии. Теоремы Пифагора, синусов, косинусов; виды треугольников и четырёхугольников; окружность."},
+ {sec:'p9',html:"§ 9: площади плоских фигур и объёмы тел. Формулы Герона, $S=\\frac{1}{2}ab\\sin C$, $V=\\frac{1}{3}S_{осн}h$, шар."},
{sec:'p10',html:"§ 10 «Координаты и векторы» — содержание в разработке. 3D: $\\\\\\\\vec{a}=(x;y;z)$"},
{sec:'p11',html:"§ 11 «Геометрические построения» — содержание в разработке. циркуль и линейка"},
{sec:'final4',html:"Финал раздела 4 — интегрированные задачи по разделу."}
@@ -708,6 +708,489 @@ function buildStub(id){
wireReadBtn(id);
}
+/* ===== §8 «Геометрические фигуры и их свойства» (повторение планиметрии) ===== */
+
+function buildP8(){
+ const box = document.getElementById('p8-body');
+ if(!box) return;
+ let html = '';
+
+ /* === ТЕОРИЯ === */
+
+ html += makeCard('theory', 'Треугольники и четырёхугольники', '§ 8.1',
+ '
Треугольник. Сумма углов любого треугольника равна $180°$. Виды по углам: остроугольный, прямоугольный, тупоугольный . По сторонам: разносторонний, равнобедренный, равносторонний .
'
+ + 'Замечательные точки треугольника: центроид $G$ (точка пересечения медиан, делит каждую медиану $2{:}1$ от вершины), ортоцентр $H$ (пересечение высот), центр описанной окружности $O$ (пересечение серединных перпендикуляров), центр вписанной окружности $I$ (пересечение биссектрис).
'
+ + 'Прямоугольный треугольник: теорема Пифагора $a^2 + b^2 = c^2$. Тригонометрия острого угла $A$:
'
+ + '$\\sin A = \\dfrac{a}{c},\\quad \\cos A = \\dfrac{b}{c},\\quad \\tan A = \\dfrac{a}{b}$
'
+ + 'Теорема синусов (для любого треугольника):
'
+ + '$\\dfrac{a}{\\sin A} = \\dfrac{b}{\\sin B} = \\dfrac{c}{\\sin C} = 2R$
'
+ + 'Теорема косинусов:
'
+ + '$c^2 = a^2 + b^2 - 2ab\\cos C$
'
+ + 'Четырёхугольники. Сумма углов выпуклого четырёхугольника равна $360°$. Иерархия: параллелограмм $\\supset$ прямоугольник , ромб $\\supset$ квадрат . У параллелограмма противоположные стороны равны и параллельны, диагонали точкой пересечения делятся пополам.
'
+ + 'Трапеция: две параллельные стороны (основания) разной длины. Средняя линия $m = \\dfrac{a+b}{2}$.
');
+
+ html += makeCard('example', 'Окружность и её свойства', '§ 8.2',
+ 'Окружность. Длина окружности: $C = 2\\pi R$. Длина дуги в $\\alpha$ градусов: $\\ell = \\dfrac{\\pi R \\alpha}{180°}$.
'
+ + 'Круг: площадь $S = \\pi R^2$. Площадь сектора с центральным углом $\\alpha$: $S_{сект} = \\dfrac{\\pi R^2 \\alpha}{360°}$.
'
+ + 'Вписанный угол. Угол, вершина которого лежит на окружности, а стороны — хорды, равен половине центрального угла, опирающегося на ту же дугу. Все вписанные углы, опирающиеся на один диаметр, прямые (теорема Фалеса).
'
+ + 'Касательная. Прямая, имеющая с окружностью ровно одну общую точку. Касательная перпендикулярна радиусу, проведённому в точку касания. Отрезки касательных из одной внешней точки равны.
'
+ + 'Вписанная и описанная окружности треугольника:
'
+ + '$r = \\dfrac{S}{p},\\qquad R = \\dfrac{abc}{4S}$
'
+ + 'где $p = \\dfrac{a+b+c}{2}$ — полупериметр, $S$ — площадь треугольника.
'
+ + 'Пример: треугольник $a=3$, $b=4$, $c=5$ '
+ + '
Прямоугольный (так как $3^2+4^2=5^2$). $S = \\frac{1}{2}\\cdot 3 \\cdot 4 = 6$. $p = 6$.
'
+ + '
$r = S/p = 6/6 = 1$. $R = (3\\cdot 4\\cdot 5)/(4\\cdot 6) = 60/24 = 2{,}5$ (= $c/2$ — гипотенуза диаметр).
'
+ + '
');
+
+ /* === ИНТЕРАКТИВ 1 — Квикфайр === */
+ html += ''
+ + ''
+ + '
Для каждой ситуации выбери теорему: Пифагор, синусов или косинусов. После 8 верных — +10 XP.
'
+ + '
'
+ + '
Верно: 0 / 8
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 2 — DnD сортер === */
+ html += ''
+ + ''
+ + '
Перетащи описание в нужный ящик. После всех верных — +15 XP.
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
Проверить Сброс
'
+ + '
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 3 — Тренажёр повторения === */
+ html += ''
+ + ''
+ + '
Введи числовой ответ. Допуск $\\pm 0{,}05$. Для $\\pi$ используй $3{,}14$.
'
+ + '
'
+ + '
Решено: 0 / 5
'
+ + '
';
+
+ html += secNavFor('p8');
+ html += readButton('p8');
+
+ box.innerHTML = html;
+ renderMath(box);
+
+ /* IV1 — Квикфайр */
+ (function(){
+ const tasks = [
+ { q:'В прямоугольном треугольнике даны оба катета . Найти гипотенузу.', a:'pyth' },
+ { q:'В произвольном треугольнике даны две стороны и угол между ними . Найти третью сторону.', a:'cos' },
+ { q:'Дана сторона и противолежащий ей угол . Найти радиус описанной окружности.', a:'sin' },
+ { q:'В треугольнике даны все три стороны . Найти один из углов.', a:'cos' },
+ { q:'Даны два угла и сторона . Найти другую сторону.', a:'sin' },
+ { q:'В прямоугольном треугольнике даны катет и гипотенуза . Найти второй катет.', a:'pyth' },
+ { q:'Даны две стороны и угол между ними . Найти третью сторону.', a:'cos' },
+ { q:'Сторона и противолежащий угол в произвольном треугольнике. Найти радиус $R$.', a:'sin' }
+ ];
+ const LABELS = {pyth:'Пифагор', sin:'Синусов', cos:'Косинусов'};
+ const area = document.getElementById('p8-iv1-area');
+ const scoreEl = document.getElementById('p8-iv1-score');
+ const solved = new Set();
+ let xpGiven = false;
+
+ area.innerHTML = tasks.map(function(t, i){
+ return ''
+ + '
Вопрос '+(i+1)+'. '+t.q+'
'
+ + '
'
+ + 'Пифагор '
+ + 'Синусов '
+ + 'Косинусов '
+ + '
'
+ + '
'
+ + '
';
+ }).join('');
+ renderMath(area);
+
+ area.querySelectorAll('button[data-i]').forEach(function(b){
+ b.addEventListener('click', function(){
+ const i = +b.dataset.i, v = b.dataset.v, t = tasks[i];
+ const fb = document.getElementById('p8-iv1-fb-'+i);
+ if(v === t.a){
+ feedback(fb, true, '✓ Верно — теорема '+LABELS[t.a]+'!');
+ if(!solved.has(i)){
+ solved.add(i);
+ scoreEl.textContent = solved.size;
+ if(solved.size === tasks.length && !xpGiven){
+ xpGiven = true;
+ addXp(10, 'p8-iv1');
+ bumpProgress('p8', 20);
+ }
+ }
+ } else {
+ feedback(fb, false, '✗ Неверно. Подумай: что дано — прямоуг. $\\triangle$? Угол между двумя сторонами? Сторона + противолежащий угол?');
+ }
+ });
+ });
+ })();
+
+ /* IV2 — DnD сортер */
+ (function(){
+ const items = [
+ { id:'q1', html:'4 стороны равны, все углы прямые', cat:'square' },
+ { id:'q2', html:'4 стороны равны, углы не обязательно прямые', cat:'rhomb' },
+ { id:'q3', html:'Противоположные стороны равны и параллельны', cat:'rect' },
+ { id:'q4', html:'2 параллельные стороны (основания) разной длины', cat:'trap' },
+ { id:'q5', html:'4 угла по $90°$, противоположные стороны равны', cat:'rect' },
+ { id:'q6', html:'Все 4 угла $90°$ и все стороны равны', cat:'square' }
+ ];
+ const sorter = setupSorter({
+ poolId:'p8-iv2-pool',
+ scopeSelector:'#p8-iv2',
+ items: items,
+ cats: ['square','rhomb','rect','trap']
+ });
+ let xpGiven = false;
+ document.getElementById('p8-iv2-check').addEventListener('click', function(){
+ const fb = document.getElementById('p8-iv2-fb');
+ let correct = 0;
+ items.forEach(function(it){ if(sorter.placed[it.id] === it.cat) correct++; });
+ if(correct === items.length){
+ feedback(fb, true, '✓ Все 6 правильно! +15 XP');
+ if(!xpGiven){
+ xpGiven = true;
+ addXp(15, 'p8-iv2');
+ bumpProgress('p8', 30);
+ }
+ } else {
+ feedback(fb, false, '✗ Правильно: '+correct+' из '+items.length+'. Попробуй ещё раз.');
+ }
+ });
+ document.getElementById('p8-iv2-reset').addEventListener('click', function(){
+ sorter.reset();
+ const fb = document.getElementById('p8-iv2-fb'); fb.style.display = 'none';
+ });
+ })();
+
+ /* IV3 — Тренажёр повторения */
+ (function(){
+ const tasks = [
+ { q:'Треугольник со сторонами 3, 4, 5. Какой угол (в градусах) лежит против стороны 5?', a:90, tol:0.05 },
+ { q:'В прямоугольном треугольнике катеты 6 и 8. Найди гипотенузу.', a:10, tol:0.05 },
+ { q:'Чему равна сумма углов выпуклого 5-угольника (в градусах)?', a:540, tol:0.05 },
+ { q:'В круге $R=6$. Длина окружности ($\\pi\\approx 3{,}14$)?', a:37.68, tol:0.05 },
+ { q:'Треугольник со сторонами 7, 8, 9. Найди площадь по формуле Герона (точность 0,01).', a:26.83, tol:0.05 }
+ ];
+ const list = document.getElementById('p8-iv3-list');
+ const scoreEl = document.getElementById('p8-iv3-score');
+ const solved = new Set();
+ let xpGiven = false;
+
+ list.innerHTML = tasks.map(function(t, i){
+ return ''
+ + '
Задача '+(i+1)+'. '+t.q+'
'
+ + '
'
+ + ' '
+ + 'Проверить '
+ + '
'
+ + '
'
+ + '
';
+ }).join('');
+ renderMath(list);
+
+ list.querySelectorAll('button[data-i]').forEach(function(b){
+ b.addEventListener('click', function(){
+ const i = +b.dataset.i, t = tasks[i];
+ const inp = document.getElementById('p8-iv3-inp-'+i);
+ const fb = document.getElementById('p8-iv3-fb-'+i);
+ const raw = (inp.value || '').replace(',', '.').trim();
+ const val = parseFloat(raw);
+ if(!isFinite(val)){ feedback(fb, false, '✗ Введи число'); return; }
+ if(Math.abs(val - t.a) <= t.tol){
+ feedback(fb, true, '✓ Верно!');
+ if(!solved.has(i)){
+ solved.add(i);
+ scoreEl.textContent = solved.size;
+ if(solved.size === tasks.length && !xpGiven){
+ xpGiven = true;
+ addXp(15, 'p8-iv3');
+ bumpProgress('p8', 30);
+ setTimeout(function(){ achievement('p8_done'); }, 400);
+ }
+ }
+ } else {
+ feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.');
+ }
+ });
+ });
+ })();
+
+ wireReadBtn('p8');
+}
+
+/* ===== §9 «Геометрические величины» (площади + объёмы — обзор) ===== */
+
+function buildP9(){
+ const box = document.getElementById('p9-body');
+ if(!box) return;
+ let html = '';
+
+ /* === ТЕОРИЯ === */
+
+ html += makeCard('theory', 'Площади плоских фигур', '§ 9.1',
+ 'Треугольник. Несколько эквивалентных формул:
'
+ + '$S = \\dfrac{1}{2} a h_a = \\dfrac{1}{2} a b \\sin C = \\sqrt{p(p-a)(p-b)(p-c)} = \\dfrac{abc}{4R} = p r$
'
+ + 'где $p = \\dfrac{a+b+c}{2}$, $R$ — описанная, $r$ — вписанная окружности.
'
+ + 'Четырёхугольники:
'
+ + ''
+ + 'Прямоугольник: $S = a b$. '
+ + 'Параллелограмм: $S = a h = a b \\sin\\alpha$. '
+ + 'Ромб: $S = \\dfrac{1}{2} d_1 d_2 = a^2 \\sin\\alpha$. '
+ + 'Трапеция: $S = \\dfrac{a + b}{2} \\cdot h$ (где $a$, $b$ — основания). '
+ + ' '
+ + 'Круг и сектор:
'
+ + '$S_{круг} = \\pi R^2,\\qquad S_{сект} = \\dfrac{\\pi R^2 \\alpha}{360°}$
');
+
+ html += makeCard('example', 'Объёмы тел в пространстве', '§ 9.2',
+ 'Сводная таблица формул объёмов (повторение §§ 1–6):
'
+ + ''
+ + 'Куб со стороной $a$: $V = a^3$. '
+ + 'Прямоугольный параллелепипед $a \\times b \\times c$: $V = a b c$. '
+ + 'Призма : $V = S_{осн} \\cdot h$. '
+ + 'Цилиндр : $V = \\pi R^2 h$. '
+ + 'Пирамида : $V = \\dfrac{1}{3} S_{осн} \\cdot h$. '
+ + 'Конус : $V = \\dfrac{1}{3} \\pi R^2 h$. '
+ + 'Шар : $V = \\dfrac{4}{3} \\pi R^3$, $S_{пов} = 4\\pi R^2$. '
+ + ' '
+ + 'Ключевая идея. Объёмы «остроконечных» тел (пирамида, конус) в 3 раза меньше объёма «призменных» аналогов с той же основой и высотой: $V_{пир} = \\frac{1}{3} V_{призмы}$, $V_{конус} = \\frac{1}{3} V_{цил}$.
'
+ + 'Пример сравнения: $R=3$, $h=4$ '
+ + '
'
+ + 'Цилиндр: $V = \\pi \\cdot 9 \\cdot 4 = 36\\pi \\approx 113{,}0$. '
+ + 'Конус с теми же $R$, $h$: $V = \\frac{1}{3}\\cdot 36\\pi = 12\\pi \\approx 37{,}7$ — ровно треть. '
+ + 'Шар $R=3$: $V = \\frac{4}{3}\\pi \\cdot 27 = 36\\pi \\approx 113{,}0$ — столько же, сколько у цилиндра $R=3$, $h=4$! '
+ + ' '
+ + '
');
+
+ /* === ИНТЕРАКТИВ 1 — Универсальный калькулятор === */
+ html += ''
+ + ''
+ + '
Выбери фигуру, введи параметры. После 5 разных фигур — +10 XP.
'
+ + '
'
+ + 'Фигура:'
+ + 'Прямоугольник ($a,b$) '
+ + 'Треугольник ($a,b,C°$) '
+ + 'Параллелограмм ($a,b,\\alpha°$) '
+ + 'Ромб ($d_1,d_2$) '
+ + 'Трапеция ($a,b,h$) '
+ + 'Круг ($R$) '
+ + 'Призма ($S_{осн},h$) '
+ + 'Цилиндр ($R,h$) '
+ + 'Пирамида ($S_{осн},h$) '
+ + 'Конус ($R,h$) '
+ + 'Шар ($R$) '
+ + ' '
+ + '
'
+ + '
'
+ + '
Вычислить
'
+ + '
Выбери фигуру и параметры, затем нажми «Вычислить».
'
+ + '
Фигур изучено: 0 / 5
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 2 — Тренажёр площадей === */
+ html += ''
+ + ''
+ + '
Введи числовой ответ. Допуск $\\pm 0{,}05$. Для $\\pi$ используй $3{,}14$.
'
+ + '
'
+ + '
Решено: 0 / 6
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 3 — Тренажёр объёмов === */
+ html += ''
+ + ''
+ + '
Введи числовой ответ. Допуск $\\pm 0{,}05$. Для $\\pi$ используй $3{,}14$.
'
+ + '
'
+ + '
Решено: 0 / 6
'
+ + '
';
+
+ html += secNavFor('p9');
+ html += readButton('p9');
+
+ box.innerHTML = html;
+ renderMath(box);
+
+ /* IV1 — Универсальный калькулятор */
+ (function(){
+ const PI = 3.14;
+ /* Спецификация полей: { key, label, defValue } */
+ const SPEC = {
+ rect: { name:'Прямоугольник', fields:[['a','$a$',5],['b','$b$',8]], calc:p=>({fx:'S = a\\cdot b = '+p.a+'\\cdot '+p.b+' = '+(p.a*p.b).toFixed(2), val:p.a*p.b, unit:'S'}) },
+ tri: { name:'Треугольник', fields:[['a','$a$',5],['b','$b$',8],['C','$C°$',30]], calc:p=>{const v=0.5*p.a*p.b*Math.sin(p.C*Math.PI/180); return {fx:'S = \\tfrac{1}{2}ab\\sin C = \\tfrac{1}{2}\\cdot '+p.a+'\\cdot '+p.b+'\\cdot \\sin '+p.C+'° = '+v.toFixed(2), val:v, unit:'S'};} },
+ par: { name:'Параллелограмм', fields:[['a','$a$',6],['b','$b$',10],['A','$\\alpha°$',30]], calc:p=>{const v=p.a*p.b*Math.sin(p.A*Math.PI/180); return {fx:'S = ab\\sin\\alpha = '+p.a+'\\cdot '+p.b+'\\cdot \\sin '+p.A+'° = '+v.toFixed(2), val:v, unit:'S'};} },
+ rhomb: { name:'Ромб', fields:[['d1','$d_1$',6],['d2','$d_2$',8]], calc:p=>({fx:'S = \\tfrac{1}{2}d_1 d_2 = \\tfrac{1}{2}\\cdot '+p.d1+'\\cdot '+p.d2+' = '+(0.5*p.d1*p.d2).toFixed(2), val:0.5*p.d1*p.d2, unit:'S'}) },
+ trap: { name:'Трапеция', fields:[['a','$a$',4],['b','$b$',8],['h','$h$',5]], calc:p=>({fx:'S = \\tfrac{a+b}{2}\\cdot h = \\tfrac{'+p.a+'+'+p.b+'}{2}\\cdot '+p.h+' = '+(0.5*(p.a+p.b)*p.h).toFixed(2), val:0.5*(p.a+p.b)*p.h, unit:'S'}) },
+ circ: { name:'Круг', fields:[['R','$R$',4]], calc:p=>({fx:'S = \\pi R^2 \\approx 3{,}14\\cdot '+p.R+'^2 = '+(PI*p.R*p.R).toFixed(2), val:PI*p.R*p.R, unit:'S'}) },
+ prism: { name:'Призма', fields:[['So','$S_{осн}$',12],['h','$h$',5]], calc:p=>({fx:'V = S_{осн}\\cdot h = '+p.So+'\\cdot '+p.h+' = '+(p.So*p.h).toFixed(2), val:p.So*p.h, unit:'V'}) },
+ cyl: { name:'Цилиндр', fields:[['R','$R$',3],['h','$h$',5]], calc:p=>({fx:'V = \\pi R^2 h \\approx 3{,}14\\cdot '+p.R+'^2\\cdot '+p.h+' = '+(PI*p.R*p.R*p.h).toFixed(2), val:PI*p.R*p.R*p.h, unit:'V'}) },
+ pyr: { name:'Пирамида', fields:[['So','$S_{осн}$',24],['h','$h$',5]], calc:p=>({fx:'V = \\tfrac{1}{3}S_{осн}h = \\tfrac{1}{3}\\cdot '+p.So+'\\cdot '+p.h+' = '+(p.So*p.h/3).toFixed(2), val:p.So*p.h/3, unit:'V'}) },
+ cone: { name:'Конус', fields:[['R','$R$',6],['h','$h$',5]], calc:p=>({fx:'V = \\tfrac{1}{3}\\pi R^2 h \\approx \\tfrac{1}{3}\\cdot 3{,}14\\cdot '+p.R+'^2\\cdot '+p.h+' = '+(PI*p.R*p.R*p.h/3).toFixed(2), val:PI*p.R*p.R*p.h/3, unit:'V'}) },
+ sph: { name:'Шар', fields:[['R','$R$',3]], calc:p=>({fx:'V = \\tfrac{4}{3}\\pi R^3 \\approx \\tfrac{4}{3}\\cdot 3{,}14\\cdot '+p.R+'^3 = '+(4*PI*p.R*p.R*p.R/3).toFixed(2), val:4*PI*p.R*p.R*p.R/3, unit:'V'}) }
+ };
+ const sel = document.getElementById('p9-iv1-fig');
+ const fields = document.getElementById('p9-iv1-fields');
+ const out = document.getElementById('p9-iv1-out');
+ const oCnt = document.getElementById('p9-iv1-cnt');
+ const seen = new Set();
+ let xpGiven = false;
+
+ function renderFields(){
+ const sp = SPEC[sel.value];
+ fields.innerHTML = sp.fields.map(function(f){
+ return ''
+ + ''+f[1]+' = '
+ + ' ';
+ }).join('');
+ renderMath(fields);
+ }
+ sel.addEventListener('change', function(){ renderFields(); out.innerHTML = 'Параметры обновлены. Нажми «Вычислить».'; });
+ renderFields();
+
+ document.getElementById('p9-iv1-calc').addEventListener('click', function(){
+ const key = sel.value;
+ const sp = SPEC[key];
+ const p = {};
+ let bad = false;
+ sp.fields.forEach(function(f){
+ const el = document.getElementById('p9-iv1-f-'+f[0]);
+ const raw = (el.value || '').replace(',', '.').trim();
+ const v = parseFloat(raw);
+ if(!isFinite(v) || v <= 0){ bad = true; }
+ p[f[0]] = v;
+ });
+ if(bad){ out.innerHTML = 'Введи положительные числа во все поля. '; return; }
+ const r = sp.calc(p);
+ out.innerHTML = ''+sp.name+'
'
+ + '$$ '+r.fx+' $$
'
+ + 'Ответ: $'+r.unit+' \\approx '+r.val.toFixed(2)+'$
';
+ renderMath(out);
+ seen.add(key);
+ oCnt.textContent = seen.size;
+ if(seen.size >= 5 && !xpGiven){
+ xpGiven = true;
+ addXp(10, 'p9-iv1');
+ bumpProgress('p9', 20);
+ }
+ });
+ })();
+
+ /* IV2 — Тренажёр площадей */
+ (function(){
+ const tasks = [
+ { q:'Прямоугольник $5 \\times 8$. Найди площадь.', a:40, tol:0.05 },
+ { q:'Круг $R=4$. Найди площадь ($\\pi\\approx 3{,}14$).', a:50.24, tol:0.05 },
+ { q:'Треугольник со сторонами 5, 12, 13. Найди площадь.', a:30, tol:0.05 },
+ { q:'Трапеция: основания 4 и 8, высота 5. Найди площадь.', a:30, tol:0.05 },
+ { q:'Параллелограмм со сторонами 6 и 10, угол $30°$. Площадь?', a:30, tol:0.05 },
+ { q:'Ромб с диагоналями 6 и 8. Площадь?', a:24, tol:0.05 }
+ ];
+ const list = document.getElementById('p9-iv2-list');
+ const scoreEl = document.getElementById('p9-iv2-score');
+ const solved = new Set();
+ let xpGiven = false;
+
+ list.innerHTML = tasks.map(function(t, i){
+ return ''
+ + '
Задача '+(i+1)+'. '+t.q+'
'
+ + '
'
+ + ' '
+ + 'Проверить '
+ + '
'
+ + '
'
+ + '
';
+ }).join('');
+ renderMath(list);
+
+ list.querySelectorAll('button[data-i]').forEach(function(b){
+ b.addEventListener('click', function(){
+ const i = +b.dataset.i, t = tasks[i];
+ const inp = document.getElementById('p9-iv2-inp-'+i);
+ const fb = document.getElementById('p9-iv2-fb-'+i);
+ const raw = (inp.value || '').replace(',', '.').trim();
+ const val = parseFloat(raw);
+ if(!isFinite(val)){ feedback(fb, false, '✗ Введи число'); return; }
+ if(Math.abs(val - t.a) <= t.tol){
+ feedback(fb, true, '✓ Верно!');
+ if(!solved.has(i)){
+ solved.add(i);
+ scoreEl.textContent = solved.size;
+ if(solved.size === tasks.length && !xpGiven){
+ xpGiven = true;
+ addXp(15, 'p9-iv2');
+ bumpProgress('p9', 30);
+ }
+ }
+ } else {
+ feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.');
+ }
+ });
+ });
+ })();
+
+ /* IV3 — Тренажёр объёмов */
+ (function(){
+ const tasks = [
+ { q:'Куб со стороной 4. Найди $V$.', a:64, tol:0.05 },
+ { q:'Прямоугольный параллелепипед $3\\times 4\\times 5$. Найди $V$.', a:60, tol:0.05 },
+ { q:'Цилиндр $R=3$, $h=5$. Найди $V$ ($\\pi\\approx 3{,}14$).', a:141.3, tol:0.05 },
+ { q:'Пирамида: $S_{осн}=24$, $h=5$. Найди $V$.', a:40, tol:0.05 },
+ { q:'Конус $R=6$, $h=5$. Найди $V$ ($\\pi\\approx 3{,}14$).', a:188.4, tol:0.05 },
+ { q:'Шар $R=3$. Найди $V$ ($\\pi\\approx 3{,}14$).', a:113.04, tol:0.05 }
+ ];
+ const list = document.getElementById('p9-iv3-list');
+ const scoreEl = document.getElementById('p9-iv3-score');
+ const solved = new Set();
+ let xpGiven = false;
+
+ list.innerHTML = tasks.map(function(t, i){
+ return ''
+ + '
Задача '+(i+1)+'. '+t.q+'
'
+ + '
'
+ + ' '
+ + 'Проверить '
+ + '
'
+ + '
'
+ + '
';
+ }).join('');
+ renderMath(list);
+
+ list.querySelectorAll('button[data-i]').forEach(function(b){
+ b.addEventListener('click', function(){
+ const i = +b.dataset.i, t = tasks[i];
+ const inp = document.getElementById('p9-iv3-inp-'+i);
+ const fb = document.getElementById('p9-iv3-fb-'+i);
+ const raw = (inp.value || '').replace(',', '.').trim();
+ const val = parseFloat(raw);
+ if(!isFinite(val)){ feedback(fb, false, '✗ Введи число'); return; }
+ if(Math.abs(val - t.a) <= t.tol){
+ feedback(fb, true, '✓ Верно!');
+ if(!solved.has(i)){
+ solved.add(i);
+ scoreEl.textContent = solved.size;
+ if(solved.size === tasks.length && !xpGiven){
+ xpGiven = true;
+ addXp(15, 'p9-iv3');
+ bumpProgress('p9', 30);
+ setTimeout(function(){ achievement('p9_done'); }, 400);
+ }
+ }
+ } else {
+ feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.');
+ }
+ });
+ });
+ })();
+
+ wireReadBtn('p9');
+}
+
/* ===== Search ===== */
const SEARCH_INDEX = (function(){
const arr=[];