feat(phys8 ch2): Phase 2 Wave 3 — §17 эл. поле + §18 A=qU (Phase 2 завершён)

§17 Электрическое поле:
- 3 теории: что такое поле, линии поля, напряжение U=A/q
- IV-1: линии поля точечного заряда через fieldLinesPointCharge,
  slider знака (+/−) и силы поля (40-120 px scale)
- IV-2: 5 вопросов о свойствах линий
- IV-3: DnD 8 утверждений «правда / ложь»
- IV-4: 6 MCQ

§18 Единица напряжения. A = qU:
- 3 теории: формула, 1 Вольт = 1 Дж/Кл, таблица напряжений в быту
- IV-1: калькулятор A=qU с анимацией batteryEMF→стрелка→lightbulb
  + аналогия «поднять груз на 1 м»
- IV-2: 5 числовых задач «дано/найди» (q, U, A)
- IV-3: DnD 5 источников по возрастанию U (батарейка → молния 10⁸ В)
- IV-4: 5 расчётных задач (включая 1 эВ = 1.6×10⁻¹⁹ Дж)

С Phase 2 целиком: §12-18 (7 параграфов) — электростатика главы 2
закончена. Дальше — Phase 3: постоянный ток (§19-27).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-29 23:22:09 +03:00
parent 053c2ebfdd
commit 17a4a1b751
+417 -6
View File
@@ -343,8 +343,21 @@ const SIDEBARS = {
["Анион (&minus;)","принял электрон(ы)"],
["Электронные оболочки","K, L, M, …"]
]},
p17:{title:"Шпаргалка § 17",rows:[["В разработке","Phase 2 Wave 3"]]},
p18:{title:"Шпаргалка § 18",rows:[["В разработке","Phase 2 Wave 3"]]},
p17:{title:"Шпаргалка § 17",rows:[
["Эл. поле","материя вокруг заряда"],
["Действует","силой на другие заряды"],
["Линии поля","от + к &minus;"],
["Напряжение $U$","энергет. характеристика"],
["$U_{AB}$","разность потенциалов между A и B"]
]},
p18:{title:"Шпаргалка § 18",rows:[
["Формула","$A = q U$"],
["Единица","[U] = В = Дж/Кл"],
["Батарейка","1,5 В"],
["Аккумулятор","12 В"],
["Розетка","220 В"],
["1 В","работа 1 Дж на 1 Кл"]
]},
p19:{title:"Шпаргалка § 19",rows:[["В разработке","Phase 3 Wave 1"]]},
p20:{title:"Шпаргалка § 20",rows:[["В разработке","Phase 3 Wave 1"]]},
p21:{title:"Шпаргалка § 21",rows:[["В разработке","Phase 3 Wave 2"]]},
@@ -367,8 +380,8 @@ const TIPS=[
{sec:'p14',html:"Поднеси заряженный шар к незаряженному металлическому шарику — он притянется. В нейтральном проводнике под действием внешнего заряда электроны перераспределяются, и ближний конец получает противоположный знак."},
{sec:'p15',html:"Заряд не бывает «дробным» — все заряды кратны элементарному $e = 1{,}6 \\cdot 10^{-19}$ Кл. Если у тела «лишние» $N$ электронов, его заряд $q = -Ne$. 1 Кл — это очень много: примерно $6 \\cdot 10^{18}$ электронов."},
{sec:'p16',html:"Атом — это плотное положительное ядро (протоны+нейтроны) и облако отрицательных электронов вокруг. В обычном атоме число электронов равно числу протонов — он нейтрален. Если потерять электрон → ион +, если получить → ион &minus;."},
{sec:'p17',html:"Параграф § 17 будет реализован в Phase 2 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p18',html:"Параграф § 18 будет реализован в Phase 2 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p17',html:"Заряд не «торкает» другие заряды напрямую — он создаёт вокруг себя <b>электрическое поле</b>, а уже оно действует силой на другие заряды. Линии поля идут от + к &minus; и показывают направление силы на пробный +заряд."},
{sec:'p18',html:"Напряжение $U$ — это работа поля по перемещению единичного заряда: $A = qU$. Единица — 1 Вольт. Розетка 220 В, батарейка 1,5 В. Чем больше $U$, тем «сильнее» поле толкает заряд."},
{sec:'p19',html:"Параграф § 19 будет реализован в Phase 3 Wave 1. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p20',html:"Параграф § 20 будет реализован в Phase 3 Wave 1. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p21',html:"Параграф § 21 будет реализован в Phase 3 Wave 2. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
@@ -391,8 +404,8 @@ const BUILDERS = {
p14: ()=>{ build_p14(); },
p15: ()=>{ build_p15(); },
p16: ()=>{ build_p16(); },
p17: ()=>{ const box=document.getElementById('p17-body'); box.innerHTML = buildStub('p17', 'Электрическое поле. Электрическое напряжение', 'Phase 2 Wave 3') + secNavFor('p17') + readButton('p17'); renderMath(box); wireReadBtn('p17'); },
p18: ()=>{ const box=document.getElementById('p18-body'); box.innerHTML = buildStub('p18', 'Единица электрического напряжения. Расчёт работы в электрическом поле', 'Phase 2 Wave 3') + secNavFor('p18') + readButton('p18'); renderMath(box); wireReadBtn('p18'); },
p17: ()=>{ build_p17(); },
p18: ()=>{ build_p18(); },
p19: ()=>{ const box=document.getElementById('p19-body'); box.innerHTML = buildStub('p19', 'Электрический ток. Источники тока', 'Phase 3 Wave 1') + secNavFor('p19') + readButton('p19'); renderMath(box); wireReadBtn('p19'); },
p20: ()=>{ const box=document.getElementById('p20-body'); box.innerHTML = buildStub('p20', 'Сила и направление электрического тока', 'Phase 3 Wave 1') + secNavFor('p20') + readButton('p20'); renderMath(box); wireReadBtn('p20'); },
p21: ()=>{ const box=document.getElementById('p21-body'); box.innerHTML = buildStub('p21', 'Электрическая цепь. Измерение силы тока и напряжения', 'Phase 3 Wave 2') + secNavFor('p21') + readButton('p21'); renderMath(box); wireReadBtn('p21'); },
@@ -1855,6 +1868,404 @@ function _initP16_mcq(){
render();
}
/* ======================================================================
PHASE 2 · WAVE 3 — §17, §18
====================================================================== */
/* ======== §17 — Электрическое поле. Напряжение ======== */
function build_p17(){
const box = document.getElementById('p17-body');
let h = '';
h += makeCard('theory', 'Что такое электрическое поле', '§ 17.1',
'<p>Заряды действуют друг на друга <b>на расстоянии</b>, без прямого контакта. Как же передаётся это взаимодействие?</p>'
+'<p>Ответ: вокруг каждого заряда существует <b>электрическое поле</b> — особый вид материи. Поле — посредник.</p>'
+'<p>Когда мы помещаем в это поле другой заряд, поле действует на него с некоторой <b>силой</b>:</p>'
+'<ul style="padding-left:20px;margin:6px 0">'
+'<li>от $+q$ поле «отталкивает» другие $+q$ и «притягивает» $-q$;</li>'
+'<li>от $-q$ — наоборот.</li>'
+'</ul>'
);
h += makeCard('rule', 'Линии электрического поля', '§ 17.2',
'<p>Поле наглядно изображают линиями со стрелками. Они показывают направление силы, которая действовала бы на <b>пробный положительный</b> заряд.</p>'
+'<ul style="padding-left:20px;margin:6px 0">'
+'<li>Линии выходят из <b>$+q$</b> и входят в <b>$-q$</b>.</li>'
+'<li>Не пересекаются.</li>'
+'<li>Чем гуще линии — тем сильнее поле.</li>'
+'</ul>'
);
h += makeCard('example', 'Напряжение', '§ 17.3',
'<p>Чтобы переместить заряд $q$ внутри поля, поле совершает (или над ним совершают) <b>работу</b>. Эта работа зависит от того, между какими двумя точками идёт перемещение.</p>'
+'<p><b>Электрическое напряжение</b> $U$ между точками A и B — это работа поля по переносу единичного $+q$ из A в B:</p>'
+'<p style="text-align:center;margin:8px 0">$$U_{AB} = \\dfrac{A}{q}$$</p>'
+'<p>Подробно — в § 18.</p>'
);
/* IV1 — линии поля точечного заряда */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Линии электрического поля</div></div>'
+'<div class="wg-help">Выбери знак заряда — увидь, как направлены линии поля.</div>'
+'<div class="sliders" style="margin-bottom:10px">'
+'<label>Знак заряда: <select id="p17-sig" class="tinp" style="width:auto;padding:6px 10px"><option value="1">$+q$ (отталкивает)</option><option value="-1">$-q$ (притягивает)</option></select></label>'
+'<label>Сила поля: <b id="p17-sv">средняя</b><input type="range" id="p17-s" min="40" max="120" step="10" value="80"></label>'
+'</div>'
+'<svg id="p17-sim" viewBox="0 0 460 240" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
+'</div>';
/* IV2 — викторина «линии поля» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Куда направлены линии?</div></div>'
+'<div class="wg-help">Свойства линий поля.</div>'
+'<div id="p17-quiz"></div>'
+'<div class="actions"><button class="btn" id="p17-quiz-next">Следующий</button></div>'
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p17-quiz-r">1</b> / 5</span><span>Правильно: <b id="p17-quiz-ok">0</b></span></div>'
+'</div>';
/* IV3 — DnD факты */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Правда или ложь?</div></div>'
+'<div class="wg-help">Утверждения о поле и напряжении.</div>'
+'<div id="p17-dnd-pool"></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
+'<div class="drop-box"><h5>Правда</h5><div class="drop-items" data-cat="t"></div></div>'
+'<div class="drop-box"><h5>Ложь</h5><div class="drop-items" data-cat="f"></div></div>'
+'</div>'
+'<div class="actions"><button class="btn primary" id="p17-dnd-check">Проверить</button><button class="btn" id="p17-dnd-reset">Сброс</button></div>'
+'<div class="feedback" id="p17-dnd-fb"></div>'
+'</div>';
/* IV4 — MCQ */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
+'<div id="p17-mcq"></div>'
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p17-mcq-i">1</b> / 6</span><span>Правильно: <b id="p17-mcq-ok">0</b></span></div>'
+'</div>';
box.innerHTML = h + secNavFor('p17') + readButton('p17');
renderMath(box);
wireReadBtn('p17');
_initP17_field();
_initP17_quiz();
_initP17_dnd();
_initP17_mcq();
}
function _initP17_field(){
const svg = document.getElementById('p17-sim'); if(!svg) return;
function draw(){
const sig = +document.getElementById('p17-sig').value;
const scale = +document.getElementById('p17-s').value;
document.getElementById('p17-sv').textContent = scale < 60 ? 'слабая' : scale < 100 ? 'средняя' : 'сильная';
const cx = 230, cy = 120;
let s = '';
s += window.PHYS.fieldLinesPointCharge(cx, cy, sig, scale, 14);
s += window.PHYS.chargeMark(cx, cy, sig, 22, sig > 0 ? '+q' : 'q');
svg.innerHTML = s;
}
document.getElementById('p17-sig').addEventListener('change', draw);
document.getElementById('p17-s').addEventListener('input', draw);
draw();
}
function _initP17_quiz(){
const QS = [
{sit:'Линии поля около +q идут…', opts:['наружу','внутрь','параллельно','по кругу'], ans:0, why:'От + наружу.'},
{sit:'Линии поля около −q идут…', opts:['наружу','внутрь','параллельно','по кругу'], ans:1, why:'К внутрь.'},
{sit:'Чем гуще линии, тем поле…', opts:['слабее','сильнее','не меняется','исчезает'], ans:1, why:'Густота показывает силу поля.'},
{sit:'Линии поля могут пересекаться?', opts:['да','нет','только в вакууме','только у проводников'], ans:1, why:'В каждой точке поле имеет одно направление.'},
{sit:'Поле двух одинаковых +q посередине между ними…', opts:['большое','нулевое','перпендикулярное','непрерывное'], ans:1, why:'Силы от двух зарядов равны и противоположны — компенсируются.'}
];
let i = 0, ok = 0;
function render(){
const q = QS[i]; const wrap = document.getElementById('p17-quiz'); if(!wrap) return;
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:6px">';
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
html += '</div><div class="feedback" id="p17-quiz-fb"></div>';
wrap.innerHTML = html;
document.getElementById('p17-quiz-r').textContent = (i+1);
document.getElementById('p17-quiz-ok').textContent = ok;
wrap.querySelectorAll('[data-k]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
const k = +btn.dataset.k; const fb = document.getElementById('p17-quiz-fb');
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(3,'p17-quiz'); bumpProgress('p17', 4); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p17-quiz-ok').textContent = ok;
});
});
}
document.getElementById('p17-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
render();
}
function _initP17_dnd(){
const items = [
{id:'a', cat:'t', html:'Электрическое поле — особый вид материи'},
{id:'b', cat:'t', html:'Поле существует вокруг любого заряда'},
{id:'c', cat:'t', html:'$U_{AB} = A/q$ — определение напряжения'},
{id:'d', cat:'t', html:'Линии поля начинаются на + и кончаются на &minus;'},
{id:'e', cat:'f', html:'Поле — это вакуум вокруг заряда'},
{id:'f', cat:'f', html:'Линии поля могут пересекаться'},
{id:'g', cat:'f', html:'Напряжение — это сила, действующая на заряд'},
{id:'h', cat:'f', html:'Поле существует только в вакууме'}
];
const dnd = setupSorter({ poolId:'p17-dnd-pool', scopeSelector:'#sec-p17', cats:['t','f'], items, columnLayout:false });
document.getElementById('p17-dnd-check').addEventListener('click', ()=>{
const fb = document.getElementById('p17-dnd-fb');
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально! +15 XP. Поле — материя; напряжение — работа на ед. заряда.'; addXp(15,'p17-dnd'); bumpProgress('p17', 20); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'.'; }
});
document.getElementById('p17-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p17-dnd-fb'); fb.style.display='none'; });
}
function _initP17_mcq(){
const QS = [
{q:'Через что заряды взаимодействуют?', opts:['напрямую','через эл. поле','через гравитацию','через воздух'], ans:1, why:'Поле — посредник взаимодействия.'},
{q:'Откуда выходят линии поля?', opts:['из &minus;','из +','из любого','ниоткуда'], ans:1, why:'Линии начинаются на +.'},
{q:'Что показывают линии поля?', opts:['массу','направление силы на +q','скорость','температуру'], ans:1, why:'Линии — направление силы на пробный +.'},
{q:'Куда направлена сила на $-q$ в поле, идущем направо?', opts:['направо','налево','вверх','никуда'], ans:1, why:'На &minus;q сила направлена против поля.'},
{q:'$U_{AB}$ — это…', opts:['сила поля','энергия заряда','работа поля на ед. заряд','скорость заряда'], ans:2, why:'$U = A/q$ — определение.'},
{q:'Если убрать заряд-источник, поле…', opts:['останется','исчезнет','инвертируется','усилится'], ans:1, why:'Поле существует только пока есть его источник.'}
];
let i = 0, ok = 0, done = 0, awarded = false;
function render(){
const q = QS[i]; const wrap = document.getElementById('p17-mcq'); if(!wrap) return;
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
h += '</div><div class="feedback" id="p17-mcq-fb"></div><div class="actions"><button class="btn" id="p17-mcq-next">Следующий</button></div>';
wrap.innerHTML = h;
document.getElementById('p17-mcq-i').textContent = (i+1);
document.getElementById('p17-mcq-ok').textContent = ok;
wrap.querySelectorAll('[data-k]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
const k = +btn.dataset.k; const fb = document.getElementById('p17-mcq-fb');
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(2,'p17-mcq'); bumpProgress('p17', 3); }
else { done++; fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p17-mcq-ok').textContent = ok;
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p17-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='&#10003; +15 XP — тренажёр пройден.'; addXp(15,'p17-mcq-bonus'); bumpProgress('p17', 15); }, 600); }
});
});
const nb = document.getElementById('p17-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
}
render();
}
/* ======== §18 — A = qU ======== */
function build_p18(){
const box = document.getElementById('p18-body');
let h = '';
h += makeCard('theory', 'Формула $A = qU$', '§ 18.1',
'<p>Если перенести заряд $q$ через разность потенциалов $U$, поле совершит работу:</p>'
+'<p style="text-align:center;margin:8px 0">$$A = q \\, U$$</p>'
+'<ul style="padding-left:20px;margin:6px 0">'
+'<li>$A$ — работа, Дж;</li>'
+'<li>$q$ — заряд, Кл;</li>'
+'<li>$U$ — напряжение, В.</li>'
+'</ul>'
+'<p>Если $A > 0$ — поле «помогает» движению заряда; $A < 0$ — заряд движется «против» поля.</p>'
);
h += makeCard('rule', 'Что такое 1 Вольт', '§ 18.2',
'<p>1 Вольт — это такое напряжение, при котором поле совершает работу 1 Джоуль на каждый 1 Кулон переносимого заряда:</p>'
+'<p style="text-align:center;margin:8px 0">$$1 \\text{ В} = \\dfrac{1 \\text{ Дж}}{1 \\text{ Кл}}$$</p>'
+'<p>Один из величайших физиков Алессандро Вольта изобрёл первый источник тока — гальванический элемент. В его честь и названа единица.</p>'
);
h += makeCard('example', 'Напряжения в быту', '§ 18.3',
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><tbody>'
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Батарейка</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>1{,}5 В</code></td></tr>'
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Крона</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>9 В</code></td></tr>'
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Автомобильный аккумулятор</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>12 В</code></td></tr>'
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Зарядка для телефона</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>5 В</code></td></tr>'
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Розетка</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>220 В</code></td></tr>'
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">ЛЭП высокого напряжения</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>10 000 — 750 000 В</code></td></tr>'
+'<tr><td style="padding:5px">Молния</td><td style="padding:5px;text-align:right"><code>$10^8$ В</code></td></tr>'
+'</tbody></table>'
);
/* IV1 — калькулятор A=qU */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Калькулятор $A = qU$</div></div>'
+'<div class="wg-help">Меняй $q$ и $U$ — увидь работу поля.</div>'
+'<div class="sliders" style="margin-bottom:10px">'
+'<label>$q$, мКл (10<sup>&minus;3</sup> Кл): <b id="p18-qv">1.0</b><input type="range" id="p18-q" min="0.1" max="10" step="0.1" value="1"></label>'
+'<label>$U$, В: <b id="p18-uv">220</b><input type="range" id="p18-u" min="1" max="500" step="1" value="220"></label>'
+'</div>'
+'<svg id="p18-sim" viewBox="0 0 460 140" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
+'<span>$A = q U$ = <b id="p18-a">0.22</b> Дж</span>'
+'<span style="font-size:.84rem;color:var(--muted)">Этой энергии хватит, чтобы <b id="p18-anal">поднять груз 22 г на 1 м</b>.</span>'
+'</div>'
+'</div>';
/* IV2 — викторина «дано / найди» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Что найти?</div></div>'
+'<div class="wg-help">По формуле $A = qU$ найди недостающую величину.</div>'
+'<div id="p18-quiz"></div>'
+'<div class="actions"><button class="btn" id="p18-quiz-next">Следующий</button></div>'
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p18-quiz-r">1</b> / 5</span><span>Правильно: <b id="p18-quiz-ok">0</b></span></div>'
+'</div>';
/* IV3 — DnD «напряжения по возрастанию» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Расставь напряжения по возрастанию</div></div>'
+'<div class="wg-help">От самого маленького к самому большому.</div>'
+'<div id="p18-dnd-pool"></div>'
+'<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:10px">'
+'<div class="drop-box"><h5>1. Меньше</h5><div class="drop-items" data-cat="r1"></div></div>'
+'<div class="drop-box"><h5>2</h5><div class="drop-items" data-cat="r2"></div></div>'
+'<div class="drop-box"><h5>3</h5><div class="drop-items" data-cat="r3"></div></div>'
+'<div class="drop-box"><h5>4</h5><div class="drop-items" data-cat="r4"></div></div>'
+'<div class="drop-box"><h5>5. Больше</h5><div class="drop-items" data-cat="r5"></div></div>'
+'</div>'
+'<div class="actions"><button class="btn primary" id="p18-dnd-check">Проверить</button><button class="btn" id="p18-dnd-reset">Сброс</button></div>'
+'<div class="feedback" id="p18-dnd-fb"></div>'
+'</div>';
/* IV4 — расчётные задачи */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 задач</div></div>'
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
+'<div id="p18-task"></div>'
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p18-task-i">1</b> / 5</span><span>Правильно: <b id="p18-task-ok">0</b></span></div>'
+'</div>';
box.innerHTML = h + secNavFor('p18') + readButton('p18');
renderMath(box);
wireReadBtn('p18');
_initP18_calc();
_initP18_quiz();
_initP18_dnd();
_initP18_tasks();
}
function _initP18_calc(){
const svg = document.getElementById('p18-sim'); if(!svg) return;
function update(){
const qmC = +document.getElementById('p18-q').value;
const U = +document.getElementById('p18-u').value;
const q = qmC * 1e-3; /* мКл → Кл */
const A = q * U;
document.getElementById('p18-qv').textContent = qmC.toFixed(1);
document.getElementById('p18-uv').textContent = U;
document.getElementById('p18-a').textContent = A.toFixed(3);
/* аналогия: поднять груз на 1 м, m = A/(g*1) */
const g = 9.8;
const massG = (A/g) * 1000;
document.getElementById('p18-anal').textContent = 'поднять груз '+massG.toFixed(0)+' г на 1 м';
/* sim */
let s = '';
/* батарея */
s += window.PHYS.batteryEMF(80, 70, U+' В', 'h');
/* стрелка переноса заряда */
s += '<text x="160" y="60" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#dc2626">q = '+qmC.toFixed(1)+' мКл</text>';
s += window.PHYS.drawArrow(180, 100, 320, 100, '#10b981', 2.5, 11);
s += '<text x="250" y="120" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" fill="#0f172a">A = qU = '+A.toFixed(3)+' Дж</text>';
/* итог "лампа" */
s += window.PHYS.lightbulbSymbol(360, 80, 22);
s += '<text x="360" y="125" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" fill="#475569">энергия</text>';
svg.innerHTML = s;
}
document.getElementById('p18-q').addEventListener('input', update);
document.getElementById('p18-u').addEventListener('input', update);
update();
}
function _initP18_quiz(){
const QS = [
{q:'Заряд $q = 2$ Кл прошёл напряжение $U = 5$ В. Найди $A$ (Дж).', ans:10, tol:0.1, why:'$A = qU = 2 \\cdot 5 = 10$ Дж.'},
{q:'$A = 240$ Дж, $U = 12$ В. Какой заряд прошёл (Кл)?', ans:20, tol:0.5, why:'$q = A/U = 240/12 = 20$ Кл.'},
{q:'$A = 6$ Дж, $q = 30$ мКл $= 0{,}03$ Кл. Найди $U$ (В).', ans:200, tol:2, why:'$U = A/q = 6/0{,}03 = 200$ В.'},
{q:'Поле перенесло $q = 0{,}5$ Кл через $U = 220$ В. Найди $A$ (Дж).', ans:110, tol:1, why:'$A = 0{,}5 \\cdot 220 = 110$ Дж.'},
{q:'$A = 4{,}5$ Дж, $q = 3$ Кл. Найди $U$ (В).', ans:1.5, tol:0.05, why:'$U = 4{,}5/3 = 1{,}5$ В — это батарейка.'}
];
let i = 0, ok = 0;
function render(){
const t = QS[i]; const wrap = document.getElementById('p18-quiz'); if(!wrap) return;
wrap.innerHTML =
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+t.q+'</div>'
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p18-quiz-inp" placeholder="число" style="width:140px">'
+'<button class="btn primary" id="p18-quiz-go">Ответ</button></div>'
+'<div class="feedback" id="p18-quiz-fb"></div>';
document.getElementById('p18-quiz-r').textContent = (i+1);
document.getElementById('p18-quiz-ok').textContent = ok;
document.getElementById('p18-quiz-go').addEventListener('click', ()=>{
const v = parseFloat((document.getElementById('p18-quiz-inp').value || '').replace(',','.'));
const fb = document.getElementById('p18-quiz-fb');
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно! '+t.why; addXp(3,'p18-quiz'); bumpProgress('p18', 4); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. Ответ: '+t.ans+'. '+t.why; }
document.getElementById('p18-quiz-ok').textContent = ok;
renderMath(wrap);
});
renderMath(wrap);
}
document.getElementById('p18-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
render();
}
function _initP18_dnd(){
const items = [
{id:'bat', cat:'r1', html:'батарейка ($1{,}5$ В)'},
{id:'kr', cat:'r2', html:'аккумулятор авто ($12$ В)'},
{id:'sock',cat:'r3', html:'розетка ($220$ В)'},
{id:'lep', cat:'r4', html:'ЛЭП ($10^5$ В)'},
{id:'lit', cat:'r5', html:'молния ($10^8$ В)'}
];
const dnd = setupSorter({ poolId:'p18-dnd-pool', scopeSelector:'#sec-p18', cats:['r1','r2','r3','r4','r5'], items, columnLayout:false });
document.getElementById('p18-dnd-check').addEventListener('click', ()=>{
const fb = document.getElementById('p18-dnd-fb');
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально! +15 XP. Диапазон напряжений в природе огромен — от вольта до миллиардов.'; addXp(15,'p18-dnd'); bumpProgress('p18', 20); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'.'; }
});
document.getElementById('p18-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p18-dnd-fb'); fb.style.display='none'; });
}
function _initP18_tasks(){
const TASKS = [
{q:'Электрон ($q = 1{,}6 \\cdot 10^{-19}$ Кл) прошёл $U = 1$ В. Найди $A$ в эВ (это и есть 1 эВ). Введи в Джоулях, в формате $a \\cdot 10^{-19}$, введи $a$.', ans:1.6, tol:0.05, why:'$A = qU = 1{,}6\\cdot10^{-19} \\cdot 1 = 1{,}6\\cdot10^{-19}$ Дж = 1 эВ.'},
{q:'$U = 220$ В, $q = 5$ Кл. Сколько Дж энергии передало поле?', ans:1100, tol:5, why:'$A = 5 \\cdot 220 = 1100$ Дж.'},
{q:'В лампе работа $A = 60$ Дж за 1 с при $U = 220$ В. Какой заряд прошёл (в Кл, округли до сотых)?', ans:0.27, tol:0.02, why:'$q = A/U = 60/220 \\approx 0{,}273$ Кл.'},
{q:'Заряд $q = 2$ мКл переместился через $U = 100$ В. Найди $A$ в мДж.', ans:200, tol:5, why:'$A = qU = 2\\cdot10^{-3} \\cdot 100 = 0{,}2$ Дж = $200$ мДж.'},
{q:'$A = 1$ Дж, $q = 1$ Кл. Найди $U$.', ans:1, tol:0.05, why:'$U = A/q = 1/1 = 1$ В — определение единицы.'}
];
let i = 0, ok = 0, done = 0, awarded = false;
function render(){
const t = TASKS[i]; const wrap = document.getElementById('p18-task'); if(!wrap) return;
wrap.innerHTML =
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p18-task-inp" placeholder="число" style="width:140px">'
+'<button class="btn primary" id="p18-task-go">Ответ</button>'
+'<button class="btn" id="p18-task-hint">Подсказка</button>'
+'<button class="btn" id="p18-task-next">Следующая</button></div>'
+'<div class="boss-hint-txt" id="p18-task-hint-txt">'+t.why+'</div>'
+'<div class="feedback" id="p18-task-fb"></div>';
document.getElementById('p18-task-i').textContent = (i+1);
document.getElementById('p18-task-ok').textContent = ok;
document.getElementById('p18-task-go').addEventListener('click', ()=>{
const v = parseFloat((document.getElementById('p18-task-inp').value || '').replace(',','.'));
const fb = document.getElementById('p18-task-fb');
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
done++;
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно! '+t.why; addXp(4,'p18-task'); bumpProgress('p18', 6); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. Ответ: '+t.ans+'. '+t.why; }
document.getElementById('p18-task-ok').textContent = ok;
renderMath(wrap);
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p18-task-fb'); wf.className='feedback ok'; wf.innerHTML='&#10003; +15 XP — расчёты сданы ('+ok+'/'+TASKS.length+').'; addXp(15,'p18-task-bonus'); bumpProgress('p18', 15); }, 600); }
});
document.getElementById('p18-task-hint').addEventListener('click', ()=>{ document.getElementById('p18-task-hint-txt').classList.toggle('show'); });
document.getElementById('p18-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
renderMath(wrap);
}
render();
}
function init(){
loadProgress(); initTheme(); initSidebarToggle(); initSearch();
buildParaSelector(); refreshProgressUI(); loadServerReadState(); goTo(PARAS[0].id);