feat(geom11 ch1 wave1): §1 «Призма» + 3D-конструктор + калькуляторы
This commit is contained in:
@@ -392,7 +392,7 @@ function buildParaSelector(){
|
||||
}
|
||||
|
||||
const BUILT=new Set();
|
||||
const BUILDERS = { p1:()=>buildStub('p1'), p2:()=>buildStub('p2'), final1:()=>buildStub('final1') };
|
||||
const BUILDERS = { p1:()=>buildP1(), p2:()=>buildStub('p2'), final1:()=>buildStub('final1') };
|
||||
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,13 @@ function goTo(id){
|
||||
}
|
||||
|
||||
const SIDEBARS = {
|
||||
p1:{title:"Шпаргалка § 1", rows:[["Тема", "Призма"],["Формула","$S_{бок}=Pl$, $V=S_{осн}h$"]]},
|
||||
p1:{title:"Шпаргалка § 1", rows:[["Тема","Призма"],["Прямая","$S_{бок}=P_{осн}\\\\cdot h$"],["Наклонная","$S_{бок}=P_{пер}\\\\cdot l$"],["Объём","$V=S_{осн}\\\\cdot h$"],["Диагональ пар.","$d=\\\\sqrt{a^2+b^2+c^2}$"]]},
|
||||
p2:{title:"Шпаргалка § 2", rows:[["Тема", "Цилиндр"],["Формула","$S_{бок}=2\\\\pi Rh$, $V=\\\\pi R^2h$"]]},
|
||||
final1:{title:"Финал раздела 1", rows:[["§ 1–§ 2","теория раздела 1"],["Награда","+50 XP"]]}
|
||||
};
|
||||
|
||||
const TIPS=[
|
||||
{sec:'p1',html:"§ 1 «Призма» — содержание в разработке. $S_{бок}=Pl$, $V=S_{осн}h$"},
|
||||
{sec:'p1',html:"§ 1 «Призма» — крути 3D-модель в интерактиве 1, проверь формулы в калькуляторе. Главное: $V=S_{осн}\\\\cdot h$, $S_{бок}=P_{осн}\\\\cdot h$ (для прямой)."},
|
||||
{sec:'p2',html:"§ 2 «Цилиндр» — содержание в разработке. $S_{бок}=2\\\\\\\\pi Rh$, $V=\\\\\\\\pi R^2h$"},
|
||||
{sec:'final1',html:"Финал раздела 1 — интегрированные задачи по разделу."}
|
||||
];
|
||||
@@ -619,6 +619,376 @@ function wireReadBtn(paraId){
|
||||
});
|
||||
}
|
||||
|
||||
/* ===== §1 «Призма» — Wave 1 ===== */
|
||||
function buildP1(){
|
||||
const box = document.getElementById('p1-body');
|
||||
if(!box) return;
|
||||
let html = '';
|
||||
|
||||
/* === ТЕОРИЯ === */
|
||||
|
||||
html += makeCard('theory', 'Определение и виды призм', '§ 1.1',
|
||||
'<p><b>Призма</b> — многогранник, две грани которого (основания) — равные многоугольники, лежащие в параллельных плоскостях, а остальные грани (боковые) — параллелограммы.</p>'
|
||||
+ '<p><b>Виды призм:</b></p>'
|
||||
+ '<ul style="margin:6px 0 10px 22px;line-height:1.7">'
|
||||
+ '<li><b>Прямая</b> — боковые рёбра $\\perp$ основанию. Боковые грани — прямоугольники.</li>'
|
||||
+ '<li><b>Наклонная</b> — боковые рёбра не перпендикулярны основанию.</li>'
|
||||
+ '<li><b>Правильная</b> — прямая призма, основание которой — правильный многоугольник.</li>'
|
||||
+ '</ul>'
|
||||
+ '<p><b>Параллелепипед</b> — призма с параллелограммом в основании. У неё $6$ граней, $12$ рёбер, $8$ вершин.</p>'
|
||||
+ '<p><b>Прямой параллелепипед</b> — боковые рёбра $\\perp$ основанию. <b>Прямоугольный параллелепипед</b> — прямой, у которого основание — прямоугольник (значит, все грани — прямоугольники). <b>Куб</b> — прямоугольный параллелепипед с равными рёбрами.</p>'
|
||||
+ '<p style="margin-top:10px"><b>Свойства параллелепипеда:</b></p>'
|
||||
+ '<ul style="margin:6px 0 0 22px;line-height:1.7">'
|
||||
+ '<li>Противоположные грани равны и параллельны.</li>'
|
||||
+ '<li>Все четыре диагонали пересекаются в одной точке и делятся ею пополам.</li>'
|
||||
+ '<li>Диагональ прямоугольного параллелепипеда: $d=\\sqrt{a^2+b^2+c^2}$.</li>'
|
||||
+ '</ul>');
|
||||
|
||||
html += makeCard('rule', 'Площадь поверхности и объём', '§ 1.2',
|
||||
'<p><b>Боковая поверхность.</b></p>'
|
||||
+ '<ul style="margin:6px 0 10px 22px;line-height:1.7">'
|
||||
+ '<li>Прямой призмы: $S_{бок}=P_{осн}\\cdot h$, где $P_{осн}$ — периметр основания, $h$ — высота (= боковое ребро).</li>'
|
||||
+ '<li>Наклонной призмы: $S_{бок}=P_{пер}\\cdot l$, где $P_{пер}$ — периметр <i>перпендикулярного сечения</i>, $l$ — боковое ребро.</li>'
|
||||
+ '</ul>'
|
||||
+ '<p><b>Полная поверхность:</b> $S_{полн}=S_{бок}+2\\cdot S_{осн}$.</p>'
|
||||
+ '<p><b>Объём</b> (для любой призмы):</p>'
|
||||
+ '<p style="text-align:center;margin:8px 0">$$V=S_{осн}\\cdot h$$</p>'
|
||||
+ '<p style="font-size:.9rem;color:var(--muted)">где $h$ — высота призмы (расстояние между плоскостями оснований).</p>'
|
||||
+ '<details class="spoiler"><summary>Пример: правильная 6-угольная призма</summary><div class="spoiler-body">'
|
||||
+ '<p>Сторона основания $a=4$, высота $h=10$:</p>'
|
||||
+ '<ul style="margin:6px 0 0 22px;line-height:1.7">'
|
||||
+ '<li>$S_{осн}=\\dfrac{3\\sqrt{3}}{2}\\,a^2=24\\sqrt{3}\\approx 41{,}57$</li>'
|
||||
+ '<li>$P_{осн}=6a=24$</li>'
|
||||
+ '<li>$S_{бок}=24\\cdot 10=240$</li>'
|
||||
+ '<li>$V=24\\sqrt{3}\\cdot 10=240\\sqrt{3}\\approx 415{,}7$</li>'
|
||||
+ '</ul>'
|
||||
+ '</div></details>');
|
||||
|
||||
html += makeCard('example', 'Диагональ прямоугольного параллелепипеда', '§ 1.3',
|
||||
'<p>Пусть у прямоугольного параллелепипеда измерения $a$, $b$, $c$ (длина, ширина, высота).</p>'
|
||||
+ '<p><b>Диагональ грани</b> (например, нижнего основания): $d_{грани}=\\sqrt{a^2+b^2}$.</p>'
|
||||
+ '<p><b>Главная диагональ</b> — отрезок, соединяющий противоположные вершины. Тогда:</p>'
|
||||
+ '<p style="text-align:center;margin:8px 0">$$d^2=a^2+b^2+c^2$$</p>'
|
||||
+ '<p>Это <b>трёхмерная теорема Пифагора</b>.</p>'
|
||||
+ '<details class="spoiler"><summary>Доказательство</summary><div class="spoiler-body">'
|
||||
+ '<p>Возьмём вершину $A$ нижнего основания и противоположную $A_1$ верхнего. Соединим $A$ с вершиной $C$ нижнего основания, потом $C$ с $A_1$.</p>'
|
||||
+ '<p>В треугольнике $ACA_1$ угол при $C$ прямой (ребро $CC_1=c$ перпендикулярно плоскости основания). По Пифагору в нижнем основании: $AC^2=a^2+b^2$. В $\\triangle ACA_1$: $AA_1^2=AC^2+CA_1^2=a^2+b^2+c^2$.</p>'
|
||||
+ '</div></details>'
|
||||
+ '<p style="margin-top:10px"><b>Пример:</b> куб со стороной $3 \\Rightarrow d=\\sqrt{9+9+9}=3\\sqrt{3}\\approx 5{,}20$.</p>');
|
||||
|
||||
/* === ИНТЕРАКТИВ 1 — 3D-конструктор === */
|
||||
html += '<div class="wg" id="p1-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="p1-iv1-n-v">5</b><input type="range" id="p1-iv1-n" min="3" max="8" step="1" value="5"></label>'
|
||||
+ '<label>$R$ (радиус):<b id="p1-iv1-R-v">1.5</b><input type="range" id="p1-iv1-R" min="1" max="4" step="0.1" value="1.5"></label>'
|
||||
+ '<label>$h$ (высота):<b id="p1-iv1-h-v">2.4</b><input type="range" id="p1-iv1-h" min="1" max="6" step="0.1" value="2.4"></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="p1-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>$P_{осн}=$<b id="p1-iv1-P">—</b></span>'
|
||||
+ '<span>$S_{осн}=$<b id="p1-iv1-Sb">—</b></span>'
|
||||
+ '<span>$S_{бок}=$<b id="p1-iv1-Ss">—</b></span>'
|
||||
+ '<span>$S_{полн}=$<b id="p1-iv1-St">—</b></span>'
|
||||
+ '<span>$V=$<b id="p1-iv1-V">—</b></span>'
|
||||
+ '</div>'
|
||||
+ '<div style="font-size:.78rem;color:var(--muted);margin-top:6px">Конфигураций изучено: <b id="p1-iv1-cnt">0</b> / 4</div>'
|
||||
+ '</div>';
|
||||
|
||||
/* === ИНТЕРАКТИВ 2 — Калькулятор === */
|
||||
html += '<div class="wg" id="p1-iv2">'
|
||||
+ '<div class="wg-header"><span class="wg-badge">калькулятор</span><div class="wg-title">$V$, $S_{полн}$ и диагональ</div></div>'
|
||||
+ '<div class="wg-help">Выбери тип призмы и задай размеры. Получишь полный разбор формул.</div>'
|
||||
+ '<div style="display:flex;gap:14px;margin-bottom:10px;flex-wrap:wrap">'
|
||||
+ '<label style="display:flex;align-items:center;gap:6px;cursor:pointer"><input type="radio" name="p1-iv2-type" value="reg" checked> Правильная $n$-угольная</label>'
|
||||
+ '<label style="display:flex;align-items:center;gap:6px;cursor:pointer"><input type="radio" name="p1-iv2-type" value="rect"> Прямоугольный параллелепипед</label>'
|
||||
+ '</div>'
|
||||
+ '<div id="p1-iv2-fields-reg" class="sliders">'
|
||||
+ '<label>$n$:<b id="p1-iv2-n-v">6</b><input type="range" id="p1-iv2-n" min="3" max="10" step="1" value="6"></label>'
|
||||
+ '<label>$a$ (сторона):<b id="p1-iv2-a-v">4.0</b><input type="range" id="p1-iv2-a" min="1" max="8" step="0.1" value="4"></label>'
|
||||
+ '<label>$h$ (высота):<b id="p1-iv2-h-v">10.0</b><input type="range" id="p1-iv2-h" min="1" max="15" step="0.1" value="10"></label>'
|
||||
+ '</div>'
|
||||
+ '<div id="p1-iv2-fields-rect" class="sliders" style="display:none">'
|
||||
+ '<label>$a$:<b id="p1-iv2-ra-v">3.0</b><input type="range" id="p1-iv2-ra" min="1" max="6" step="0.1" value="3"></label>'
|
||||
+ '<label>$b$:<b id="p1-iv2-rb-v">4.0</b><input type="range" id="p1-iv2-rb" min="1" max="6" step="0.1" value="4"></label>'
|
||||
+ '<label>$c$:<b id="p1-iv2-rc-v">5.0</b><input type="range" id="p1-iv2-rc" min="1" max="6" step="0.1" value="5"></label>'
|
||||
+ '</div>'
|
||||
+ '<div class="actions"><button class="btn primary" id="p1-iv2-calc">Вычислить</button></div>'
|
||||
+ '<div id="p1-iv2-out" style="margin-top:10px;font-size:.92rem;line-height:1.7"></div>'
|
||||
+ '</div>';
|
||||
|
||||
/* === ИНТЕРАКТИВ 3 — DnD сортер === */
|
||||
html += '<div class="wg" id="p1-iv3">'
|
||||
+ '<div class="wg-header"><span class="wg-badge">сортер</span><div class="wg-title">Какая это призма?</div></div>'
|
||||
+ '<div class="wg-help">Перетащи описание в нужный ящик. Кликни чип, затем ящик — тоже сработает.</div>'
|
||||
+ '<div class="dnd-hint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/></svg>6 описаний → 3 типа</div>'
|
||||
+ '<div id="p1-iv3-pool" class="dnd-pool"></div>'
|
||||
+ '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px">'
|
||||
+ '<div class="drop-box"><h5>Прямая</h5><div class="drop-items" data-cat="straight"></div></div>'
|
||||
+ '<div class="drop-box"><h5>Правильная</h5><div class="drop-items" data-cat="regular"></div></div>'
|
||||
+ '<div class="drop-box"><h5>Наклонная</h5><div class="drop-items" data-cat="oblique"></div></div>'
|
||||
+ '</div>'
|
||||
+ '<div class="actions"><button class="btn primary" id="p1-iv3-check">Проверить</button><button class="btn" id="p1-iv3-reset">Сброс</button></div>'
|
||||
+ '<div class="feedback" id="p1-iv3-fb"></div>'
|
||||
+ '</div>';
|
||||
|
||||
/* === ИНТЕРАКТИВ 4 — Тренажёр === */
|
||||
html += '<div class="wg" id="p1-iv4">'
|
||||
+ '<div class="wg-header"><span class="wg-badge">тренажёр · 6 задач</span><div class="wg-title">$V$, $S$ и диагональ</div></div>'
|
||||
+ '<div class="wg-help">Введи числовой ответ. Допуск $\\pm 0{,}05$ для дробных значений.</div>'
|
||||
+ '<div id="p1-iv4-list"></div>'
|
||||
+ '<div class="score-display" style="margin-top:10px">Решено: <b id="p1-iv4-score">0</b> / 6</div>'
|
||||
+ '</div>';
|
||||
|
||||
html += secNavFor('p1');
|
||||
html += readButton('p1');
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
|
||||
/* ====== JS-логика интерактивов ====== */
|
||||
|
||||
/* IV1 — 3D конструктор */
|
||||
(function(){
|
||||
if(!window.G3D) return;
|
||||
const svg = document.getElementById('p1-iv1-svg');
|
||||
const elN = document.getElementById('p1-iv1-n');
|
||||
const elR = document.getElementById('p1-iv1-R');
|
||||
const elH = document.getElementById('p1-iv1-h');
|
||||
const vN = document.getElementById('p1-iv1-n-v');
|
||||
const vR = document.getElementById('p1-iv1-R-v');
|
||||
const vH = document.getElementById('p1-iv1-h-v');
|
||||
const oP = document.getElementById('p1-iv1-P');
|
||||
const oSb = document.getElementById('p1-iv1-Sb');
|
||||
const oSs = document.getElementById('p1-iv1-Ss');
|
||||
const oSt = document.getElementById('p1-iv1-St');
|
||||
const oV = document.getElementById('p1-iv1-V');
|
||||
const oCnt = document.getElementById('p1-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.prismMesh(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'
|
||||
});
|
||||
/* Формулы для правильного n-угольника, вписанного в окружность радиуса R */
|
||||
const a = 2*R*Math.sin(Math.PI/n);
|
||||
const P = n*a;
|
||||
const Sb = 0.5*n*R*R*Math.sin(2*Math.PI/n);
|
||||
const Ss = P*h;
|
||||
const St = Ss + 2*Sb;
|
||||
const V = Sb*h;
|
||||
oP.textContent = P.toFixed(2);
|
||||
oSb.textContent = Sb.toFixed(2);
|
||||
oSs.textContent = Ss.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, 'p1-iv1');
|
||||
bumpProgress('p1', 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('p1-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('#p1-iv1 .g3d-tools .btn').forEach(function(b){
|
||||
b.addEventListener('click', function(){ G3D.presetView(scene, b.dataset.view, draw); });
|
||||
});
|
||||
})();
|
||||
|
||||
/* IV2 — Калькулятор */
|
||||
(function(){
|
||||
const radios = document.querySelectorAll('input[name="p1-iv2-type"]');
|
||||
const fldReg = document.getElementById('p1-iv2-fields-reg');
|
||||
const fldRect = document.getElementById('p1-iv2-fields-rect');
|
||||
const elN = document.getElementById('p1-iv2-n');
|
||||
const elA = document.getElementById('p1-iv2-a');
|
||||
const elH = document.getElementById('p1-iv2-h');
|
||||
const elRa = document.getElementById('p1-iv2-ra');
|
||||
const elRb = document.getElementById('p1-iv2-rb');
|
||||
const elRc = document.getElementById('p1-iv2-rc');
|
||||
const labels = {
|
||||
'p1-iv2-n':'p1-iv2-n-v', 'p1-iv2-a':'p1-iv2-a-v', 'p1-iv2-h':'p1-iv2-h-v',
|
||||
'p1-iv2-ra':'p1-iv2-ra-v', 'p1-iv2-rb':'p1-iv2-rb-v', 'p1-iv2-rc':'p1-iv2-rc-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();
|
||||
});
|
||||
radios.forEach(function(r){ r.addEventListener('change', function(){
|
||||
const v = document.querySelector('input[name="p1-iv2-type"]:checked').value;
|
||||
fldReg.style.display = v === 'reg' ? '' : 'none';
|
||||
fldRect.style.display = v === 'rect' ? '' : 'none';
|
||||
}); });
|
||||
let xpGiven = false;
|
||||
document.getElementById('p1-iv2-calc').addEventListener('click', function(){
|
||||
const out = document.getElementById('p1-iv2-out');
|
||||
const v = document.querySelector('input[name="p1-iv2-type"]:checked').value;
|
||||
let html = '';
|
||||
if(v === 'reg'){
|
||||
const n = +elN.value, a = +elA.value, h = +elH.value;
|
||||
const P = n*a;
|
||||
const apo = a / (2*Math.tan(Math.PI/n));
|
||||
const Sb = 0.5 * P * apo;
|
||||
const Ss = P * h;
|
||||
const St = Ss + 2*Sb;
|
||||
const V = Sb * h;
|
||||
html = '<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>$P_{осн}=n\\cdot a='+n+'\\cdot '+a.toFixed(2)+'='+P.toFixed(2)+'$</p>'
|
||||
+ '<p>$S_{осн}=\\dfrac{1}{2}P\\cdot a_{апо}=\\dfrac{n a^2}{4}\\cot\\dfrac{\\pi}{n}\\approx '+Sb.toFixed(2)+'$</p>'
|
||||
+ '<p>$S_{бок}=P_{осн}\\cdot h='+P.toFixed(2)+'\\cdot '+h.toFixed(2)+'='+Ss.toFixed(2)+'$</p>'
|
||||
+ '<p>$S_{полн}=S_{бок}+2S_{осн}\\approx '+St.toFixed(2)+'$</p>'
|
||||
+ '<p style="font-weight:700;color:var(--pri2)">$V=S_{осн}\\cdot h\\approx '+V.toFixed(2)+'$</p>'
|
||||
+ '</div>';
|
||||
} else {
|
||||
const a = +elRa.value, b = +elRb.value, c = +elRc.value;
|
||||
const V = a*b*c;
|
||||
const St = 2*(a*b + b*c + a*c);
|
||||
const d = Math.sqrt(a*a + b*b + c*c);
|
||||
html = '<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:10px 14px">'
|
||||
+ '<p><b>Прямоугольный параллелепипед, $a='+a.toFixed(2)+'$, $b='+b.toFixed(2)+'$, $c='+c.toFixed(2)+'$</b></p>'
|
||||
+ '<p>$V=abc='+a.toFixed(2)+'\\cdot '+b.toFixed(2)+'\\cdot '+c.toFixed(2)+'='+V.toFixed(2)+'$</p>'
|
||||
+ '<p>$S_{полн}=2(ab+bc+ac)='+St.toFixed(2)+'$</p>'
|
||||
+ '<p style="font-weight:700;color:var(--pri2)">$d=\\sqrt{a^2+b^2+c^2}=\\sqrt{'+(a*a+b*b+c*c).toFixed(2)+'}\\approx '+d.toFixed(2)+'$</p>'
|
||||
+ '</div>';
|
||||
}
|
||||
out.innerHTML = html;
|
||||
renderMath(out);
|
||||
if(!xpGiven){
|
||||
xpGiven = true;
|
||||
addXp(10, 'p1-iv2');
|
||||
bumpProgress('p1', 15);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
/* IV3 — DnD сортер */
|
||||
(function(){
|
||||
const items = [
|
||||
{ id:'i1', html:'Основание — правильный 6-угольник, боковые рёбра $\\perp$ основанию', cat:'regular' },
|
||||
{ id:'i2', html:'Боковые рёбра наклонены к основанию под углом 60°', cat:'oblique' },
|
||||
{ id:'i3', html:'Все 6 граней — прямоугольники, все рёбра равны (куб)', cat:'straight' },
|
||||
{ id:'i4', html:'Боковые рёбра $\\perp$ основанию, основание — параллелограмм', cat:'straight' },
|
||||
{ id:'i5', html:'Основание — квадрат со стороной 3, высота 5, боковые рёбра $\\perp$', cat:'regular' },
|
||||
{ id:'i6', html:'Боковые грани — параллелограммы, не прямоугольники', cat:'oblique' }
|
||||
];
|
||||
const sorter = setupSorter({
|
||||
poolId:'p1-iv3-pool',
|
||||
scopeSelector:'#p1-iv3',
|
||||
items: items,
|
||||
cats: ['straight','regular','oblique']
|
||||
});
|
||||
let xpGiven = false;
|
||||
document.getElementById('p1-iv3-check').addEventListener('click', function(){
|
||||
const fb = document.getElementById('p1-iv3-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, 'p1-iv3');
|
||||
bumpProgress('p1', 25);
|
||||
}
|
||||
} else {
|
||||
feedback(fb, false, '✗ Правильно: '+correct+' из '+items.length+'. Попробуй ещё раз.');
|
||||
}
|
||||
});
|
||||
document.getElementById('p1-iv3-reset').addEventListener('click', function(){
|
||||
sorter.reset();
|
||||
const fb = document.getElementById('p1-iv3-fb'); fb.style.display = 'none';
|
||||
});
|
||||
})();
|
||||
|
||||
/* IV4 — Тренажёр */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{ q:'Прямоугольный параллелепипед $3\\times 4\\times 5$. $V=\\,?$', a:60, tol:0.05 },
|
||||
{ q:'Куб со стороной 2. $V=\\,?$', a:8, tol:0.05 },
|
||||
{ q:'Куб со стороной 3. Диагональ $d=\\,?$ (точность 0,01)', a:5.20, tol:0.05 },
|
||||
{ q:'Прямоугольный параллелепипед $2\\times 3\\times 6$. Главная диагональ?', a:7, tol:0.05 },
|
||||
{ q:'Правильная 4-угольная призма со стороной основания 4 и высотой 5. $V=\\,?$', a:80, tol:0.05 },
|
||||
{ q:'Прямоугольный параллелепипед $3\\times 4\\times 5$. $S_{полн}=\\,?$', a:94, tol:0.05 }
|
||||
];
|
||||
const list = document.getElementById('p1-iv4-list');
|
||||
const scoreEl = document.getElementById('p1-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="p1-iv4-inp-'+i+'" placeholder="число" style="width:140px">'
|
||||
+ '<button class="btn primary" data-i="'+i+'">Проверить</button>'
|
||||
+ '</div>'
|
||||
+ '<div class="feedback" id="p1-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('p1-iv4-inp-'+i);
|
||||
const fb = document.getElementById('p1-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, 'p1-iv4');
|
||||
bumpProgress('p1', 25);
|
||||
setTimeout(function(){ achievement('p1_done'); }, 400);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.');
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
wireReadBtn('p1');
|
||||
}
|
||||
|
||||
/* ===== STUB BUILDER — единый для всех параграфов раздела (Phase 0) ===== */
|
||||
|
||||
function buildStub(id){
|
||||
|
||||
Reference in New Issue
Block a user