feat(geom11 ch2 wave1): §3 «Пирамида» + 3D + калькулятор
This commit is contained in:
@@ -392,7 +392,7 @@ function buildParaSelector(){
|
||||
}
|
||||
|
||||
const BUILT=new Set();
|
||||
const BUILDERS = { p3:()=>buildStub('p3'), p4:()=>buildStub('p4'), final2:()=>buildStub('final2') };
|
||||
const BUILDERS = { p3:buildP3, p4:()=>buildStub('p4'), final2:()=>buildStub('final2') };
|
||||
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);
|
||||
@@ -407,13 +407,22 @@ function goTo(id){
|
||||
}
|
||||
|
||||
const SIDEBARS = {
|
||||
p3:{title:"Шпаргалка § 3", rows:[["Тема", "Пирамида"],["Формула","$V=\\\\frac{1}{3}S_{осн}h$"]]},
|
||||
p3:{title:"Шпаргалка § 3", rows:[
|
||||
["Пирамида", "основание + апекс"],
|
||||
["Правильная","основание — правильный многоугольник; высота в центре основания"],
|
||||
["Апофема $l$","высота боковой грани"],
|
||||
["Объём","$V=\\\\dfrac{1}{3}S_{осн}\\\\cdot h$"],
|
||||
["$S_{бок}$ (правильной)","$\\\\dfrac{1}{2}P_{осн}\\\\cdot l$"],
|
||||
["Боковое ребро","$b=\\\\sqrt{R^2+h^2}$"],
|
||||
["Апофема","$l=\\\\sqrt{r^2+h^2}$"],
|
||||
["Усечённая","$V=\\\\dfrac{h}{3}(S_1+S_2+\\\\sqrt{S_1 S_2})$"]
|
||||
]},
|
||||
p4:{title:"Шпаргалка § 4", rows:[["Тема", "Конус"],["Формула","$S_{бок}=\\\\pi Rl$"]]},
|
||||
final2:{title:"Финал раздела 2", rows:[["§ 3–§ 4","теория раздела 2"],["Награда","+50 XP"]]}
|
||||
};
|
||||
|
||||
const TIPS=[
|
||||
{sec:'p3',html:"§ 3 «Пирамида» — содержание в разработке. $V=\\\\\\\\frac{1}{3}S_{осн}h$"},
|
||||
{sec:'p3',html:"Главное правило: <b>$V=\\\\\\\\dfrac{1}{3}S_{осн}h$</b> для <i>любой</i> пирамиды. А для правильной — $S_{бок}=\\\\\\\\dfrac{1}{2}P_{осн}l$, где $l$ — апофема."},
|
||||
{sec:'p4',html:"§ 4 «Конус» — содержание в разработке. $S_{бок}=\\\\\\\\pi Rl$"},
|
||||
{sec:'final2',html:"Финал раздела 2 — интегрированные задачи по разделу."}
|
||||
];
|
||||
@@ -619,6 +628,364 @@ function wireReadBtn(paraId){
|
||||
});
|
||||
}
|
||||
|
||||
/* ===== § 3 «Пирамида» — Wave 1 ===== */
|
||||
|
||||
function buildP3(){
|
||||
const box = document.getElementById('p3-body');
|
||||
if(!box) return;
|
||||
let html = '';
|
||||
|
||||
/* === ТЕОРИЯ === */
|
||||
|
||||
html += makeCard('theory', 'Определение и виды', '§ 3.1',
|
||||
'<p><b>Пирамида</b> — многогранник, у которого одна грань (<b>основание</b>) — многоугольник, а остальные грани (<b>боковые</b>) — треугольники с общей вершиной.</p>'
|
||||
+ '<p><b>Элементы пирамиды:</b></p>'
|
||||
+ '<ul style="margin:6px 0 10px 22px;line-height:1.7">'
|
||||
+ '<li><b>Основание</b> — многоугольник.</li>'
|
||||
+ '<li><b>Вершина пирамиды</b> (апекс) — общая точка боковых граней.</li>'
|
||||
+ '<li><b>Боковые грани</b> — треугольники.</li>'
|
||||
+ '<li><b>Боковые рёбра</b> — отрезки от апекса к вершинам основания.</li>'
|
||||
+ '<li><b>Высота</b> $h$ — перпендикуляр из апекса к плоскости основания.</li>'
|
||||
+ '</ul>'
|
||||
+ '<p><b>Правильная пирамида</b> — пирамида, у которой:</p>'
|
||||
+ '<ul style="margin:6px 0 10px 22px;line-height:1.7">'
|
||||
+ '<li>Основание — <b>правильный</b> многоугольник.</li>'
|
||||
+ '<li>Высота попадает в <b>центр основания</b>.</li>'
|
||||
+ '</ul>'
|
||||
+ '<p>Тогда автоматически выполняются <b>следствия:</b> все боковые рёбра равны, а боковые грани — равные равнобедренные треугольники.</p>'
|
||||
+ '<p><b>Апофема</b> $l$ — высота боковой грани, опущенная из апекса к середине стороны основания. У правильной пирамиды все апофемы равны.</p>');
|
||||
|
||||
html += makeCard('rule', 'Площадь и объём', '§ 3.2',
|
||||
'<p><b>Объём</b> (для любой пирамиды):</p>'
|
||||
+ '<p style="text-align:center;margin:8px 0">$$V=\\dfrac{1}{3}\\,S_{осн}\\cdot h$$</p>'
|
||||
+ '<p><b>Боковая поверхность правильной пирамиды:</b></p>'
|
||||
+ '<p style="text-align:center;margin:8px 0">$$S_{бок}=\\dfrac{1}{2}\\,P_{осн}\\cdot l$$</p>'
|
||||
+ '<p>где $l$ — апофема, $P_{осн}$ — периметр основания.</p>'
|
||||
+ '<p><b>Полная поверхность:</b> $S_{полн}=S_{бок}+S_{осн}$.</p>'
|
||||
+ '<p style="margin-top:10px"><b>Связь между элементами правильной $n$-угольной пирамиды.</b> Пусть $R$ — радиус описанной около основания окружности, $r$ — радиус вписанной, $b$ — боковое ребро, $l$ — апофема, $h$ — высота. Тогда:</p>'
|
||||
+ '<ul style="margin:6px 0 10px 22px;line-height:1.7">'
|
||||
+ '<li>$b^2=R^2+h^2$ — теорема Пифагора в треугольнике «апекс — центр — вершина основания».</li>'
|
||||
+ '<li>$l^2=r^2+h^2$ — теорема Пифагора в треугольнике «апекс — центр — середина стороны».</li>'
|
||||
+ '</ul>'
|
||||
+ '<details class="spoiler"><summary>Пример: правильная 4-угольная пирамида $a=6$, $h=4$</summary><div class="spoiler-body">'
|
||||
+ '<p>Основание — квадрат, $r=a/2=3$.</p>'
|
||||
+ '<ul style="margin:6px 0 0 22px;line-height:1.7">'
|
||||
+ '<li>$l=\\sqrt{r^2+h^2}=\\sqrt{9+16}=5$ — апофема.</li>'
|
||||
+ '<li>$S_{осн}=a^2=36$, $P_{осн}=4a=24$.</li>'
|
||||
+ '<li>$S_{бок}=\\dfrac{1}{2}\\cdot 24\\cdot 5=60$.</li>'
|
||||
+ '<li>$S_{полн}=60+36=96$.</li>'
|
||||
+ '<li>$V=\\dfrac{1}{3}\\cdot 36\\cdot 4=48$.</li>'
|
||||
+ '</ul>'
|
||||
+ '</div></details>');
|
||||
|
||||
html += makeCard('example', 'Усечённая пирамида', '§ 3.3',
|
||||
'<p><b>Усечённая пирамида</b> — часть пирамиды, заключённая между основанием и плоскостью, параллельной основанию.</p>'
|
||||
+ '<p>У неё <b>два основания</b> — подобные многоугольники в параллельных плоскостях. Боковые грани — <b>трапеции</b>.</p>'
|
||||
+ '<p><b>Объём усечённой пирамиды:</b></p>'
|
||||
+ '<p style="text-align:center;margin:8px 0">$$V=\\dfrac{1}{3}\\,h\\bigl(S_1+S_2+\\sqrt{S_1 S_2}\\bigr)$$</p>'
|
||||
+ '<p>где $S_1,\\,S_2$ — площади оснований, $h$ — высота (расстояние между плоскостями оснований).</p>'
|
||||
+ '<p><b>Боковая поверхность правильной усечённой пирамиды:</b></p>'
|
||||
+ '<p style="text-align:center;margin:8px 0">$$S_{бок}=\\dfrac{1}{2}(P_1+P_2)\\cdot l$$</p>'
|
||||
+ '<p>где $l$ — апофема (высота боковой трапеции), $P_1,\\,P_2$ — периметры оснований.</p>'
|
||||
+ '<details class="spoiler"><summary>Пример: правильная 4-угольная усечённая, $a_1=6$, $a_2=4$, $h=3$</summary><div class="spoiler-body">'
|
||||
+ '<p>$S_1=36$, $S_2=16$.</p>'
|
||||
+ '<p>Апофема: $l=\\sqrt{h^2+\\left(\\dfrac{a_1-a_2}{2}\\right)^2}=\\sqrt{9+1}=\\sqrt{10}$.</p>'
|
||||
+ '<p>$V=\\dfrac{1}{3}\\cdot 3\\cdot(36+16+\\sqrt{576})=36+16+24=76$.</p>'
|
||||
+ '</div></details>');
|
||||
|
||||
/* === ИНТЕРАКТИВ 1 — 3D-конструктор === */
|
||||
html += '<div class="wg" id="p3-iv1">'
|
||||
+ '<div class="wg-header"><span class="wg-badge">3D · конструктор</span><div class="wg-title">Правильная $n$-угольная пирамида</div></div>'
|
||||
+ '<div class="wg-help">Меняй число сторон основания $n$, радиус описанной окружности $R$ и высоту $h$. Вращай мышью или выбирай вид. После <b>4 разных конфигураций</b> — +10 XP.</div>'
|
||||
+ '<div class="sliders">'
|
||||
+ '<label>$n$ (сторон):<b id="p3-iv1-n-v">4</b><input type="range" id="p3-iv1-n" min="3" max="6" step="1" value="4"></label>'
|
||||
+ '<label>$R$ (радиус):<b id="p3-iv1-R-v">1.8</b><input type="range" id="p3-iv1-R" min="1" max="4" step="0.1" value="1.8"></label>'
|
||||
+ '<label>$h$ (высота):<b id="p3-iv1-h-v">2.6</b><input type="range" id="p3-iv1-h" min="1" max="6" step="0.1" value="2.6"></label>'
|
||||
+ '</div>'
|
||||
+ '<div class="g3d-tools">'
|
||||
+ '<button class="btn" data-view="iso">Изо</button>'
|
||||
+ '<button class="btn" data-view="front">Спереди</button>'
|
||||
+ '<button class="btn" data-view="top">Сверху</button>'
|
||||
+ '<button class="btn" data-view="side">Сбоку</button>'
|
||||
+ '</div>'
|
||||
+ '<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:8px;text-align:center"><svg id="p3-iv1-svg" viewBox="0 0 480 400" width="100%" style="max-width:480px;height:auto"></svg></div>'
|
||||
+ '<div class="score-display" style="margin-top:10px;flex-wrap:wrap">'
|
||||
+ '<span>$a=$<b id="p3-iv1-a">—</b></span>'
|
||||
+ '<span>$r=$<b id="p3-iv1-r">—</b></span>'
|
||||
+ '<span>$P_{осн}=$<b id="p3-iv1-P">—</b></span>'
|
||||
+ '<span>$S_{осн}=$<b id="p3-iv1-So">—</b></span>'
|
||||
+ '<span>$l=$<b id="p3-iv1-l">—</b></span>'
|
||||
+ '<span>$b=$<b id="p3-iv1-b">—</b></span>'
|
||||
+ '<span>$S_{бок}=$<b id="p3-iv1-Sb">—</b></span>'
|
||||
+ '<span>$S_{полн}=$<b id="p3-iv1-St">—</b></span>'
|
||||
+ '<span>$V=$<b id="p3-iv1-V">—</b></span>'
|
||||
+ '</div>'
|
||||
+ '<div style="font-size:.78rem;color:var(--muted);margin-top:6px">Конфигураций изучено: <b id="p3-iv1-cnt">0</b> / 4</div>'
|
||||
+ '</div>';
|
||||
|
||||
/* === ИНТЕРАКТИВ 2 — Калькулятор V и S === */
|
||||
html += '<div class="wg" id="p3-iv2">'
|
||||
+ '<div class="wg-header"><span class="wg-badge">калькулятор</span><div class="wg-title">$V$ и $S_{бок}$ правильной пирамиды</div></div>'
|
||||
+ '<div class="wg-help">Введи $n$ (число сторон основания, $3..8$), сторону $a$ и высоту $h$. Калькулятор покажет пошаговый разбор.</div>'
|
||||
+ '<div class="sliders">'
|
||||
+ '<label>$n$:<b id="p3-iv2-n-v">4</b><input type="range" id="p3-iv2-n" min="3" max="8" step="1" value="4"></label>'
|
||||
+ '<label>$a$ (сторона):<b id="p3-iv2-a-v">6.0</b><input type="range" id="p3-iv2-a" min="1" max="10" step="0.1" value="6"></label>'
|
||||
+ '<label>$h$ (высота):<b id="p3-iv2-h-v">4.0</b><input type="range" id="p3-iv2-h" min="1" max="12" step="0.1" value="4"></label>'
|
||||
+ '</div>'
|
||||
+ '<div class="actions"><button class="btn primary" id="p3-iv2-calc">Вычислить</button></div>'
|
||||
+ '<div id="p3-iv2-out" style="margin-top:10px;font-size:.92rem;line-height:1.7"></div>'
|
||||
+ '</div>';
|
||||
|
||||
/* === ИНТЕРАКТИВ 3 — «Найди элемент» (квикфайр) === */
|
||||
html += '<div class="wg" id="p3-iv3">'
|
||||
+ '<div class="wg-header"><span class="wg-badge">квикфайр · 6 заданий</span><div class="wg-title">Найди элемент пирамиды</div></div>'
|
||||
+ '<div class="wg-help">Читай описание отрезка — выбирай, какой это элемент: высота $h$, апофема $l$ или боковое ребро $b$.</div>'
|
||||
+ '<div id="p3-iv3-list"></div>'
|
||||
+ '<div class="score-display" style="margin-top:10px">Верно: <b id="p3-iv3-score">0</b> / 6</div>'
|
||||
+ '</div>';
|
||||
|
||||
/* === ИНТЕРАКТИВ 4 — Тренажёр V и S === */
|
||||
html += '<div class="wg" id="p3-iv4">'
|
||||
+ '<div class="wg-header"><span class="wg-badge">тренажёр · 6 задач</span><div class="wg-title">$V$, $l$, $S_{бок}$ и усечённая</div></div>'
|
||||
+ '<div class="wg-help">Введи числовой ответ. Допуск $\\pm 0{,}05$ для дробных значений.</div>'
|
||||
+ '<div id="p3-iv4-list"></div>'
|
||||
+ '<div class="score-display" style="margin-top:10px">Решено: <b id="p3-iv4-score">0</b> / 6</div>'
|
||||
+ '</div>';
|
||||
|
||||
html += secNav(null, 'p4');
|
||||
html += readButton('p3');
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
|
||||
/* ====== JS-логика интерактивов ====== */
|
||||
|
||||
/* IV1 — 3D-конструктор */
|
||||
(function(){
|
||||
if(!window.G3D) return;
|
||||
const svg = document.getElementById('p3-iv1-svg');
|
||||
const elN = document.getElementById('p3-iv1-n');
|
||||
const elR = document.getElementById('p3-iv1-R');
|
||||
const elH = document.getElementById('p3-iv1-h');
|
||||
const vN = document.getElementById('p3-iv1-n-v');
|
||||
const vR = document.getElementById('p3-iv1-R-v');
|
||||
const vH = document.getElementById('p3-iv1-h-v');
|
||||
const oA = document.getElementById('p3-iv1-a');
|
||||
const oR = document.getElementById('p3-iv1-r');
|
||||
const oP = document.getElementById('p3-iv1-P');
|
||||
const oSo = document.getElementById('p3-iv1-So');
|
||||
const oL = document.getElementById('p3-iv1-l');
|
||||
const oB = document.getElementById('p3-iv1-b');
|
||||
const oSb = document.getElementById('p3-iv1-Sb');
|
||||
const oSt = document.getElementById('p3-iv1-St');
|
||||
const oV = document.getElementById('p3-iv1-V');
|
||||
const oCnt = document.getElementById('p3-iv1-cnt');
|
||||
if(!svg) return;
|
||||
const scene = G3D.createScene({W:480, H:400, scale:50, camDist:8, rotX:-0.35, rotY:0.7});
|
||||
const seen = new Set();
|
||||
let xpGiven = false;
|
||||
|
||||
function draw(){
|
||||
const n = +elN.value, R = +elR.value, h = +elH.value;
|
||||
vN.textContent = n;
|
||||
vR.textContent = R.toFixed(1);
|
||||
vH.textContent = h.toFixed(1);
|
||||
const mesh = G3D.pyramidMesh(n, R, h);
|
||||
const M = G3D.buildRotMatrix(scene);
|
||||
svg.innerHTML = G3D.renderMesh(mesh, M, scene, {
|
||||
fillBase:'rgba(252,231,243,.55)',
|
||||
fillSide:'rgba(219,234,254,.55)',
|
||||
strokeVisible:'#0f172a',
|
||||
strokeHidden:'#94a3b8'
|
||||
});
|
||||
const a = 2*R*Math.sin(Math.PI/n);
|
||||
const r = R*Math.cos(Math.PI/n);
|
||||
const P = n*a;
|
||||
const So = 0.5*n*R*R*Math.sin(2*Math.PI/n);
|
||||
const l = Math.sqrt(r*r + h*h);
|
||||
const bs = Math.sqrt(R*R + h*h);
|
||||
const Sb = 0.5*P*l;
|
||||
const St = Sb + So;
|
||||
const V = So*h/3;
|
||||
oA.textContent = a.toFixed(2);
|
||||
oR.textContent = r.toFixed(2);
|
||||
oP.textContent = P.toFixed(2);
|
||||
oSo.textContent = So.toFixed(2);
|
||||
oL.textContent = l.toFixed(2);
|
||||
oB.textContent = bs.toFixed(2);
|
||||
oSb.textContent = Sb.toFixed(2);
|
||||
oSt.textContent = St.toFixed(2);
|
||||
oV.textContent = V.toFixed(2);
|
||||
const key = n+'|'+R.toFixed(1)+'|'+h.toFixed(1);
|
||||
seen.add(key);
|
||||
oCnt.textContent = Math.min(seen.size, 4);
|
||||
if(seen.size >= 4 && !xpGiven){
|
||||
xpGiven = true;
|
||||
addXp(10, 'p3-iv1');
|
||||
bumpProgress('p3', 15);
|
||||
const note = document.createElement('div');
|
||||
note.className = 'feedback ok';
|
||||
note.innerHTML = '✓ +10 XP за изучение 4 разных пирамид!';
|
||||
note.style.cssText = 'display:block;margin-top:8px';
|
||||
const host = document.getElementById('p3-iv1');
|
||||
if(host) host.appendChild(note);
|
||||
setTimeout(function(){ try{ note.remove(); }catch(e){} }, 3000);
|
||||
}
|
||||
}
|
||||
draw();
|
||||
G3D.attachOrbit(svg, scene, draw);
|
||||
[elN, elR, elH].forEach(function(el){ el.addEventListener('input', draw); });
|
||||
document.querySelectorAll('#p3-iv1 .g3d-tools .btn').forEach(function(b){
|
||||
b.addEventListener('click', function(){ G3D.presetView(scene, b.dataset.view, draw); });
|
||||
});
|
||||
})();
|
||||
|
||||
/* IV2 — Калькулятор */
|
||||
(function(){
|
||||
const elN = document.getElementById('p3-iv2-n');
|
||||
const elA = document.getElementById('p3-iv2-a');
|
||||
const elH = document.getElementById('p3-iv2-h');
|
||||
const labels = {'p3-iv2-n':'p3-iv2-n-v','p3-iv2-a':'p3-iv2-a-v','p3-iv2-h':'p3-iv2-h-v'};
|
||||
Object.keys(labels).forEach(function(k){
|
||||
const el = document.getElementById(k), lab = document.getElementById(labels[k]);
|
||||
if(!el || !lab) return;
|
||||
const upd = function(){ lab.textContent = el.step === '1' ? el.value : (+el.value).toFixed(1); };
|
||||
el.addEventListener('input', upd); upd();
|
||||
});
|
||||
let xpGiven = false;
|
||||
document.getElementById('p3-iv2-calc').addEventListener('click', function(){
|
||||
const out = document.getElementById('p3-iv2-out');
|
||||
const n = +elN.value, a = +elA.value, h = +elH.value;
|
||||
const r = a / (2*Math.tan(Math.PI/n));
|
||||
const P = n*a;
|
||||
const So = 0.5*P*r;
|
||||
const l = Math.sqrt(r*r + h*h);
|
||||
const Sb = 0.5*P*l;
|
||||
const St = Sb + So;
|
||||
const V = So*h/3;
|
||||
const html2 = '<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:10px 14px">'
|
||||
+ '<p><b>Правильная '+n+'-угольная пирамида: $a='+a.toFixed(2)+'$, $h='+h.toFixed(2)+'$</b></p>'
|
||||
+ '<p>$r=\\dfrac{a}{2\\tan(\\pi/n)}\\approx '+r.toFixed(3)+'$ — радиус вписанной окружности основания.</p>'
|
||||
+ '<p>$P_{осн}=n\\cdot a='+n+'\\cdot '+a.toFixed(2)+'='+P.toFixed(2)+'$</p>'
|
||||
+ '<p>$S_{осн}=\\dfrac{1}{2}P\\cdot r\\approx '+So.toFixed(2)+'$</p>'
|
||||
+ '<p>$l=\\sqrt{r^2+h^2}=\\sqrt{'+(r*r).toFixed(2)+'+'+(h*h).toFixed(2)+'}\\approx '+l.toFixed(3)+'$ — апофема.</p>'
|
||||
+ '<p>$S_{бок}=\\dfrac{1}{2}P_{осн}\\cdot l\\approx '+Sb.toFixed(2)+'$</p>'
|
||||
+ '<p>$S_{полн}=S_{бок}+S_{осн}\\approx '+St.toFixed(2)+'$</p>'
|
||||
+ '<p style="font-weight:700;color:var(--pri2)">$V=\\dfrac{1}{3}S_{осн}\\cdot h\\approx '+V.toFixed(2)+'$</p>'
|
||||
+ '</div>';
|
||||
out.innerHTML = html2;
|
||||
renderMath(out);
|
||||
if(!xpGiven){
|
||||
xpGiven = true;
|
||||
addXp(10, 'p3-iv2');
|
||||
bumpProgress('p3', 15);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
/* IV3 — «Найди элемент» (квикфайр) */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{ q:'Отрезок от апекса к центру основания.', a:'h' },
|
||||
{ q:'Отрезок от апекса к середине стороны основания.', a:'l' },
|
||||
{ q:'Отрезок от апекса к вершине основания.', a:'b' },
|
||||
{ q:'В равнобедренном треугольнике боковой грани — высота к стороне основания.', a:'l' },
|
||||
{ q:'Отрезок из апекса перпендикулярно плоскости основания.', a:'h' },
|
||||
{ q:'Длина отрезка апекс — вершина основания.', a:'b' }
|
||||
];
|
||||
const list = document.getElementById('p3-iv3-list');
|
||||
const scoreEl = document.getElementById('p3-iv3-score');
|
||||
const solved = new Set();
|
||||
let xpGiven = false;
|
||||
const NAMES = {h:'Высота $h$', l:'Апофема $l$', b:'Боковое ребро $b$'};
|
||||
list.innerHTML = tasks.map(function(t, i){
|
||||
return '<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:10px 12px;margin-bottom:8px">'
|
||||
+ '<div style="margin-bottom:8px"><b>Задание '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+ '<div style="display:flex;gap:6px;flex-wrap:wrap">'
|
||||
+ '<button class="btn" data-i="'+i+'" data-v="h">Высота $h$</button>'
|
||||
+ '<button class="btn" data-i="'+i+'" data-v="l">Апофема $l$</button>'
|
||||
+ '<button class="btn" data-i="'+i+'" data-v="b">Боковое ребро $b$</button>'
|
||||
+ '</div>'
|
||||
+ '<div class="feedback" id="p3-iv3-fb-'+i+'"></div>'
|
||||
+ '</div>';
|
||||
}).join('');
|
||||
renderMath(list);
|
||||
list.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('p3-iv3-fb-'+i);
|
||||
if(solved.has(i)) return;
|
||||
if(v === t.a){
|
||||
feedback(fb, true, '✓ Верно — это '+NAMES[t.a]+'.');
|
||||
solved.add(i);
|
||||
scoreEl.textContent = solved.size;
|
||||
if(solved.size === tasks.length && !xpGiven){
|
||||
xpGiven = true;
|
||||
addXp(15, 'p3-iv3');
|
||||
bumpProgress('p3', 25);
|
||||
}
|
||||
} else {
|
||||
feedback(fb, false, '✗ Не то. Подумай ещё раз.');
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
/* IV4 — Тренажёр V и S */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{ q:'Правильная 4-угольная пирамида: $a=6$, $h=4$. $V=\\,?$', a:48, tol:0.05 },
|
||||
{ q:'Та же пирамида ($a=6$, $h=4$). Апофема $l=\\,?$', a:5, tol:0.05 },
|
||||
{ q:'Та же пирамида. $S_{бок}=\\,?$', a:60, tol:0.05 },
|
||||
{ q:'Правильная 3-угольная пирамида: $a=6$, $h=4$. $V=\\,?$ (точность 0,01)', a:20.78, tol:0.05 },
|
||||
{ q:'Правильная 6-угольная пирамида: $a=4$, $h=3$. $V=\\,?$ (точность 0,01)', a:41.57, tol:0.05 },
|
||||
{ q:'Правильная 4-угольная усечённая: $a_1=6$, $a_2=4$, $h=3$. $V=\\,?$', a:76, tol:0.05 }
|
||||
];
|
||||
const list = document.getElementById('p3-iv4-list');
|
||||
const scoreEl = document.getElementById('p3-iv4-score');
|
||||
const solved = new Set();
|
||||
let xpGiven = false;
|
||||
list.innerHTML = tasks.map(function(t, i){
|
||||
return '<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:10px 12px;margin-bottom:8px">'
|
||||
+ '<div style="margin-bottom:6px"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+ '<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:center">'
|
||||
+ '<input type="text" class="tinp" id="p3-iv4-inp-'+i+'" placeholder="число" style="width:140px">'
|
||||
+ '<button class="btn primary" data-i="'+i+'">Проверить</button>'
|
||||
+ '</div>'
|
||||
+ '<div class="feedback" id="p3-iv4-fb-'+i+'"></div>'
|
||||
+ '</div>';
|
||||
}).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('p3-iv4-inp-'+i);
|
||||
const fb = document.getElementById('p3-iv4-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, 'p3-iv4');
|
||||
bumpProgress('p3', 25);
|
||||
setTimeout(function(){ achievement('p3_done'); }, 400);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.');
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
wireReadBtn('p3');
|
||||
}
|
||||
|
||||
/* ===== STUB BUILDER — единый для всех параграфов раздела (Phase 0) ===== */
|
||||
|
||||
function buildStub(id){
|
||||
|
||||
Reference in New Issue
Block a user