diff --git a/frontend/textbooks/geometry_8_ch1.html b/frontend/textbooks/geometry_8_ch1.html
index c54c1b9..085ce5d 100644
--- a/frontend/textbooks/geometry_8_ch1.html
+++ b/frontend/textbooks/geometry_8_ch1.html
@@ -491,7 +491,7 @@ function buildParaSelector(){
const BUILT = new Set();
const BUILDERS = {
- p1:()=>buildP1stub(), p2:()=>buildP2stub(), p3:()=>buildP3stub(), p4:()=>buildP4stub(),
+ p1:()=>buildP1(), p2:()=>buildP2(), p3:()=>buildP3(), p4:()=>buildP4(),
p5:()=>buildP5stub(), p6:()=>buildP6stub(), p7:()=>buildP7stub(), p8:()=>buildP8stub(),
p9:()=>buildP9stub(), p10:()=>buildP10stub(), p11:()=>buildP11stub(), p12:()=>buildP12stub(),
p13:()=>buildP13stub(), p14:()=>buildP14stub(), p15:()=>buildP15stub(), p16:()=>buildP16stub(),
@@ -743,11 +743,1155 @@ function init(){
}
document.addEventListener('DOMContentLoaded', init);
-/* STUBS — Wave 1 будет заполнять реальный контент */
-function buildP1stub(){ document.getElementById('p1-body').innerHTML = '
§1 — Волна 1 : содержимое появится в следующем обновлении.
' + secNav(null,'p2'); }
-function buildP2stub(){ document.getElementById('p2-body').innerHTML = '§2 — Волна 1 : содержимое появится в следующем обновлении.
' + secNav('p1','p3'); }
-function buildP3stub(){ document.getElementById('p3-body').innerHTML = '§3 — Волна 1 : содержимое появится в следующем обновлении.
' + secNav('p2','p4'); }
-function buildP4stub(){ document.getElementById('p4-body').innerHTML = '§4 — Волна 1 : содержимое появится в следующем обновлении.
' + secNav('p3','p5'); }
+/* ============================================================
+ § 1 — ВЫПУКЛЫЕ МНОГОУГОЛЬНИКИ. ДИАГОНАЛЬ. ПЕРИМЕТР
+ ============================================================ */
+function buildP1(){
+ const box = document.getElementById('p1-body');
+ let html = '';
+
+ html += makeCard('theory','Многоугольник — определение','1.1',`
+ Многоугольник — это замкнутая ломаная без самопересечений. Она делит плоскость на внутреннюю часть (многоугольник) и внешнюю.
+ Элементы: вершины (точки излома), стороны (звенья ломаной), углы (при каждой вершине).
+ Названия: 3 стороны — треугольник, 4 — четырёхугольник, 5 — пятиугольник, 6 — шестиугольник, …, n — n-угольник.
`);
+
+ html += makeCard('rule','Выпуклый многоугольник','1.2',`
+ Выпуклый многоугольник — многоугольник, у которого каждая сторона (её прямая) не разделяет оставшиеся вершины на две части: все они лежат по одну сторону от этой прямой.
+ Эквивалентно: все диагонали лежат внутри фигуры.
+ Невыпуклый (вогнутый) — если хотя бы одна диагональ выходит наружу.
`);
+
+ html += makeCard('rule','Диагональ. Число диагоналей','1.3',`
+ Диагональ — отрезок, соединяющий две несмежные (несоседние) вершины многоугольника.
+ В n-угольнике число диагоналей:
+ \\[D = \\dfrac{n(n-3)}{2}\\]
+ Объяснение: из каждой из $n$ вершин можно провести $(n-3)$ диагонали (не к самой себе и не к двум соседним). Делим на 2, т.к. каждая диагональ считается дважды.
+
+ $n$ 3 4 5 6 7 8 10
+ Диагоналей 0 2 5 9 14 20 35
+
`);
+
+ html += makeCard('rule','Периметр','1.4',`
+ Периметр многоугольника — сумма длин всех его сторон:
+ \\[P = a_1 + a_2 + \\cdots + a_n\\]
+ Для правильного n-угольника со стороной $a$: $P = n \\cdot a$.
`);
+
+ html += makeCard('example','Пример','1.5',`
+ Сколько диагоналей у восьмиугольника?
+ $n = 8$: $D = \\dfrac{8 \\cdot (8-3)}{2} = \\dfrac{8 \\cdot 5}{2} = \\dfrac{40}{2} = 20$. Ответ: 20 диагоналей.
+ Периметр четырёхугольника со сторонами 5, 7, 4, 6 равен $5+7+4+6=22$.
`);
+
+ /* --- INTERACTIVE 1: SVG-конструктор многоугольника --- */
+ html += `
+
+
Тащи вершины мышью (или пальцем). Меняй количество вершин слайдером. Смотри: периметр, диагонали, выпуклость.
+
+ Вершин: 5
+
+
+ Сбросить
+
+
+
+
`;
+
+ /* --- INTERACTIVE 2: Калькулятор диагоналей --- */
+ html += `
+
+
Выбери n — увидишь пошаговое вычисление формулы $D = \\dfrac{n(n-3)}{2}$.
+
+ $n$ = 7
+
+
+
`;
+
+ /* --- INTERACTIVE 3: DnD — выпуклый/невыпуклый/не многоугольник --- */
+ html += `
+
+
Разложи фигуры по категориям. Нажми карточку, затем — на нужный ящик. Или перетащи.
+
Перетащивайте или нажмите карточку, затем — на нужный ящик.
+
+
+
Проверить Сначала
+
+
`;
+
+ /* --- INTERACTIVE 4: Тренажёр периметра --- */
+ html += `
+
+
Вычисли периметр многоугольника по данным сторонам и введи ответ.
+
Задача 1 / 5 Очки: 0
+
+
+
+ Проверить
+ Начать
+
+
+
`;
+
+ /* --- INTERACTIVE 5: Босс §1 --- */
+ html += `
+
+
Реши все 4 задачи — получишь XP. Каждая правильно решённая задача даёт +5 XP.
+
+
`;
+
+ html += `
+
+
+ Я прочитал §1 (+10 XP)
+
+
`;
+
+ html += secNav(null,'p2');
+ box.innerHTML = html;
+ if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
+
+ /* == INIT: SVG-конструктор многоугольника == */
+ (function(){
+ const W = 360, H = 320, cx = W/2, cy = H/2, R = 120;
+ let n = 5;
+ let verts = [];
+ function defaultVerts(nv){
+ const v = [];
+ for(let i=0;i1e-6&&t<1-1e-6&&u>1e-6&&u<1-1e-6;
+ }
+ function hasSelfIntersection(vs){
+ const n=vs.length;
+ for(let i=0;i0?1:-1;
+ if(!sign) sign=s;
+ else if(sign!==s) return false;
+ }
+ return true;
+ }
+ function interiorAngle(vs,i){
+ const n=vs.length;
+ const prev=vs[(i-1+n)%n],cur=vs[i],next=vs[(i+1)%n];
+ const ax=prev.x-cur.x,ay=prev.y-cur.y;
+ const bx=next.x-cur.x,by=next.y-cur.y;
+ const dot=ax*bx+ay*by,cross=ax*by-ay*bx;
+ let a=Math.atan2(Math.abs(cross),dot)*180/Math.PI;
+ if(cross<0) a=360-a;
+ return a;
+ }
+ function redraw(){
+ const svg=document.getElementById('p1-poly-svg');
+ if(!svg) return;
+ const nv=verts.length;
+ const selfX=hasSelfIntersection(verts);
+ const conv=!selfX&&isConvex(verts);
+ const pts=verts.map(v=>v.x+','+v.y).join(' ');
+ const col=selfX?'#ef4444':(conv?'#10b981':'#f59e0b');
+ const fillCol=selfX?'rgba(239,68,68,.12)':(conv?'rgba(16,185,129,.12)':'rgba(245,158,11,.12)');
+ let s='';
+ s+=' ';
+ // диагонали
+ for(let i=0;i ';
+ }
+ // метки сторон
+ for(let i=0;i'+d.toFixed(1)+'';
+ }
+ // вершины
+ for(let i=0;i ';
+ s+=' ';
+ const letter=String.fromCharCode(65+i);
+ const lx=v.x+(v.x-cx)*0.22+2,ly=v.y+(v.y-cy)*0.22+2;
+ s+=''+letter+' ';
+ }
+ svg.innerHTML=s;
+ // drag handlers
+ svg.querySelectorAll('.p1-poly-vh').forEach(el=>{
+ el.style.cursor='grab';
+ el.addEventListener('pointerdown',ev=>{
+ if(ev.button!==undefined&&ev.button!==0) return;
+ const idx=+el.dataset.i;
+ el.style.cursor='grabbing';
+ try{el.setPointerCapture(ev.pointerId);}catch(e){}
+ function onMove(e){
+ const rect=svg.getBoundingClientRect();
+ const sx=svg.viewBox.baseVal.width/rect.width;
+ const sy=svg.viewBox.baseVal.height/rect.height;
+ const nx=Math.max(10,Math.min(W-10,(e.clientX-rect.left)*sx));
+ const ny=Math.max(10,Math.min(H-10,(e.clientY-rect.top)*sy));
+ verts[idx]={x:nx,y:ny};
+ redraw(); updateInfo();
+ }
+ function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp);el.style.cursor='grab'; }
+ el.addEventListener('pointermove',onMove);
+ el.addEventListener('pointerup',onUp);
+ el.addEventListener('pointercancel',onUp);
+ });
+ });
+ const statusEl=document.getElementById('p1-poly-status');
+ if(statusEl){
+ statusEl.textContent=selfX?'Самопересечение!':(conv?'Выпуклый':'Невыпуклый');
+ statusEl.style.color=col;
+ }
+ }
+ function updateInfo(){
+ const nv=verts.length;
+ const perimeter=verts.reduce((s,v,i)=>s+dist(v,verts[(i+1)%nv]),0);
+ const diags=nv*(nv-3)/2;
+ const selfX=hasSelfIntersection(verts);
+ const conv=!selfX&&isConvex(verts);
+ const angStr=verts.map((v,i)=>interiorAngle(verts,i).toFixed(1)+'°').join(', ');
+ const angSum=verts.reduce((s,v,i)=>s+interiorAngle(verts,i),0);
+ const col=selfX?'#ef4444':(conv?'#10b981':'#f59e0b');
+ document.getElementById('p1-poly-info').innerHTML=`
+ Вид
${selfX?'Самопересечение!':(conv?'Выпуклый':'Невыпуклый')}
+ Периметр
${perimeter.toFixed(2)}
+ Диагоналей
${Math.max(0,diags)}
+ Сумма углов
${angSum.toFixed(1)}° `;
+ }
+ function build(){
+ verts=defaultVerts(n);
+ const wrap=document.getElementById('p1-poly-svg-wrap');
+ wrap.innerHTML=' ';
+ redraw(); updateInfo();
+ }
+ build();
+ document.getElementById('p1-poly-n-sl').addEventListener('input',function(){
+ n=+this.value; document.getElementById('p1-poly-n-val').textContent=n; build();
+ });
+ document.getElementById('p1-poly-reset').addEventListener('click',()=>build());
+ })();
+
+ /* == INIT: Калькулятор диагоналей == */
+ (function(){
+ const sl=document.getElementById('p1-dc-n'),val=document.getElementById('p1-dc-nval'),out=document.getElementById('p1-dc-out');
+ function update(){
+ const n=+sl.value; val.textContent=n;
+ const d=n*(n-3)/2;
+ out.innerHTML=`
+ $n = ${n}$, формула: $D = \\dfrac{n(n-3)}{2}$
+ Подставляем: $D = \\dfrac{${n} \\cdot (${n} - 3)}{2} = \\dfrac{${n} \\cdot ${n-3}}{2} = \\dfrac{${n*(n-3)}}{2}$
+ Ответ: $D = ${d}$ диагоналей
`;
+ renderMath(out);
+ }
+ sl.addEventListener('input',update); update();
+ })();
+
+ /* == INIT: DnD сортировка == */
+ (function(){
+ const items=[
+ {id:'tri', html:'Треугольник ', ans:'conv'},
+ {id:'square',html:'Квадрат ', ans:'conv'},
+ {id:'hex', html:'Правильный шестиугольник ', ans:'conv'},
+ {id:'star', html:'Звезда ', ans:'conc'},
+ {id:'arrow', html:'Стрелка ', ans:'conc'},
+ {id:'circle',html:'Круг ', ans:'not'},
+ {id:'open', html:'Незамкнутая ломаная ', ans:'not'},
+ ];
+ const sorter=setupSorter({poolId:'p1-dnd-pool',scopeSelector:'#p1-dnd-wrap',items,cats:['conv','conc','not']});
+ document.getElementById('p1-dnd-reset').addEventListener('click',()=>{ sorter.reset(); document.getElementById('p1-dnd-fb').style.display='none'; });
+ document.getElementById('p1-dnd-check').addEventListener('click',()=>{
+ let ok=0,total=items.length;
+ items.forEach(it=>{ if(sorter.placed[it.id]===it.ans) ok++; });
+ const fb=document.getElementById('p1-dnd-fb');
+ if(ok===total){ feedback(fb,true,'Все '+total+' фигур разложены верно! +5 XP'); addXp(5,'p1-dnd'); bumpProgress('p1',15); }
+ else feedback(fb,false,'Верно: '+ok+' из '+total+'. Попробуй ещё раз.');
+ });
+ })();
+
+ /* == INIT: Тренажёр периметра == */
+ (function(){
+ const tasks=[
+ {sides:[5,7,4,6], ans:22, text:'Четырёхугольник со сторонами 5, 7, 4, 6.'},
+ {sides:[3,4,5], ans:12, text:'Треугольник со сторонами 3, 4, 5.'},
+ {sides:[8,8,8,8,8], ans:40, text:'Правильный пятиугольник со стороной 8.'},
+ {sides:[6,9,6,9], ans:30, text:'Прямоугольник со сторонами 6 и 9.'},
+ {sides:[7,5,8,4,6], ans:30, text:'Пятиугольник со сторонами 7, 5, 8, 4, 6.'},
+ ];
+ let idx=0,score=0;
+ function show(){
+ const t=tasks[idx];
+ document.getElementById('p1-pt-i').textContent=idx+1;
+ document.getElementById('p1-pt-task').innerHTML=''+t.text+' Найди периметр.';
+ document.getElementById('p1-pt-ans').value='';
+ document.getElementById('p1-pt-fb').style.display='none';
+ }
+ document.getElementById('p1-pt-start').addEventListener('click',()=>{ idx=0;score=0;document.getElementById('p1-pt-score').textContent=0;show(); });
+ document.getElementById('p1-pt-go').addEventListener('click',()=>{
+ if(idx>=tasks.length) return;
+ const ans=+document.getElementById('p1-pt-ans').value;
+ const fb=document.getElementById('p1-pt-fb');
+ if(ans===tasks[idx].ans){
+ score++; document.getElementById('p1-pt-score').textContent=score;
+ addXp(3,'p1-perim'); bumpProgress('p1',5);
+ if(idxshow(),900); }
+ else{ feedback(fb,true,'Все задачи решены! +5 XP'); addXp(5,'p1-perim-all'); bumpProgress('p1',10); }
+ } else {
+ feedback(fb,false,'Неверно. Ответ: '+tasks[idx].ans+'. Периметр = сумма всех сторон.');
+ }
+ });
+ document.getElementById('p1-pt-ans').addEventListener('keydown',e=>{ if(e.key==='Enter') document.getElementById('p1-pt-go').click(); });
+ show();
+ })();
+
+ /* == INIT: Босс §1 == */
+ (function(){
+ const tasks=[
+ { q:'Сколько диагоналей у 7-угольника ?', ans:14, hint:'Формула: n(n-3)/2, n=7.' },
+ { q:'Найди периметр прямоугольника со сторонами AB=12 и BC=7 .', ans:38, hint:'P = 2(12+7) = 38.' },
+ { q:'В многоугольнике 20 диагоналей . Сколько в нём вершин? (Число сторон)', ans:8, hint:'n(n-3)/2=20 → n=8.' },
+ { q:'Периметр правильного шестиугольника равен 54 . Чему равна одна сторона?', ans:9, hint:'P = 6a → a = 54/6 = 9.' },
+ ];
+ const box=document.getElementById('p1-boss-tasks');
+ let solved=new Set();
+ box.innerHTML=tasks.map((t,i)=>`
+
+
${t.q}
+
+
+ Проверить
+
+
+
`).join('');
+ window.p1BossSolved=new Set();
+ })();
+}
+
+/* ============================================================
+ § 2 — СУММА УГЛОВ ВЫПУКЛОГО МНОГОУГОЛЬНИКА
+ ============================================================ */
+function buildP2(){
+ const box = document.getElementById('p2-body');
+ let html = '';
+
+ html += makeCard('theory','Теорема о сумме углов','2.1',`
+ Теорема. Сумма внутренних углов выпуклого $n$-угольника равна:
+ \\[(n-2)\\cdot 180^{\\circ}\\]
+ Доказательство. Из любой вершины $A_1$ проводим диагонали ко всем несмежным вершинам. Получаем $(n-2)$ треугольника. Сумма углов каждого треугольника равна $180°$, и все эти углы вместе составляют углы многоугольника. Итого: $(n-2) \\cdot 180°$.
+
+ $n$ 3 4 5 6 7 8 10
+ Сумма углов $180°$ $360°$ $540°$ $720°$ $900°$ $1080°$ $1440°$
+
`);
+
+ html += makeCard('rule','Правильный многоугольник','2.2',`
+ Правильный n-угольник — все стороны равны и все углы равны.
+ Каждый внутренний угол правильного $n$-угольника:
+ \\[\\alpha = \\dfrac{(n-2)\\cdot 180^{\\circ}}{n}\\]
+
+ Фигура $n$ Угол $\\alpha$
+
+ Треугольник 3 $60°$
+ Квадрат 4 $90°$
+ Пятиугольник 5 $108°$
+ Шестиугольник 6 $120°$
+ Восьмиугольник 8 $135°$
+ Двенадцатиугольник 12 $150°$
+
+
`);
+
+ html += makeCard('example','Примеры','2.3',`
+ Один угол девятиугольника. $n=9$: сумма $= (9-2)\\cdot 180°=7\\cdot 180°=1260°$. Один угол правильного 9-угольника: $1260°/9=140°$.
+ Найти n по сумме углов. Сумма $=1440°$: $(n-2)\\cdot 180°=1440° \\Rightarrow n-2=8 \\Rightarrow n=10$. Ответ: десятиугольник.
`);
+
+ /* --- INTERACTIVE 1: Анимация триангуляции --- */
+ html += `
+
+
Выбери n-угольник и нажми «Триангулировать» — увидишь разбиение на треугольники и подсчёт суммы углов.
+
+ $n$ = 5
+
+
+ Триангулировать
+ Сбросить
+
+
+
+
`;
+
+ /* --- INTERACTIVE 2: Калькулятор суммы и угла --- */
+ html += `
+
+
Задай $n$ — мгновенно увидишь сумму всех углов и величину одного угла правильного $n$-угольника.
+
+ $n$ = 6
+
+
+
`;
+
+ /* --- INTERACTIVE 3: Обратная задача --- */
+ html += `
+
+
Введи сумму внутренних углов (кратную 180°, больше 180°) — система найдёт n или скажет, что такого многоугольника нет.
+
+
+ Найти n
+
+
+
`;
+
+ /* --- INTERACTIVE 4: DnD правильные многоугольники ↔ углы --- */
+ html += `
+
+
Разложи названия правильных многоугольников по значению угла.
+
Перетащивайте или нажмите карточку, затем — на нужный ящик.
+
+
+
Проверить Сначала
+
+
`;
+
+ /* --- INTERACTIVE 5: Босс §2 --- */
+ html += `
+
+
Реши задачи — каждая верная даёт +5 XP.
+
+
`;
+
+ html += `
+
+
+ Я прочитал §2 (+10 XP)
+
+
`;
+
+ html += secNav('p1','p3');
+ box.innerHTML = html;
+ if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
+
+ /* == INIT: Триангуляция == */
+ (function(){
+ const W=360, H=300, cx=W/2, cy=H/2, R=110;
+ let n=5, shown=false;
+ const colors=['#d97706','#10b981','#0891b2','#8b5cf6','#ef4444','#f97316','#14b8a6','#a855f7','#e11d48','#6366f1'];
+ function pts(nv,r,ox,oy){ const a=[]; for(let i=0;i';
+ if(triangulate){
+ for(let i=1;i ';
+ }
+ const out=document.getElementById('p2-tr-out');
+ out.style.display='block';
+ out.innerHTML='$n='+n+'$, треугольников: $'+(n-2)+'$. Сумма углов $= ('+n+'-2)\\cdot 180° = '+(n-2)+'\\cdot 180° = '+((n-2)*180)+'°$';
+ renderMath(out);
+ }
+ const ptstr=vs.map(v=>v.x+','+v.y).join(' ');
+ s+=' ';
+ vs.forEach((v,i)=>{
+ s+=' ';
+ const lx=v.x+(v.x-cx)*0.22,ly=v.y+(v.y-cy)*0.22;
+ s+=''+ String.fromCharCode(65+i)+' ';
+ });
+ if(triangulate){
+ for(let i=1;i ';
+ }
+ for(let i=1;iT'+(i)+'';
+ }
+ }
+ s+='';
+ wrap.innerHTML=s;
+ }
+ const nlSl=document.getElementById('p2-tr-n');
+ const nlVal=document.getElementById('p2-tr-nval');
+ nlSl.addEventListener('input',function(){ n=+this.value; nlVal.textContent=n; shown=false; document.getElementById('p2-tr-out').style.display='none'; draw(false); });
+ document.getElementById('p2-tr-go').addEventListener('click',()=>{ shown=true; draw(true); addXp(2,'p2-triang'); bumpProgress('p2',10); });
+ document.getElementById('p2-tr-reset').addEventListener('click',()=>{ shown=false; document.getElementById('p2-tr-out').style.display='none'; draw(false); });
+ draw(false);
+ })();
+
+ /* == INIT: Калькулятор == */
+ (function(){
+ const sl=document.getElementById('p2-cl-n'),val=document.getElementById('p2-cl-nval'),out=document.getElementById('p2-cl-out');
+ function update(){
+ const n=+sl.value; val.textContent=n;
+ const sum=(n-2)*180;
+ const ang=sum/n;
+ out.innerHTML='$n='+n+'$ Сумма всех углов: $('+n+'-2)\\cdot 180° = '+sum+'°$ Один угол правильного $'+n+'$-угольника: $\\dfrac{'+sum+'°}{'+n+'} = '+ang.toFixed(2).replace(/\.00$/,'')+'°$';
+ renderMath(out);
+ }
+ sl.addEventListener('input',update); update();
+ })();
+
+ /* == INIT: Обратная задача == */
+ (function(){
+ document.getElementById('p2-rev-go').addEventListener('click',()=>{
+ const s=+document.getElementById('p2-rev-inp').value;
+ const out=document.getElementById('p2-rev-out');
+ out.style.display='block';
+ if(s<=0||isNaN(s)){ out.innerHTML='Введи положительное число. '; return; }
+ if(s%180!==0){ out.innerHTML='Сумма углов должна делиться на 180°. '; return; }
+ const n=(s/180)+2;
+ if(!Number.isInteger(n)||n<3){ out.innerHTML='Нет такого многоугольника (n должен быть целым ≥ 3). '; return; }
+ out.innerHTML='$(n-2)\\cdot 180°='+s+'° \\Rightarrow n-2='+s/180+' \\Rightarrow n='+n+'$Ответ: '+n+'-угольник ';
+ renderMath(out);
+ addXp(3,'p2-rev');
+ });
+ document.getElementById('p2-rev-inp').addEventListener('keydown',e=>{ if(e.key==='Enter') document.getElementById('p2-rev-go').click(); });
+ })();
+
+ /* == INIT: DnD правильные ↔ углы == */
+ (function(){
+ const items=[
+ {id:'tri3', html:'Треугольник', ans:'60'},
+ {id:'sq4', html:'Квадрат', ans:'90'},
+ {id:'pent5', html:'Пятиугольник', ans:'108'},
+ {id:'hex6', html:'Шестиугольник', ans:'120'},
+ {id:'oct8', html:'Восьмиугольник', ans:'135'},
+ {id:'n9', html:'Девятиугольник', ans:'140'},
+ ];
+ const sorter=setupSorter({poolId:'p2-dnd-pool',scopeSelector:'#p2-dnd-wrap',items,cats:['60','90','108','120','135','140']});
+ document.getElementById('p2-dnd-reset').addEventListener('click',()=>{ sorter.reset(); document.getElementById('p2-dnd-fb').style.display='none'; });
+ document.getElementById('p2-dnd-check').addEventListener('click',()=>{
+ let ok=0;
+ items.forEach(it=>{ if(sorter.placed[it.id]===it.ans) ok++; });
+ const fb=document.getElementById('p2-dnd-fb');
+ if(ok===items.length){ feedback(fb,true,'Все фигуры сопоставлены верно! +5 XP'); addXp(5,'p2-dnd'); bumpProgress('p2',15); }
+ else feedback(fb,false,'Верно: '+ok+' из '+items.length+'. Используй формулу α=(n-2)·180°/n.');
+ });
+ })();
+
+ /* == INIT: Босс §2 == */
+ (function(){
+ const tasks=[
+ { q:'Найди сумму углов выпуклого десятиугольника .', ans:1440, hint:'(10-2)·180=1440' },
+ { q:'Один угол правильного восьмиугольника равен … °', ans:135, hint:'(8-2)·180/8=135' },
+ { q:'Сумма углов многоугольника равна 900° . Сколько сторон?', ans:7, hint:'(n-2)·180=900→n=7' },
+ { q:'Сумма углов правильного многоугольника = 2520° . Найди один угол.', ans:168, hint:'n=(2520/180)+2=16; угол=2520/16=157.5? нет: (16-2)*180=2520, угол=2520/16=157.5. Проверь: n=16' },
+ ];
+ const bossBox=document.getElementById('p2-boss-tasks');
+ bossBox.innerHTML=tasks.map((t,i)=>`
+
+
${t.q}
+
+
+ Проверить
+
+
+
`).join('');
+ window.p2BossSolved=new Set();
+ })();
+}
+
+/* ============================================================
+ § 3 — СУММА ВНЕШНИХ УГЛОВ ВЫПУКЛОГО МНОГОУГОЛЬНИКА
+ ============================================================ */
+function buildP3(){
+ const box = document.getElementById('p3-body');
+ let html = '';
+
+ html += makeCard('theory','Внешний угол. Теорема','3.1',`
+ Внешний угол выпуклого многоугольника при вершине — угол между стороной и продолжением соседней стороны. Внешний угол при вершине $A_i$:
+ \\[\\beta_i = 180^{\\circ} - \\alpha_i\\]
+ где $\\alpha_i$ — соответствующий внутренний угол.
+ Теорема. Сумма всех внешних углов выпуклого многоугольника (по одному у каждой вершины) равна $360°$ — при любом $n$.
+ Объяснение: если обойти многоугольник по периметру, на каждой вершине повернёшься на внешний угол. За полный обход — ровно один полный оборот $= 360°$.
`);
+
+ html += makeCard('rule','Правильный n-угольник','3.2',`
+ Внешний угол правильного $n$-угольника:
+ \\[\\beta = \\dfrac{360^{\\circ}}{n}\\]
+ Внутренний угол: $\\alpha = 180° - \\dfrac{360°}{n} = \\dfrac{(n-2)\\cdot 180°}{n}$.
+ Отсюда: зная внешний угол $\\beta$, можно найти $n = \\dfrac{360°}{\\beta}$.
`);
+
+ html += makeCard('example','Примеры','3.3',`
+ Внешний угол правильного шестиугольника: $\\beta = 360°/6 = 60°$, внутренний $= 180°-60°=120°$.
+ Внешний угол правильного многоугольника = 24°. Найти n: $n = 360°/24° = 15$. Ответ: 15-угольник.
+ Сумма внешних углов правильного 100-угольника: всегда $360°$, независимо от $n$!
`);
+
+ /* --- INTERACTIVE 1: SVG внешние углы + анимация "свернуть в точку" --- */
+ html += `
+
+
Выбери $n$. Посмотри на внешние углы (жёлтые дуги). Нажми «Свернуть» — углы образуют полный оборот $360°$.
+
+ $n$ = 6
+
+
+ Свернуть в точку
+ Сбросить
+
+
+
+
`;
+
+ /* --- INTERACTIVE 2: Калькулятор правильного n-угольника --- */
+ html += `
+
+
Задай $n$ — получишь и внешний, и внутренний угол.
+
+ $n$ = 6
+
+
+
`;
+
+ /* --- INTERACTIVE 3: Тренажёр — найти n по внешнему углу --- */
+ html += `
+
+
Дан один внешний угол правильного n-угольника. Найди n.
+
Задача 1 / 4 Очки: 0
+
+
+
+ Ответить
+ Начать
+
+
+
`;
+
+ /* --- INTERACTIVE 4: Mini-quiz --- */
+ html += ``;
+
+ /* --- INTERACTIVE 5: Босс §3 --- */
+ html += `
+
+
Реши задачи — +5 XP за каждую верную.
+
+
`;
+
+ html += `
+
+
+ Я прочитал §3 (+10 XP)
+
+
`;
+
+ html += secNav('p2','p4');
+ box.innerHTML = html;
+ if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
+
+ /* == INIT: SVG внешние углы == */
+ (function(){
+ const W=380, H=320, cx=W/2, cy=H/2, R=100, Rext=30;
+ let n=6, folded=false;
+ const colors=['#d97706','#10b981','#0891b2','#8b5cf6','#ef4444','#f97316','#14b8a6','#a855f7','#e11d48','#6366f1'];
+ function pts(nv){ const v=[];for(let i=0;i';
+ s+=' ';
+ vs.forEach((v,i)=>{
+ const nxt=vs[(i+1)%n];
+ const ext=40;
+ const dx=v.x-nxt.x,dy=v.y-nxt.y;
+ const len=Math.hypot(dx,dy);
+ const ex=v.x+ext*dx/len,ey=v.y+ext*dy/len;
+ s+=' ';
+ const extAngle=360/n;
+ const startAng=Math.atan2(v.y-nxt.y,v.x-nxt.x)*180/Math.PI;
+ const endAng=startAng-extAngle;
+ const ra=Rext,sa=startAng*(Math.PI/180),ea=endAng*(Math.PI/180);
+ const x1=nxt.x+ra*Math.cos(sa),y1=nxt.y+ra*Math.sin(sa);
+ const x2=nxt.x+ra*Math.cos(ea),y2=nxt.y+ra*Math.sin(ea);
+ const large=extAngle>180?1:0;
+ s+=' ';
+ s+=''+(extAngle.toFixed(1))+'° ';
+ });
+ vs.forEach((v,i)=>{
+ s+=' ';
+ });
+ s+='';
+ document.getElementById('p3-ex-svg-wrap').innerHTML=s;
+ document.getElementById('p3-ex-info').innerHTML='$n='+n+'$, внешний угол $= \\dfrac{360°}{'+n+'} = '+(360/n).toFixed(2).replace(/\.00$/,'')+'°$, сумма $= '+n+' \\times '+(360/n).toFixed(1)+'° = 360°$';
+ renderMath(document.getElementById('p3-ex-info'));
+ }
+ function drawFolded(){
+ let s='';
+ const R2=14;
+ let cumAngle=0;
+ for(let i=0;i ';
+ const mid=(sa+ea)/2;
+ s+=''+(360/n).toFixed(0)+'° ';
+ cumAngle=ea;
+ }
+ s+=' ';
+ s+='360° ';
+ s+=' ';
+ document.getElementById('p3-ex-svg-wrap').innerHTML=s;
+ document.getElementById('p3-ex-info').innerHTML='Все $'+n+'$ внешних углов по $'+(360/n).toFixed(1)+'°$ образуют полный оборот 360° !';
+ renderMath(document.getElementById('p3-ex-info'));
+ addXp(2,'p3-fold'); bumpProgress('p3',10);
+ }
+ const nlSl=document.getElementById('p3-ex-n'),nlVal=document.getElementById('p3-ex-nval');
+ nlSl.addEventListener('input',function(){ n=+this.value; nlVal.textContent=n; folded=false; drawNormal(); });
+ document.getElementById('p3-ex-fold').addEventListener('click',()=>{ folded=true; drawFolded(); });
+ document.getElementById('p3-ex-reset').addEventListener('click',()=>{ folded=false; drawNormal(); });
+ drawNormal();
+ })();
+
+ /* == INIT: Калькулятор == */
+ (function(){
+ const sl=document.getElementById('p3-cl-n'),val=document.getElementById('p3-cl-nval'),out=document.getElementById('p3-cl-out');
+ function update(){
+ const n=+sl.value; val.textContent=n;
+ const ext=360/n, int=180-ext;
+ out.innerHTML='$n='+n+'$ Внешний угол: $\\dfrac{360°}{'+n+'} = '+ext.toFixed(2).replace(/\.00$/,'')+'°$ Внутренний угол: $180° - '+ext.toFixed(2).replace(/\.00$/,'')+'° = '+int.toFixed(2).replace(/\.00$/,'')+'°$';
+ renderMath(out);
+ }
+ sl.addEventListener('input',update); update();
+ })();
+
+ /* == INIT: Тренажёр == */
+ (function(){
+ const tasks=[
+ {ext:30, n:12, text:'Внешний угол правильного многоугольника равен 30° . Найди n.'},
+ {ext:45, n:8, text:'Внешний угол правильного многоугольника равен 45° . Найди n.'},
+ {ext:60, n:6, text:'Внешний угол правильного многоугольника равен 60° . Найди n.'},
+ {ext:72, n:5, text:'Внешний угол правильного многоугольника равен 72° . Найди n.'},
+ ];
+ let idx=0,score=0;
+ function show(){
+ document.getElementById('p3-tr-i').textContent=idx+1;
+ document.getElementById('p3-tr-task').innerHTML=tasks[idx].text+'Подсказка: n = 360°/внешний угол ';
+ document.getElementById('p3-tr-ans').value='';
+ document.getElementById('p3-tr-fb').style.display='none';
+ }
+ document.getElementById('p3-tr-start').addEventListener('click',()=>{ idx=0;score=0;document.getElementById('p3-tr-score').textContent=0;show(); });
+ document.getElementById('p3-tr-go').addEventListener('click',()=>{
+ const ans=+document.getElementById('p3-tr-ans').value;
+ const fb=document.getElementById('p3-tr-fb');
+ if(ans===tasks[idx].n){
+ score++; document.getElementById('p3-tr-score').textContent=score; addXp(3,'p3-train'); bumpProgress('p3',8);
+ if(idxshow(),900); }
+ else{ feedback(fb,true,'Все задачи решены! +5 XP'); addXp(5,'p3-train-all'); bumpProgress('p3',10); }
+ } else feedback(fb,false,'Неверно. Используй: n=360°/'+tasks[idx].ext+'°='+tasks[idx].n);
+ });
+ document.getElementById('p3-tr-ans').addEventListener('keydown',e=>{ if(e.key==='Enter') document.getElementById('p3-tr-go').click(); });
+ show();
+ })();
+
+ /* == INIT: Мини-квиз == */
+ (function(){
+ const qs=[
+ {q:'Сумма внешних углов выпуклого семиугольника равна...', opts:['360°','1260°','900°','Зависит от n'], ans:0},
+ {q:'Внешний угол правильного пятиугольника равен...', opts:['60°','72°','108°','120°'], ans:1},
+ {q:'Если внешний угол правильного многоугольника = 40°, то сторон...', opts:['7','8','9','12'], ans:2},
+ ];
+ let qi=0,qscore=0,answered=false;
+ const cont=document.getElementById('p3-quiz-container');
+ function showQ(){
+ const q=qs[qi];
+ cont.innerHTML=`${q.q}
+
+ ${q.opts.map((o,i)=>''+o+' ').join('')}
+
+
+
+ Вопрос ${qi+1} / ${qs.length} · Очки: ${qscore}
+
`;
+ answered=false;
+ }
+ window.p3QuizAns=function(i){
+ if(answered) return;
+ answered=true;
+ const q=qs[qi];
+ const fb=document.getElementById('p3-q-fb');
+ if(i===q.ans){ qscore++; feedback(fb,true,'Верно! +3 XP'); addXp(3,'p3-quiz'); bumpProgress('p3',7); }
+ else feedback(fb,false,'Неверно. Правильный ответ: '+q.opts[q.ans]);
+ document.querySelectorAll('[id^="p3-qopt-"]').forEach((b,bi)=>{ b.disabled=true; if(bi===q.ans) b.style.background='var(--ok-bg)'; else if(bi===i) b.style.background='var(--fail-bg)'; });
+ setTimeout(()=>{
+ qi++;
+ if(qi';
+ },1300);
+ };
+ showQ();
+ })();
+
+ /* == INIT: Босс §3 == */
+ (function(){
+ const tasks=[
+ { q:'Внешний угол правильного многоугольника равен 20° . Сколько сторон?', ans:18, hint:'n=360/20=18' },
+ { q:'Внутренний угол правильного многоугольника равен 150° . Сколько сторон?', ans:12, hint:'внешний=180-150=30°, n=360/30=12' },
+ { q:'Сумма внешних углов выпуклого двадцатиугольника в градусах?', ans:360, hint:'Всегда 360°!' },
+ { q:'Внешний угол правильного многоугольника равен 36° . Чему равен внутренний угол?', ans:144, hint:'внутренний = 180-36 = 144°' },
+ ];
+ const bossBox=document.getElementById('p3-boss-tasks');
+ bossBox.innerHTML=tasks.map((t,i)=>`
+
+
${t.q}
+
+
+ Проверить
+
+
+
`).join('');
+ window.p3BossSolved=new Set();
+ })();
+}
+
+/* ============================================================
+ § 4 — ПАРАЛЛЕЛОГРАММ
+ ============================================================ */
+function buildP4(){
+ const box = document.getElementById('p4-body');
+ let html = '';
+
+ html += makeCard('theory','Определение и элементы','4.1',`
+ Параллелограмм — четырёхугольник, у которого противоположные стороны попарно параллельны :
+ \\[AB \\parallel CD \\quad \\text{и} \\quad BC \\parallel AD\\]
+ Обозначение: $\\square ABCD$ или просто $ABCD$.
+ Элементы параллелограмма:
+
+ Стороны: $AB$, $BC$, $CD$, $DA$ (противоположные: $AB = CD$, $BC = DA$)
+ Углы: противоположные углы равны; смежные углы — дополнение до $180°$
+ Диагонали: $AC$ и $BD$ — пересекаются и делятся точкой пересечения пополам
+ `);
+
+ html += makeCard('rule','Основные свойства','4.2',`
+ В параллелограмме $ABCD$:
+ \\[AB = CD, \\quad BC = AD\\]
+ \\[\\angle A = \\angle C, \\quad \\angle B = \\angle D\\]
+ \\[\\angle A + \\angle B = 180^{\\circ}\\]
+ Эти свойства доказываются через равенство треугольников, на которые диагональ делит параллелограмм.
`);
+
+ html += makeCard('example','Примеры','4.3',`
+ Квадрат, прямоугольник, ромб — это частные случаи параллелограмма.
+ Трапеция — НЕ параллелограмм (только одна пара параллельных сторон).
+ Задача: в параллелограмме $AB = 8$, $BC = 5$. Найти периметр. Решение: $P = 2(8+5) = 26$.
+ Задача: $\\angle A = 65°$. Найти остальные углы. $\\angle C = 65°$, $\\angle B = \\angle D = 115°$.
`);
+
+ /* --- INTERACTIVE 1: SVG-конструктор параллелограмма --- */
+ html += `
+
+
Тащи вершины B и D . Параллелограмм строится автоматически: AB∥CD и BC∥AD. Следи за значениями сторон и углов.
+
+
+
`;
+
+ /* --- INTERACTIVE 2: DnD — какие из фигур параллелограммы --- */
+ html += `
+
+
Разложи фигуры: является ли она параллелограммом (или его частным случаем)?
+
+
+
Проверить Сначала
+
+
`;
+
+ /* --- INTERACTIVE 3: Пошаговое доказательство --- */
+ html += `
+
+
Нажимай «Дальше» — идёт пошаговое доказательство через треугольники.
+
+
+
+ Дальше
+ Сначала
+
+
`;
+
+ /* --- INTERACTIVE 4: Тренажёр --- */
+ html += `
+
+
Задача 1 / 4 Очки: 0
+
+
+
+ Проверить
+ Начать
+
+
+
`;
+
+ /* --- INTERACTIVE 5: Босс §4 --- */
+ html += `
+
+
+5 XP за каждую верную задачу.
+
+
`;
+
+ html += `
+
+
+ Я прочитал §4 (+10 XP)
+
+
`;
+
+ html += secNav('p3','p5');
+ box.innerHTML = html;
+ if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
+
+ /* == INIT: SVG-конструктор параллелограмма == */
+ (function(){
+ const W=380, H=300;
+ let A={x:60,y:220}, B={x:180,y:220}, D={x:100,y:100};
+ function getC(){ return {x:D.x+(B.x-A.x),y:D.y+(B.y-A.y)}; }
+ function dist(a,b){ return Math.hypot(b.x-a.x,b.y-a.y); }
+ function angle(O,P,Q){
+ const ax=P.x-O.x,ay=P.y-O.y,bx=Q.x-O.x,by=Q.y-O.y;
+ return Math.acos(Math.max(-1,Math.min(1,(ax*bx+ay*by)/(Math.hypot(ax,ay)*Math.hypot(bx,by)))))*180/Math.PI;
+ }
+ function redraw(){
+ const C=getC();
+ const vs={A,B,C,D};
+ const pts=[A,B,C,D];
+ let s='';
+ s+=' ';
+ s+=' ';
+ s+=' ';
+ const labels=['A','B','C','D'];
+ const cx=(A.x+B.x+C.x+D.x)/4, cy=(A.y+B.y+C.y+D.y)/4;
+ pts.forEach((v,i)=>{
+ const movable=(i===1||i===3);
+ s+=' ';
+ s+=' ';
+ const lx=v.x+(v.x-cx)*0.25,ly=v.y+(v.y-cy)*0.25;
+ s+=''+labels[i]+' ';
+ });
+ const sides=[['AB',A,B],['BC',B,C],['CD',C,D],['DA',D,A]];
+ sides.forEach(([name,p1,p2])=>{
+ const mx=(p1.x+p2.x)/2,my=(p1.y+p2.y)/2;
+ const d=dist(p1,p2);
+ s+=''+d.toFixed(1)+' ';
+ });
+ s+=' ';
+ const svg=document.createElement('div');
+ svg.innerHTML=s;
+ const svgEl=svg.firstElementChild;
+ document.getElementById('p4-pgram-svg-wrap').innerHTML='';
+ document.getElementById('p4-pgram-svg-wrap').appendChild(svgEl);
+ svgEl.querySelectorAll('.p4-vh').forEach(el=>{
+ el.style.cursor='grab';
+ el.addEventListener('pointerdown',ev=>{
+ if(ev.button!==undefined&&ev.button!==0) return;
+ const vname=el.dataset.v;
+ try{el.setPointerCapture(ev.pointerId);}catch(e){}
+ function onMove(e){
+ const rect=svgEl.getBoundingClientRect();
+ const sx=W/rect.width,sy=H/rect.height;
+ const nx=Math.max(10,Math.min(W-10,(e.clientX-rect.left)*sx));
+ const ny=Math.max(10,Math.min(H-10,(e.clientY-rect.top)*sy));
+ if(vname==='B') B={x:nx,y:ny};
+ else if(vname==='D') D={x:nx,y:ny};
+ redraw(); updateInfo();
+ }
+ function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp); }
+ el.addEventListener('pointermove',onMove);
+ el.addEventListener('pointerup',onUp);
+ el.addEventListener('pointercancel',onUp);
+ });
+ });
+ updateInfo();
+ }
+ function updateInfo(){
+ const C=getC();
+ const ab=dist(A,B),bc=dist(B,C),angA=angle(A,D,B),angB=angle(B,A,C);
+ document.getElementById('p4-pgram-info').innerHTML=`
+
+
+ ∠A = ∠C
${angA.toFixed(1)}°
+ ∠A + ∠B
${(angA+angB).toFixed(1)}° `;
+ }
+ redraw();
+ })();
+
+ /* == INIT: DnD параллелограмм или нет == */
+ (function(){
+ const items=[
+ {id:'rect', html:'Прямоугольник', ans:'yes'},
+ {id:'rhombus',html:'Ромб', ans:'yes'},
+ {id:'square', html:'Квадрат', ans:'yes'},
+ {id:'pgram', html:'Произвольный параллелограмм', ans:'yes'},
+ {id:'trap', html:'Трапеция', ans:'no'},
+ {id:'kite', html:'Дельтоид (воздушный змей)', ans:'no'},
+ {id:'arb4', html:'Произвольный четырёхугольник', ans:'no'},
+ {id:'tri', html:'Треугольник', ans:'no'},
+ ];
+ const sorter=setupSorter({poolId:'p4-dnd-pool',scopeSelector:'#p4-dnd-wrap',items,cats:['yes','no']});
+ document.getElementById('p4-dnd-reset').addEventListener('click',()=>{ sorter.reset(); document.getElementById('p4-dnd-fb').style.display='none'; });
+ document.getElementById('p4-dnd-check').addEventListener('click',()=>{
+ let ok=0;
+ items.forEach(it=>{ if(sorter.placed[it.id]===it.ans) ok++; });
+ const fb=document.getElementById('p4-dnd-fb');
+ if(ok===items.length){ feedback(fb,true,'Все '+items.length+' фигур верно! +5 XP'); addXp(5,'p4-dnd'); bumpProgress('p4',15); }
+ else feedback(fb,false,'Верно: '+ok+' из '+items.length+'. Прямоугольник, ромб, квадрат — частные случаи параллелограмма.');
+ });
+ })();
+
+ /* == INIT: Пошаговое доказательство == */
+ (function(){
+ const steps=[
+ { text:'Дано: $ABCD$ — параллелограмм, $AB \\parallel CD$, $BC \\parallel AD$. Проведём диагональ $AC$.', highlight:'' },
+ { text:'Шаг 1. $AB \\parallel CD$ и $AC$ — секущая. По свойству параллельных прямых: $\\angle BAC = \\angle DCA$ (накрест лежащие углы).', highlight:'diag' },
+ { text:'Шаг 2. $BC \\parallel AD$ и $AC$ — секущая. Аналогично: $\\angle BCA = \\angle DAC$ (накрест лежащие углы).', highlight:'diag' },
+ { text:'Шаг 3. $AC$ — общая сторона треугольников $\\triangle ABC$ и $\\triangle CDA$. По признаку «угол-сторона-угол»: $\\triangle ABC = \\triangle CDA$.', highlight:'both' },
+ { text:'Вывод. Из равенства треугольников следует: $AB = CD$ и $BC = DA$. Противоположные стороны параллелограмма равны. $\\square$', highlight:'both' },
+ ];
+ let step=0;
+ const W=300,H=200;
+ function drawProof(highlight){
+ const A={x:30,y:160},B={x:180,y:160},C={x:260,y:50},D={x:110,y:50};
+ const cx=(A.x+B.x+C.x+D.x)/4;
+ let s='';
+ const t1fill=highlight==='diag'||highlight==='both'?'rgba(220,38,38,.15)':'rgba(220,38,38,.07)';
+ const t2fill=highlight==='both'?'rgba(16,185,129,.15)':'rgba(220,38,38,.07)';
+ s+=' ';
+ if(highlight){
+ s+=' ';
+ s+=' ';
+ s+=' ';
+ }
+ ['A','B','C','D'].forEach((lbl,i)=>{
+ const v=[A,B,C,D][i];
+ s+=' ';
+ const lx=v.x+(v.x-cx)*0.28,ly=v.y+(v.y-cy)*0.28;
+ s+=''+lbl+' ';
+ });
+ s+=' ';
+ document.getElementById('p4-proof-svg').innerHTML=s;
+ }
+ function showStep(){
+ const st=steps[step];
+ document.getElementById('p4-proof-step').innerHTML=st.text;
+ renderMath(document.getElementById('p4-proof-step'));
+ drawProof(st.highlight);
+ document.getElementById('p4-proof-next').textContent=step{
+ if(step{ step=0; showStep(); document.getElementById('p4-proof-next').disabled=false; document.getElementById('p4-proof-next').textContent='Дальше'; });
+ showStep();
+ })();
+
+ /* == INIT: Тренажёр задач == */
+ (function(){
+ const tasks=[
+ { q:'В параллелограмме AB = 11 , BC = 7 . Найди периметр.', ans:36, hint:'P=2(AB+BC)=2(11+7)=36' },
+ { q:'В параллелограмме ∠A = 72° . Найди ∠B (смежный угол).', ans:108, hint:'∠A+∠B=180°, ∠B=108°' },
+ { q:'В параллелограмме ∠A = 72° . Найди ∠C (противоположный).', ans:72, hint:'∠A=∠C в параллелограмме' },
+ { q:'Периметр параллелограмма равен 56 , одна сторона равна 18 . Найди вторую сторону.', ans:10, hint:'2(18+x)=56, x=10' },
+ ];
+ let idx=0,score=0;
+ function show(){
+ document.getElementById('p4-tr-i').textContent=idx+1;
+ document.getElementById('p4-tr-task').innerHTML=tasks[idx].q;
+ document.getElementById('p4-tr-ans').value='';
+ document.getElementById('p4-tr-fb').style.display='none';
+ }
+ document.getElementById('p4-tr-start').addEventListener('click',()=>{ idx=0;score=0;document.getElementById('p4-tr-score').textContent=0;show(); });
+ document.getElementById('p4-tr-go').addEventListener('click',()=>{
+ const ans=+document.getElementById('p4-tr-ans').value;
+ const fb=document.getElementById('p4-tr-fb');
+ if(ans===tasks[idx].ans){
+ score++; document.getElementById('p4-tr-score').textContent=score; addXp(3,'p4-train'); bumpProgress('p4',6);
+ if(idxshow(),900); }
+ else{ feedback(fb,true,'Все задачи решены! +5 XP'); addXp(5,'p4-train-all'); bumpProgress('p4',10); }
+ } else feedback(fb,false,'Неверно. Подсказка: '+tasks[idx].hint);
+ });
+ document.getElementById('p4-tr-ans').addEventListener('keydown',e=>{ if(e.key==='Enter') document.getElementById('p4-tr-go').click(); });
+ show();
+ })();
+
+ /* == INIT: Босс §4 == */
+ (function(){
+ const tasks=[
+ { q:'В параллелограмме $AB = 13$, $BC = 9$. Найди периметр.', ans:44, hint:'P=2(13+9)=44' },
+ { q:'В параллелограмме $\\angle A = 55°$. Найди $\\angle D$ (смежный с $\\angle A$).', ans:125, hint:'∠A+∠D=180°, ∠D=125°' },
+ { q:'В параллелограмме $\\angle B = 130°$. Найди $\\angle A$.', ans:50, hint:'∠A+∠B=180°, ∠A=50°' },
+ { q:'Периметр параллелограмма равен 80, одна сторона = 25. Найди вторую сторону.', ans:15, hint:'2(25+x)=80, x=15' },
+ ];
+ const bossBox=document.getElementById('p4-boss-tasks');
+ bossBox.innerHTML=tasks.map((t,i)=>`
+
+
${t.q}
+
+
+ Проверить
+
+
+
`).join('');
+ window.p4BossSolved=new Set();
+ })();
+ renderMath(box);
+}
function buildP5stub(){ document.getElementById('p5-body').innerHTML = '§5 — Волна 1 : содержимое появится в следующем обновлении.
' + secNav('p4','p6'); }
function buildP6stub(){ document.getElementById('p6-body').innerHTML = '§6 — Волна 1 : содержимое появится в следующем обновлении.
' + secNav('p5','p7'); }
function buildP7stub(){ document.getElementById('p7-body').innerHTML = '§7 — Волна 1 : содержимое появится в следующем обновлении.
' + secNav('p6','p8'); }