diff --git a/frontend/textbooks/geometry_9_ch2.html b/frontend/textbooks/geometry_9_ch2.html index 50689b7..9c420ad 100644 --- a/frontend/textbooks/geometry_9_ch2.html +++ b/frontend/textbooks/geometry_9_ch2.html @@ -1049,19 +1049,516 @@ function buildP8(){ wireReadBtn('p8'); } -function buildP9(){ _stubBuilder('p9', '§9', 'Вписанные и описанные четырёхугольники', 'p8', 'final2'); } - -function buildFinal2(){ - const body = document.getElementById('final2-body'); +/* ===== §9 Вписанные и описанные четырёхугольники ===== */ +function buildP9(){ + const box = document.getElementById('p9-body'); let html = ''; - html += makeCard('theory', 'Финал главы 2', '★', ` -

Итоговый раздел главы «Окружности» будет добавлен в следующих обновлениях.

-

Раздел Phase 7.

`); - html += readButton('final2'); + + html += makeCard('theory', 'Вписанный четырёхугольник', '9.1', ` +

Четырёхугольник вписан в окружность, если все его четыре вершины лежат на этой окружности.

+

Критерий вписанности: четырёхугольник вписан в окружность тогда и только тогда, когда сумма его противоположных углов равна $180°$:

+ $$\\alpha + \\gamma = 180°, \\qquad \\beta + \\delta = 180°$$ +

где $\\alpha, \\beta, \\gamma, \\delta$ — углы при последовательных вершинах $A, B, C, D$.

+
Какие фигуры всегда вписаны?
+ Прямоугольник всегда можно вписать в окружность: его диагональ — диаметр (углы по 90°, $90+90=180$). Произвольный параллелограмм — нельзя: его противоположные углы равны, и сумма $180°$ возможна только если все углы прямые — то есть только прямоугольник. +
`); + + html += makeCard('rule', 'Описанный четырёхугольник', '9.2', ` +

Четырёхугольник описан около окружности, если все его четыре стороны касаются окружности.

+

Критерий описанности: четырёхугольник описан около окружности тогда и только тогда, когда суммы его противоположных сторон равны:

+ $$a + c = b + d$$ +

где $a, b, c, d$ — последовательные стороны $AB, BC, CD, DA$.

+

Квадрат и ромб всегда описаны около окружности (центр — точка пересечения диагоналей). Произвольный прямоугольник — нет (только квадрат).

`); + + html += makeCard('example', 'Свойства и примеры', '9.3', ` + `); + + /* IV1 — Вписанный четырёхугольник (SVG) */ + html += `
+
ИНТЕРАКТИВ 1
Вписанный четырёхугольник
+
Перемещай вершины $A, B, C, D$ по окружности — они всегда останутся на ней. Проверь, что $\\alpha + \\gamma = 180°$ и $\\beta + \\delta = 180°$.
+
+ + + + +
+
+ +
+
+
`; + + /* IV2 — Калькулятор сторон описанного */ + html += `
+
ИНТЕРАКТИВ 2
Калькулятор 4-й стороны
+
Введи три последовательные стороны описанного четырёхугольника $a, b, c$ — программа найдёт $d$ из условия $a + c = b + d$.
+
+ $a$ = + + $b$ = + + $c$ = + + +
+
+
+
`; + + /* IV3 — «Вписан или описан?» */ + html += `
+
ИНТЕРАКТИВ 3
Вписан или описан?
+
Дана фигура — определи, можно ли её вписать в окружность, описать около окружности — или и то, и то.
+
Задача 1 / 6Очки: 0 / 6
+
+
+ + + +
+
+
`; + + /* IV4 — Тренажёр */ + html += `
+
ИНТЕРАКТИВ 4
Тренажёр
+
Реши задачу и введи число (целое или с десятичной точкой).
+
Задача 1 / 6Очки: 0 / 6
+
+
+ ответ = + + + +
+
+
`; + + html += secNav('p8', 'final2'); + html += readButton('p9'); + + box.innerHTML = html; + renderMath(box); + + /* IV1 — Вписанный четырёхугольник */ + (function(){ + const sA=document.getElementById('p9-iv1-a'); + const sB=document.getElementById('p9-iv1-b'); + const sC=document.getElementById('p9-iv1-c'); + const sD=document.getElementById('p9-iv1-d'); + const lA=document.getElementById('p9-iv1-aval'); + const lB=document.getElementById('p9-iv1-bval'); + const lC=document.getElementById('p9-iv1-cval'); + const lD=document.getElementById('p9-iv1-dval'); + const svg=document.getElementById('p9-iv1-svg'); + const out=document.getElementById('p9-iv1-out'); + const seen=new Set(); + const cx=190, cy=190, R=140; + function pt(angDeg){ + const a = deg2rad(angDeg); + return { x: cx + R*Math.cos(a), y: cy - R*Math.sin(a) }; + } + function interiorAngle(prev, cur, next){ + // Угол при cur между сторонами cur->prev и cur->next + const v1 = unitVec(cur, prev); + const v2 = unitVec(cur, next); + let cos = v1.x*v2.x + v1.y*v2.y; + if(cos>1) cos=1; if(cos<-1) cos=-1; + return Math.acos(cos) * 180 / Math.PI; + } + function draw(){ + const aA=+sA.value, aB=+sB.value, aC=+sC.value, aD=+sD.value; + lA.textContent=aA; lB.textContent=aB; lC.textContent=aC; lD.textContent=aD; + const A=pt(aA), B=pt(aB), C=pt(aC), D=pt(aD); + const sides={ + AB:Math.hypot(A.x-B.x,A.y-B.y), + BC:Math.hypot(B.x-C.x,B.y-C.y), + CD:Math.hypot(C.x-D.x,C.y-D.y), + DA:Math.hypot(D.x-A.x,D.y-A.y) + }; + const angA=interiorAngle(D,A,B); + const angB=interiorAngle(A,B,C); + const angC=interiorAngle(B,C,D); + const angD=interiorAngle(C,D,A); + + let s=''; + s += ''; + // Окружность + s += ''; + // Центр + s += ''; + s += 'O'; + // Четырёхугольник + s += ''; + // Вершины + const labs=[{p:A,n:'A',ang:aA},{p:B,n:'B',ang:aB},{p:C,n:'C',ang:aC},{p:D,n:'D',ang:aD}]; + labs.forEach(L=>{ + s += ''; + // подпись наружу + const ra=deg2rad(L.ang); + const lx=cx + (R+18)*Math.cos(ra); + const ly=cy - (R+18)*Math.sin(ra); + s += ''+L.n+''; + }); + svg.innerHTML=s; + + const sumAC=angA+angC, sumBD=angB+angD; + const okAC=Math.abs(sumAC-180)<0.5; + const okBD=Math.abs(sumBD-180)<0.5; + let info = 'Углы: $\\alpha = '+angA.toFixed(1)+'°$, $\\beta = '+angB.toFixed(1)+'°$, $\\gamma = '+angC.toFixed(1)+'°$, $\\delta = '+angD.toFixed(1)+'°$
' + + '$\\alpha + \\gamma = '+sumAC.toFixed(1)+'°$  ·  $\\beta + \\delta = '+sumBD.toFixed(1)+'°$'; + if(okAC && okBD) info += '
✓ Это вписанный четырёхугольник!'; + out.innerHTML=info; + renderMath(out); + seen.add(aA+'|'+aB+'|'+aC+'|'+aD); + if(seen.size>=4 && !seen.has('done')){ addXp(10,'p9-iv1'); bumpProgress('p9',15); seen.add('done'); } + } + [sA,sB,sC,sD].forEach(s=>s.addEventListener('input', draw)); + draw(); + })(); + + /* IV2 — Калькулятор 4-й стороны */ + (function(){ + const aI=document.getElementById('p9-iv2-a'); + const bI=document.getElementById('p9-iv2-b'); + const cI=document.getElementById('p9-iv2-c'); + const go=document.getElementById('p9-iv2-go'); + const out=document.getElementById('p9-iv2-out'); + const fb=document.getElementById('p9-iv2-fb'); + let solved=0; + function calc(){ + const a=parseFloat(aI.value), b=parseFloat(bI.value), c=parseFloat(cI.value); + if(!isFinite(a)||!isFinite(b)||!isFinite(c)){ feedback(fb,false,'✗ Введи три числа.'); return; } + if(a<=0||b<=0||c<=0){ feedback(fb,false,'✗ Стороны должны быть положительными.'); return; } + const d = a + c - b; + if(d<=0){ + out.innerHTML = '$a + c = b + d \\Rightarrow d = a + c - b = '+a+' + '+c+' - '+b+' = '+fmt(d)+'$'; + renderMath(out); + feedback(fb,false,'✗ Не существует описанного четырёхугольника с такими сторонами: $d \\le 0$.'); + return; + } + out.innerHTML = '$a + c = b + d$
' + + '$d = a + c - b = '+a+' + '+c+' - '+b+' = '+fmt(d)+'$
' + + '4-я сторона: $d = '+fmt(d)+'$'; + renderMath(out); + feedback(fb,true,'✓ Готово!'); + solved++; + if(solved===1){ addXp(10,'p9-iv2'); bumpProgress('p9',15); } + } + go.addEventListener('click', calc); + })(); + + /* IV3 — Quickfire «Вписан или описан?» */ + (function(){ + const Q=[ + {t:'Квадрат.', a:'both'}, + {t:'Прямоугольник (не квадрат).', a:'in'}, + {t:'Ромб (не квадрат).', a:'out'}, + {t:'Трапеция, у которой суммы противоположных углов равны $180°$.', a:'in'}, + {t:'Четырёхугольник со сторонами $3, 5, 7, 5$ (по порядку).', a:'out'}, + {t:'Четырёхугольник с углами $90°, 80°, 90°, 100°$ (по порядку).', a:'in'} + ]; + const explain={ + in:'Вписан: $\\alpha + \\gamma = 180°$.', + out:'Описан: $a + c = b + d$.', + both:'И вписан, и описан (правильный четырёхугольник).' + }; + const qBox=document.getElementById('p9-iv3-q'); + const iEl=document.getElementById('p9-iv3-i'); + const sEl=document.getElementById('p9-iv3-s'); + const fb=document.getElementById('p9-iv3-fb'); + const btns=document.querySelectorAll('#p9-iv3 button[data-ans]'); + let i=0, score=0, done=false; + function show(){ + if(i>=Q.length){ + qBox.innerHTML='Завершено! Очки: '+score+' / '+Q.length; + if(!done){ done=true; addXp(15,'p9-iv3'); bumpProgress('p9',25); if(score===Q.length) achievement('p9_done'); } + btns.forEach(b=>b.disabled=true); + return; + } + qBox.innerHTML=Q[i].t; renderMath(qBox); + iEl.textContent=(i+1); sEl.textContent=score; + fb.style.display='none'; + } + btns.forEach(b=>b.addEventListener('click', ()=>{ + const ok = b.dataset.ans===Q[i].a; + if(ok) score++; + feedback(fb, ok, ok?('✓ Верно! '+explain[Q[i].a]):('✗ Правильный ответ: '+({in:'Вписан',out:'Описан',both:'И то, и то'}[Q[i].a])+'. '+explain[Q[i].a])); + i++; + setTimeout(show, 900); + })); + show(); + })(); + + /* IV4 — Тренажёр */ + (function(){ + const Q=[ + {t:'Во вписанном 4-уг. углы $\\angle A = 75°$, $\\angle B = 110°$. Найди $\\angle C$.', a:105}, + {t:'Во вписанном 4-уг. углы $\\angle A = 90°$, $\\angle B = 95°$. Найди $\\angle D$.', a:85}, + {t:'В описанном 4-уг. стороны $a=4$, $b=6$, $c=8$. Найди $d$.', a:6}, + {t:'В описанном 4-уг. стороны $a=5$, $b=7$, $c=9$. Найди $d$.', a:7}, + {t:'Сумма противоположных углов вписанного четырёхугольника равна …', a:180}, + {t:'Параллелограмм вписан в окружность. Чему равны его углы (в градусах)?', a:90} + ]; + const qBox=document.getElementById('p9-iv4-q'); + const ans=document.getElementById('p9-iv4-ans'); + const go=document.getElementById('p9-iv4-go'); + const reset=document.getElementById('p9-iv4-start'); + const iEl=document.getElementById('p9-iv4-i'); + const sEl=document.getElementById('p9-iv4-s'); + const fb=document.getElementById('p9-iv4-fb'); + let i=0, score=0, done=false; + function show(){ + if(i>=Q.length){ + qBox.innerHTML='Финиш! Очки: '+score+' / '+Q.length; + if(!done){ done=true; addXp(15,'p9-iv4'); bumpProgress('p9',25); } + go.disabled=true; ans.disabled=true; + return; + } + qBox.innerHTML=Q[i].t; renderMath(qBox); + iEl.textContent=(i+1); sEl.textContent=score; + ans.value=''; fb.style.display='none'; go.disabled=false; ans.disabled=false; + } + go.addEventListener('click', ()=>{ + const v=parseFloat((ans.value||'').replace(',', '.')); + if(!isFinite(v)){ feedback(fb,false,'✗ Введи число.'); return; } + const ok=Math.abs(v-Q[i].a)<0.05; + if(ok) score++; + feedback(fb, ok, ok?'✓ Верно!':'✗ Правильный ответ: $'+Q[i].a+'$'); + i++; + setTimeout(show, 900); + }); + reset.addEventListener('click', ()=>{ i=0; score=0; done=false; show(); }); + show(); + })(); + + wireReadBtn('p9'); +} + +/* ===== Финал главы 2 ===== */ +function buildFinal2(){ + const box = document.getElementById('final2-body'); + let html = ''; + + /* Часть А — Шпаргалка главы (3 mini-карточки) */ + html += `
+
+
${ICONS.theory}
+
Шпаргалка главы 2
+
Итог
+
+
+

Ключевые формулы и критерии главы «Окружности» — в одном месте. Просмотри перед боссами!

+
+
+
+ + § 7 · Окружности треугольника +
+
Описанная — пересечение серединных $\\perp$, $R = \\dfrac{abc}{4S}$. Вписанная — пересечение биссектрис, $r = \\dfrac{S}{p}$.
+
+
+
+ + § 8 · Прямоугольный $\\triangle$ +
+
$R = \\dfrac{c}{2}$ — центр на середине гипотенузы. $r = \\dfrac{a + b - c}{2}$.
+
+
+
+ + § 9 · Четырёхугольники +
+
Вписан $\\Leftrightarrow$ $\\alpha + \\gamma = 180°$. Описан $\\Leftrightarrow$ $a + c = b + d$.
+
+
+
+
`; + + /* Часть Б — 5 боссов */ + html += `
+
+
${ICONS.rule}
+
Боссы главы 2
+
5
+
+
+

5 интегрированных задач — каждая комбинирует темы §§7–9. За каждого побеждённого босса — +10 XP и +18% к прогрессу. Победишь всех — +50 XP бонус и ачивка «Магистр окружностей»!

+
+
`; + + html += '
'; + + html += `
+
Прогресс по боссам
+
0 / 5 боссов побеждено
+
+
+
+ +
`; + html += secNav('p9', null); - body.innerHTML = html; - wireReadBtn('final2'); - if(window.renderMathInElement) renderMath(body); + + box.innerHTML = html; + renderMath(box); + + /* Боссы */ + const BOSSES = [ + { + n:1, color:'#10b981', + title:'Циклоп Окружностей', + tag:'§ 8 + § 7', + q:'В прямоугольном треугольнике катеты $a = 6$ и $b = 8$. Найди радиус описанной окружности.', + ans:5, decimal:false, + hint:'Гипотенуза $c = \\sqrt{6^2 + 8^2} = 10$. $R = \\dfrac{c}{2} = 5$.' + }, + { + n:2, color:'#0891b2', + title:'Минотавр Вписанной', + tag:'§ 8 + § 7', + q:'В прямоугольном треугольнике катеты $a = 9$ и $b = 12$. Найди радиус вписанной окружности.', + ans:3, decimal:false, + hint:'Гипотенуза $c = \\sqrt{81+144} = 15$. $r = \\dfrac{a + b - c}{2} = \\dfrac{9 + 12 - 15}{2} = 3$.' + }, + { + n:3, color:'#7c3aed', + title:'Гарпия 4-угольников', + tag:'§ 9', + q:'Во вписанном четырёхугольнике углы $\\angle A = 65°$ и $\\angle B = 95°$. Найди сумму $\\angle C + \\angle D$ в градусах.', + ans:200, decimal:false, + hint:'$\\angle C = 180° - \\angle A = 115°$, $\\angle D = 180° - \\angle B = 85°$. Сумма $= 115 + 85 = 200°$.' + }, + { + n:4, color:'#dc2626', + title:'Дракон Окружности', + tag:'§ 7 + § 9', + q:'В равностороннем треугольнике со стороной $a = 6$ проведена описанная окружность. Найди её радиус $R$ (округли до 2 знаков).', + ans:3.46, decimal:true, + hint:'Для равностороннего $R = \\dfrac{a}{\\sqrt{3}} = \\dfrac{6}{\\sqrt{3}} = 2\\sqrt{3} \\approx 3{,}46$.' + }, + { + n:5, color:'#f59e0b', + title:'Мастер Окружностей', + tag:'§§ 7-9 — синтез', + q:'В описанном четырёхугольнике стороны последовательно равны $5, 7, x, 4$. Найди $x$.', + ans:6, decimal:false, + hint:'$a + c = b + d \\Rightarrow 5 + x = 7 + 4 \\Rightarrow x = 6$.' + } + ]; + + const cont = document.getElementById('ch2G-bosses-container'); + const STATE_KEY = 'geometry9_ch2_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)=>{ + const stepAttr = b.decimal ? 'step="0.01"' : 'step="1"'; + const ph = b.decimal ? 'число (можно с запятой)' : 'целое число'; + return '
' + +'
' + +'' + +'
Босс '+b.n+': '+b.title+'
' + +'
'+b.tag+'
' + +'
' + +'
'+b.q+'
' + +'
' + +'ответ =' + +'' + +'' + +'' + +'
' + +'' + +'
'; + }).join(''); + renderMath(cont); + + function markDefeatedUI(b){ + const card = document.getElementById('bossG2-'+b.n+'-card'); + const goBtn = document.getElementById('bossG2-'+b.n+'-go'); + const ansInp = document.getElementById('bossG2-'+b.n+'-ans'); + if(!card || !goBtn || !ansInp) return; + card.style.background = 'linear-gradient(135deg,var(--acc-soft),var(--pri-soft))'; + card.style.boxShadow = '0 0 0 2px '+b.color+'33, 0 8px 24px rgba(16,185,129,.12)'; + goBtn.disabled = true; goBtn.style.opacity = .55; + goBtn.innerHTML = ' Повержен'; + ansInp.disabled = true; + } + + function refreshOverall(){ + const won = BOSS_STATE.filter(s => s.defeated).length; + const txt = document.getElementById('ch2G-boss-overall'); + const fill = document.getElementById('ch2G-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('ch2G-final-reward'); + if(reward && reward.style.display === 'none'){ + reward.style.display = 'block'; + if(!STATE.achievements.has('ch2_done')){ + achievement('ch2_done','Магистр окружностей'); + addXp(50, 'ch2-bonus'); + bumpProgress('final2', 10); + if(window.confetti){ try{ window.confetti(); }catch(e){} } + } + } + } + } + + BOSSES.forEach((b, idx)=>{ + const goBtn = document.getElementById('bossG2-'+b.n+'-go'); + const hintBtn = document.getElementById('bossG2-'+b.n+'-hint'); + const ansInp = document.getElementById('bossG2-'+b.n+'-ans'); + if(BOSS_STATE[idx].defeated) markDefeatedUI(b); + goBtn.addEventListener('click', ()=>{ + if(BOSS_STATE[idx].defeated) return; + const fb = document.getElementById('bossG2-'+b.n+'-fb'); + const raw = (ansInp.value||'').replace(',', '.').trim(); + const val = parseFloat(raw); + if(isNaN(val) || raw === ''){ feedback(fb, false, '✗ Введи число.'); return; } + const ok = Math.abs(val - b.ans) < 0.05; + if(ok){ + BOSS_STATE[idx].defeated = true; saveBosses(); + feedback(fb, true, '✓ Босс '+b.n+' повержен! +10 XP. '+b.hint); + addXp(10, 'boss-ch2-'+b.n); + bumpProgress('final2', 18); + markDefeatedUI(b); + refreshOverall(); + } else { + feedback(fb, false, '✗ Промах. Попробуй ещё. Подсказка доступна.'); + } + }); + hintBtn.addEventListener('click', ()=>{ + const fb = document.getElementById('bossG2-'+b.n+'-fb'); + fb.className = 'feedback ok'; + fb.innerHTML = 'Подсказка: '+b.hint; + fb.style.display = 'block'; + fb.style.background = 'var(--warn-bg)'; + fb.style.color = '#92400e'; + fb.style.borderLeftColor = 'var(--warn)'; + renderMath(fb); + }); + ansInp.addEventListener('keydown', e=>{ if(e.key === 'Enter') goBtn.click(); }); + }); + + refreshOverall(); } /* ===== Search ===== */