diff --git a/frontend/textbooks/physics_8_ch2.html b/frontend/textbooks/physics_8_ch2.html
index 252e1af..bf5563e 100644
--- a/frontend/textbooks/physics_8_ch2.html
+++ b/frontend/textbooks/physics_8_ch2.html
@@ -386,9 +386,28 @@ const SIDEBARS = {
["Больше $U$","больше $I$ (пропорц.)"],
["Больше $R$","меньше $I$"]
]},
- p23:{title:"Шпаргалка § 23",rows:[["В разработке","Phase 3 Wave 3"]]},
- p24:{title:"Шпаргалка § 24",rows:[["В разработке","Phase 3 Wave 3"]]},
- p25:{title:"Шпаргалка § 25",rows:[["В разработке","Phase 3 Wave 3"]]},
+ p23:{title:"Шпаргалка § 23",rows:[
+ ["Формула","$R = \\rho \\, l / S$"],
+ ["$\\rho$","удельное сопр., Ом·мм²/м"],
+ ["медь","$\\rho = 0{,}017$"],
+ ["алюминий","$\\rho = 0{,}028$"],
+ ["нихром","$\\rho = 1{,}1$"],
+ ["1 Ом","$U=1$ В $\\to I=1$ А"]
+ ]},
+ p24:{title:"Шпаргалка § 24",rows:[
+ ["Послед. соед.","$I = $ const"],
+ ["Напряжение","$U = U_1 + U_2$"],
+ ["Сопротивл.","$R = R_1 + R_2$"],
+ ["Реостат","переменный резистор"],
+ ["Поломка одного","вся цепь обесточена"]
+ ]},
+ p25:{title:"Шпаргалка § 25",rows:[
+ ["Паралл. соед.","$U = $ const"],
+ ["Ток","$I = I_1 + I_2$"],
+ ["Сопротивл.","$1/R = 1/R_1 + 1/R_2$"],
+ ["Два равных","$R_{общ} = R/2$"],
+ ["Поломка одного","остальные работают"]
+ ]},
p26:{title:"Шпаргалка § 26",rows:[["В разработке","Phase 3 Wave 4"]]},
p27:{title:"Шпаргалка § 27",rows:[["В разработке","Phase 3 Wave 4"]]},
p28:{title:"Шпаргалка § 28",rows:[["В разработке","Phase 4 Wave 1"]]},
@@ -410,9 +429,9 @@ const TIPS=[
{sec:'p20',html:"$I = q/t$ — сколько Кулонов прошло через сечение провода за 1 секунду. Единица — Ампер ($1$ А = $1$ Кл/с). За направление тока приняли движение «+» зарядов — хотя в металлах реально двигаются электроны (против тока)."},
{sec:'p21',html:"Простейшая цепь: батарея, лампа, ключ, провода. Чтобы измерить ток через лампу — амперметр включают последовательно с лампой. Чтобы измерить напряжение на лампе — вольтметр включают параллельно."},
{sec:'p22',html:"Закон Ома для участка цепи: $I = U/R$. Увеличил напряжение в 2 раза — ток вырос в 2 раза. Поставил резистор побольше — ток упал. Прямая зависимость для металлов."},
- {sec:'p23',html:"Параграф § 23 будет реализован в Phase 3 Wave 3. Используем хелперы из phys.js и optics.js."},
- {sec:'p24',html:"Параграф § 24 будет реализован в Phase 3 Wave 3. Используем хелперы из phys.js и optics.js."},
- {sec:'p25',html:"Параграф § 25 будет реализован в Phase 3 Wave 3. Используем хелперы из phys.js и optics.js."},
+ {sec:'p23',html:"Сопротивление провода зависит от трёх вещей: материала ($\\rho$), длины ($l$) и толщины ($S$). Длинный тонкий нихром — большое $R$ (спираль чайника), короткий толстый медный — маленькое $R$ (провод)."},
+ {sec:'p24',html:"При последовательном соединении ток течёт через все элементы один и тот же. Напряжения складываются. Сопротивления складываются. Реостат — переменный резистор, при сдвиге движка меняется длина включённой проволоки."},
+ {sec:'p25',html:"При параллельном соединении на каждой ветви одно и то же напряжение. Токи складываются. Сопротивление считается по особой формуле — в итоге $R_{общ}$ меньше любого из $R_1$, $R_2$."},
{sec:'p26',html:"Параграф § 26 будет реализован в Phase 3 Wave 4. Используем хелперы из phys.js и optics.js."},
{sec:'p27',html:"Параграф § 27 будет реализован в Phase 3 Wave 4. Используем хелперы из phys.js и optics.js."},
{sec:'p28',html:"Параграф § 28 будет реализован в Phase 4 Wave 1. Используем хелперы из phys.js и optics.js."},
@@ -434,9 +453,9 @@ const BUILDERS = {
p20: ()=>{ build_p20(); },
p21: ()=>{ build_p21(); },
p22: ()=>{ build_p22(); },
- p23: ()=>{ const box=document.getElementById('p23-body'); box.innerHTML = buildStub('p23', 'Единица сопротивления. Расчёт сопротивления', 'Phase 3 Wave 3') + secNavFor('p23') + readButton('p23'); renderMath(box); wireReadBtn('p23'); },
- p24: ()=>{ const box=document.getElementById('p24-body'); box.innerHTML = buildStub('p24', 'Последовательное соединение проводников. Реостат', 'Phase 3 Wave 3') + secNavFor('p24') + readButton('p24'); renderMath(box); wireReadBtn('p24'); },
- p25: ()=>{ const box=document.getElementById('p25-body'); box.innerHTML = buildStub('p25', 'Параллельное соединение проводников', 'Phase 3 Wave 3') + secNavFor('p25') + readButton('p25'); renderMath(box); wireReadBtn('p25'); },
+ p23: ()=>{ build_p23(); },
+ p24: ()=>{ build_p24(); },
+ p25: ()=>{ build_p25(); },
p26: ()=>{ const box=document.getElementById('p26-body'); box.innerHTML = buildStub('p26', 'Работа и мощность электрического тока. Закон Джоуля — Ленца', 'Phase 3 Wave 4') + secNavFor('p26') + readButton('p26'); renderMath(box); wireReadBtn('p26'); },
p27: ()=>{ const box=document.getElementById('p27-body'); box.innerHTML = buildStub('p27', 'Использование и экономия электроэнергии. Безопасность', 'Phase 3 Wave 4') + secNavFor('p27') + readButton('p27'); renderMath(box); wireReadBtn('p27'); },
p28: ()=>{ const box=document.getElementById('p28-body'); box.innerHTML = buildStub('p28', 'Постоянные магниты', 'Phase 4 Wave 1') + secNavFor('p28') + readButton('p28'); renderMath(box); wireReadBtn('p28'); },
@@ -3200,6 +3219,680 @@ function _initP22_tasks(){
render();
}
+/* ======================================================================
+ PHASE 3 · WAVE 3 — §23, §24, §25
+ ====================================================================== */
+
+const MAT_RHO = [
+ {name:'серебро', rho:0.016},
+ {name:'медь', rho:0.017},
+ {name:'алюминий',rho:0.028},
+ {name:'железо', rho:0.10},
+ {name:'нихром', rho:1.1},
+ {name:'константан', rho:0.5}
+];
+
+/* ======== §23 — R = ρl/S ======== */
+function build_p23(){
+ const box = document.getElementById('p23-body');
+ let h = '';
+
+ h += makeCard('theory', 'Формула сопротивления', '§ 23.1',
+ '
Сопротивление проводника зависит от трёх параметров:
'
+ +'$$R = \\dfrac{\\rho \\, l}{S}$$
'
+ +''
+ +'- $\\rho$ — удельное сопротивление, Ом·мм²/м. Свойство материала.
'
+ +'- $l$ — длина проводника, м.
'
+ +'- $S$ — площадь поперечного сечения, мм².
'
+ +'
'
+ +'Чем длиннее — тем больше $R$. Чем толще (больше $S$) — тем меньше $R$. Чем «хуже» материал — тем больше $\\rho$.
'
+ );
+ h += makeCard('rule', 'Таблица $\\rho$', '§ 23.2',
+ '| Материал | $\\rho$, $\\dfrac{\\text{Ом}\\cdot\\text{мм}^2}{\\text{м}}$ |
'
+ + MAT_RHO.map(m=>'| '+m.name+' | '+m.rho+' |
').join('')
+ +'
'
+ +'Для проводов берут медь или алюминий (малое $\\rho$). Для нагревательных спиралей — нихром (большое $\\rho$ → много тепла при том же токе).
'
+ );
+ h += makeCard('example', 'Где это применяется', '§ 23.3',
+ ''
+ +'- Электропровода — медные, толстые → малое $R$ → малые потери.
'
+ +'- Нагревательная спираль чайника — длинная и тонкая из нихрома.
'
+ +'- Линии электропередачи — толстые алюминиевые провода (медь была бы дороже).
'
+ +'- Удлинители — чем длиннее, тем больше $R$ → больше потерь.
'
+ +'
'
+ );
+
+ /* IV1 — калькулятор R = ρl/S */
+ h += ''
+ +''
+ +'
Выбери материал, длину и сечение — увидь $R$.
'
+ +'
'
+ +''
+ +''
+ +''
+ +'
'
+ +'
'
+ +'
'
+ +'$R = \\rho l / S$ = 0.17 Ом'
+ +'При $U = 12$ В: $I = U/R = $ 71 А.'
+ +'
'
+ +'
';
+
+ /* IV2 — «больше/меньше R?» */
+ h += ''
+ +''
+ +'
Сравни два варианта.
'
+ +'
'
+ +'
'
+ +'
Раунд: 1 / 6Правильно: 0
'
+ +'
';
+
+ /* IV3 — DnD «как изменится R» */
+ h += ''
+ +''
+ +'
При изменении параметра.
'
+ +'
'
+ +'
'
+ +'
'
+ +'
'
+ +'
';
+
+ /* IV4 — задачи */
+ h += ''
+ +''
+ +'
4+ — +15 XP.
'
+ +'
'
+ +'
Задача: 1 / 5Правильно: 0
'
+ +'
';
+
+ box.innerHTML = h + secNavFor('p23') + readButton('p23');
+ renderMath(box);
+ wireReadBtn('p23');
+
+ _initP23_calc();
+ _initP23_quiz();
+ _initP23_dnd();
+ _initP23_tasks();
+}
+
+function _initP23_calc(){
+ const svg = document.getElementById('p23-sim'); if(!svg) return;
+ function update(){
+ const rho = +document.getElementById('p23-mat').value;
+ const l = +document.getElementById('p23-l').value;
+ const S = +document.getElementById('p23-s').value;
+ document.getElementById('p23-lv').textContent = l.toFixed(1);
+ document.getElementById('p23-sv').textContent = S.toFixed(1);
+ const R = rho * l / S;
+ document.getElementById('p23-rv2').textContent = R.toFixed(2);
+ document.getElementById('p23-i12').textContent = (12/R).toFixed(1);
+ /* SVG: провод */
+ let s = '';
+ const lenPx = 60 + Math.min(330, l*3);
+ const wPx = 6 + Math.min(40, S*4);
+ const cy = 70;
+ const xS = 30;
+ s += '';
+ /* подписи */
+ s += 'l = '+l.toFixed(1)+' м';
+ s += 'S = '+S.toFixed(1)+' мм²';
+ /* формула */
+ s += 'R = '+rho+' · '+l.toFixed(1)+' / '+S.toFixed(1)+' = '+R.toFixed(2)+' Ом';
+ svg.innerHTML = s;
+ }
+ document.getElementById('p23-mat').addEventListener('change', update);
+ document.getElementById('p23-l').addEventListener('input', update);
+ document.getElementById('p23-s').addEventListener('input', update);
+ update();
+}
+
+function _initP23_quiz(){
+ const QS = [
+ {A:'медный провод 10 м', B:'медный провод 20 м', ans:'B', why:'Длиннее — больше $R$.'},
+ {A:'медный провод $S = 1$ мм²', B:'медный провод $S = 2$ мм²', ans:'A', why:'Толще — меньше $R$.'},
+ {A:'нихромовый провод 1 м', B:'медный провод 1 м', ans:'A', why:'Нихром в 65 раз хуже меди по $\\rho$.'},
+ {A:'железный провод', B:'медный провод (тот же)', ans:'A', why:'Железо хуже меди.'},
+ {A:'алюминиевый провод 50 м', B:'медный провод 50 м', ans:'A', why:'У алюминия $\\rho$ больше.'},
+ {A:'тонкий нихром', B:'толстая медь', ans:'A', why:'Тонкий и нихром — двойное «увеличение R».'}
+ ];
+ let i = 0, ok = 0;
+ function render(){
+ const q = QS[i]; const wrap = document.getElementById('p23-quiz'); if(!wrap) return;
+ wrap.innerHTML =
+ ''
+ +''
+ +''
+ +'
'
+ +'';
+ document.getElementById('p23-quiz-r').textContent = (i+1);
+ document.getElementById('p23-quiz-ok').textContent = ok;
+ wrap.querySelectorAll('[data-pick]').forEach(btn=>{
+ btn.addEventListener('click', ()=>{
+ if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
+ const fb = document.getElementById('p23-quiz-fb');
+ if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p23-quiz'); bumpProgress('p23', 4); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
+ document.getElementById('p23-quiz-ok').textContent = ok;
+ });
+ });
+ }
+ document.getElementById('p23-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
+ render();
+}
+
+function _initP23_dnd(){
+ const items = [
+ {id:'lup', cat:'up', html:'увеличили длину $l$'},
+ {id:'sdn', cat:'up', html:'уменьшили сечение $S$'},
+ {id:'mb', cat:'up', html:'заменили медь на нихром'},
+ {id:'cd', cat:'up', html:'заменили серебро на железо'},
+ {id:'ldn', cat:'dn', html:'укоротили провод'},
+ {id:'sup', cat:'dn', html:'утолстили провод'},
+ {id:'mw', cat:'dn', html:'заменили нихром на медь'},
+ {id:'cs', cat:'dn', html:'заменили железо на серебро'}
+ ];
+ const dnd = setupSorter({ poolId:'p23-dnd-pool', scopeSelector:'#sec-p23', cats:['up','dn'], items, columnLayout:false });
+ document.getElementById('p23-dnd-check').addEventListener('click', ()=>{
+ const fb = document.getElementById('p23-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='✓ Идеально! +15 XP. $R$ пропорционально $\\rho l$ и обратно $S$.'; addXp(15,'p23-dnd'); bumpProgress('p23', 20); renderMath(fb); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
+ });
+ document.getElementById('p23-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p23-dnd-fb'); fb.style.display='none'; });
+}
+
+function _initP23_tasks(){
+ const TASKS = [
+ {q:'Медь, $l = 100$ м, $S = 1$ мм². Найди $R$ (Ом).', ans:1.7, tol:0.05, why:'$R = 0{,}017 \\cdot 100 / 1 = 1{,}7$ Ом.'},
+ {q:'Нихромовая спираль, $l = 5$ м, $S = 0{,}5$ мм². Найди $R$ (Ом).', ans:11, tol:0.3, why:'$R = 1{,}1 \\cdot 5 / 0{,}5 = 11$ Ом.'},
+ {q:'$R = 4$ Ом, $\\rho = 0{,}4$, $l = 2$ м. Найди $S$ (мм²).', ans:0.2, tol:0.02, why:'$S = \\rho l / R = 0{,}4 \\cdot 2 / 4 = 0{,}2$ мм².'},
+ {q:'Два медных провода: один длиннее в 3 раза, тоньше в 2 раза. Во сколько раз $R$ больше?', ans:6, tol:0.1, why:'$R$ ∝ $l/S$: $3 \\cdot 2 = 6$ раз.'},
+ {q:'Алюминиевый провод, $l = 20$ м, $S = 4$ мм². Найди $R$ (Ом).', ans:0.14, tol:0.01, why:'$R = 0{,}028 \\cdot 20 / 4 = 0{,}14$ Ом.'}
+ ];
+ let i = 0, ok = 0, done = 0, awarded = false;
+ function render(){
+ const t = TASKS[i]; const wrap = document.getElementById('p23-task'); if(!wrap) return;
+ wrap.innerHTML =
+ 'Задача '+(i+1)+'. '+t.q+'
'
+ +''
+ +''
+ +''
+ +'
'
+ +''+t.why+'
'
+ +'';
+ document.getElementById('p23-task-i').textContent = (i+1);
+ document.getElementById('p23-task-ok').textContent = ok;
+ document.getElementById('p23-task-go').addEventListener('click', ()=>{
+ const v = parseFloat((document.getElementById('p23-task-inp').value || '').replace(',','.'));
+ const fb = document.getElementById('p23-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='✓ Верно! '+t.why; addXp(4,'p23-task'); bumpProgress('p23', 6); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
+ document.getElementById('p23-task-ok').textContent = ok;
+ renderMath(wrap);
+ if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p23-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p23-task-bonus'); bumpProgress('p23', 15); }, 600); }
+ });
+ document.getElementById('p23-task-hint').addEventListener('click', ()=>{ document.getElementById('p23-task-hint-txt').classList.toggle('show'); });
+ document.getElementById('p23-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
+ renderMath(wrap);
+ }
+ render();
+}
+
+/* ======== §24 — Последовательное соединение. Реостат ======== */
+function build_p24(){
+ const box = document.getElementById('p24-body');
+ let h = '';
+
+ h += makeCard('theory', 'Правила последовательного соединения', '§ 24.1',
+ 'Если резисторы соединены один за другим (в одну «петлю»), это последовательное соединение.
'
+ +''
+ +'- Ток одинаков: $I = I_1 = I_2$ (одна и та же река через все «пороги»).
'
+ +'- Напряжения складываются: $U = U_1 + U_2$.
'
+ +'- Сопротивления складываются: $R = R_1 + R_2$.
'
+ +'
'
+ +'Если один из резисторов вышел из строя — вся цепь обесточена.
'
+ );
+ h += makeCard('rule', 'Реостат', '§ 24.2',
+ 'Реостат — переменный резистор. Состоит из проволочного резистивного элемента и подвижного контакта (движка).
'
+ +'Сдвигая движок, мы изменяем длину $l$ включённой части провода. Так как $R = \\rho l/S$, меняется и сопротивление.
'
+ +'Реостат используют для:
'
+ +''
+ +'- регулировки силы тока (например, яркости лампы);
'
+ +'- защиты от перегрузки (последовательно с прибором);
'
+ +'- «старой» школы — регуляторов громкости в радиоприёмниках.
'
+ +'
'
+ );
+ h += makeCard('example', 'Гирлянда — последовательная цепь', '§ 24.3',
+ 'В старых ёлочных гирляндах все лампочки соединены последовательно. Каждой достаётся $220/N$ Вольт, где $N$ — число лампочек.
'
+ +'Минус: если перегорит одна — погаснут все! Поэтому современные гирлянды чаще делают по секциям с шунтирующими элементами.
'
+ );
+
+ /* IV1 — реостат-симулятор */
+ h += ''
+ +''
+ +'
Двигай движок реостата — увидь, как меняется ток и яркость лампы. Это последовательная цепь.
'
+ +'
'
+ +''
+ +'
'
+ +'
'
+ +'
'
+ +'$R_{реост}$ = 10 Ом, $R_{лампы} = 12$ Ом, $R_{общ}$ = 22 Ом'
+ +'$I = U/R$ при $U = 12$ В: 0.55 А'
+ +'
'
+ +'
';
+
+ /* IV2 — калькулятор */
+ h += '';
+
+ /* IV3 — DnD «верно/неверно» */
+ h += ''
+ +''
+ +'
'
+ +'
'
+ +'
'
+ +'
'
+ +'
';
+
+ /* IV4 — задачи */
+ h += ''
+ +''
+ +'
4+ — +15 XP.
'
+ +'
'
+ +'
Задача: 1 / 5Правильно: 0
'
+ +'
';
+
+ box.innerHTML = h + secNavFor('p24') + readButton('p24');
+ renderMath(box);
+ wireReadBtn('p24');
+
+ _initP24_rheostat();
+ _initP24_calc();
+ _initP24_dnd();
+ _initP24_tasks();
+}
+
+function _initP24_rheostat(){
+ const svg = document.getElementById('p24-sim'); if(!svg) return;
+ function draw(){
+ const p = +document.getElementById('p24-p').value;
+ document.getElementById('p24-pv').textContent = p+'%';
+ const Rrh = 20 * p / 100; /* 0..20 Ом */
+ const Rlamp = 12;
+ const Rtot = Rrh + Rlamp;
+ const I = 12 / Rtot;
+ document.getElementById('p24-rr').textContent = Rrh.toFixed(0);
+ document.getElementById('p24-rt').textContent = Rtot.toFixed(0);
+ document.getElementById('p24-it').textContent = I.toFixed(2);
+ /* SVG */
+ let s = '';
+ /* батарея */
+ s += window.PHYS.batteryEMF(60, 170, '12 В', 'h');
+ /* провод снизу */
+ s += window.PHYS.wire(60, 150, 60, 70);
+ s += window.PHYS.wire(60, 70, 130, 70);
+ /* реостат — длинная зигзаг полоска */
+ s += '';
+ /* зона до движка (включена) — затемнить */
+ s += '';
+ /* движок */
+ s += '';
+ s += '';
+ s += 'реостат '+Rrh.toFixed(0)+' Ом';
+ /* провод к лампе */
+ s += window.PHYS.wire(310, 70, 360, 70);
+ /* лампа */
+ s += window.PHYS.lightbulbSymbol(380, 70, 18);
+ /* яркость зависит от тока */
+ const glow = Math.min(1, I / 1.2);
+ s += '';
+ s += '';
+ /* провод вниз и обратно */
+ s += window.PHYS.wire(380, 90, 380, 170);
+ s += window.PHYS.wire(380, 170, 100, 170);
+ /* I-метка */
+ s += 'I = '+I.toFixed(2)+' А';
+ svg.innerHTML = s;
+ }
+ document.getElementById('p24-p').addEventListener('input', draw);
+ draw();
+}
+
+function _initP24_calc(){
+ function update(){
+ const U = +document.getElementById('p24-u').value;
+ const R1 = +document.getElementById('p24-r1').value;
+ const R2 = +document.getElementById('p24-r2').value;
+ document.getElementById('p24-uv').textContent = U;
+ document.getElementById('p24-r1v').textContent = R1;
+ document.getElementById('p24-r2v').textContent = R2;
+ const R = R1+R2;
+ const I = U/R;
+ const U1 = I*R1;
+ const U2 = I*R2;
+ document.getElementById('p24-rs').textContent = R;
+ document.getElementById('p24-is').textContent = I.toFixed(2);
+ document.getElementById('p24-u1').textContent = U1.toFixed(2);
+ document.getElementById('p24-u2').textContent = U2.toFixed(2);
+ document.getElementById('p24-check').textContent = (U1+U2).toFixed(2);
+ }
+ ['p24-u','p24-r1','p24-r2'].forEach(id => document.getElementById(id).addEventListener('input', update));
+ update();
+}
+
+function _initP24_dnd(){
+ const items = [
+ {id:'a', cat:'t', html:'$I = I_1 = I_2$'},
+ {id:'b', cat:'t', html:'$U = U_1 + U_2$'},
+ {id:'c', cat:'t', html:'$R = R_1 + R_2$'},
+ {id:'d', cat:'t', html:'обрыв одного $\\to$ нет тока во всей цепи'},
+ {id:'e', cat:'f', html:'$U = U_1 = U_2$'},
+ {id:'f', cat:'f', html:'$I = I_1 + I_2$'},
+ {id:'g', cat:'f', html:'$1/R = 1/R_1 + 1/R_2$'},
+ {id:'h', cat:'f', html:'обрыв одного $\\to$ ток продолжает идти'}
+ ];
+ const dnd = setupSorter({ poolId:'p24-dnd-pool', scopeSelector:'#sec-p24', cats:['t','f'], items, columnLayout:false });
+ document.getElementById('p24-dnd-check').addEventListener('click', ()=>{
+ const fb = document.getElementById('p24-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='✓ Идеально! +15 XP. Послед.: одно $I$, складываются $U$ и $R$.'; addXp(15,'p24-dnd'); bumpProgress('p24', 20); renderMath(fb); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Эти правила — для параллельного соединения.'; renderMath(fb); }
+ });
+ document.getElementById('p24-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p24-dnd-fb'); fb.style.display='none'; });
+}
+
+function _initP24_tasks(){
+ const TASKS = [
+ {q:'$R_1 = 4$, $R_2 = 6$ Ом последовательно, $U = 20$ В. Найди $I$ (А).', ans:2, tol:0.05, why:'$R = 10$, $I = 20/10 = 2$ А.'},
+ {q:'$R_1 = 3$, $R_2 = 5$ Ом, $I = 2$ А. Найди $U_2$ (В).', ans:10, tol:0.5, why:'$U_2 = I R_2 = 2 \\cdot 5 = 10$ В.'},
+ {q:'Три одинаковых лампы $R = 50$ Ом каждая, последовательно, $U = 90$ В. Найди $I$ (А).', ans:0.6, tol:0.02, why:'$R = 150$, $I = 90/150 = 0{,}6$ А.'},
+ {q:'$R_1 = 5$, $R_2 = ?$ последовательно. $U = 30$ В, $I = 2$ А. Найди $R_2$ (Ом).', ans:10, tol:0.5, why:'$R = 30/2 = 15$, $R_2 = 15 - 5 = 10$ Ом.'},
+ {q:'Реостат $R = 0..50$ Ом + лампа $R_л = 10$ Ом, $U = 12$ В. При каком положении реостата (Ом) ток будет $0{,}2$ А?', ans:50, tol:1, why:'$R_{общ} = U/I = 60$, $R_{реост} = 60 - 10 = 50$ Ом.'}
+ ];
+ let i = 0, ok = 0, done = 0, awarded = false;
+ function render(){
+ const t = TASKS[i]; const wrap = document.getElementById('p24-task'); if(!wrap) return;
+ wrap.innerHTML =
+ 'Задача '+(i+1)+'. '+t.q+'
'
+ +''
+ +''
+ +''
+ +'
'
+ +''+t.why+'
'
+ +'';
+ document.getElementById('p24-task-i').textContent = (i+1);
+ document.getElementById('p24-task-ok').textContent = ok;
+ document.getElementById('p24-task-go').addEventListener('click', ()=>{
+ const v = parseFloat((document.getElementById('p24-task-inp').value || '').replace(',','.'));
+ const fb = document.getElementById('p24-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='✓ Верно! '+t.why; addXp(4,'p24-task'); bumpProgress('p24', 6); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
+ document.getElementById('p24-task-ok').textContent = ok;
+ renderMath(wrap);
+ if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p24-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p24-task-bonus'); bumpProgress('p24', 15); }, 600); }
+ });
+ document.getElementById('p24-task-hint').addEventListener('click', ()=>{ document.getElementById('p24-task-hint-txt').classList.toggle('show'); });
+ document.getElementById('p24-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
+ renderMath(wrap);
+ }
+ render();
+}
+
+/* ======== §25 — Параллельное соединение ======== */
+function build_p25(){
+ const box = document.getElementById('p25-body');
+ let h = '';
+
+ h += makeCard('theory', 'Правила параллельного соединения', '§ 25.1',
+ 'Если резисторы соединены «бок о бок», между двумя одинаковыми узлами — это параллельное соединение.
'
+ +''
+ +'- Напряжение одинаковое: $U = U_1 = U_2$ (один и тот же «перепад высоты» на всех ветках).
'
+ +'- Токи складываются: $I = I_1 + I_2$.
'
+ +'- Сопротивления через обратные величины: $\\dfrac{1}{R} = \\dfrac{1}{R_1} + \\dfrac{1}{R_2}$.
'
+ +'
'
+ +'Поломка одного резистора не отключает остальные.
'
+ );
+ h += makeCard('rule', 'Полезные формулы', '§ 25.2',
+ 'Для двух резисторов:
'
+ +'$$R = \\dfrac{R_1 R_2}{R_1 + R_2}$$
'
+ +'Для $N$ одинаковых резисторов по $R$:
'
+ +'$$R_{общ} = \\dfrac{R}{N}$$
'
+ +'Общее $R$ меньше любого из частных. Это потому, что параллельные «ветви» дают много путей току.
'
+ );
+ h += makeCard('example', 'Где встречается', '§ 25.3',
+ ''
+ +'- В розетках дома: все приборы (свет, ТВ, чайник) подключены параллельно. Поэтому каждый получает 220 В.
'
+ +'- Поломка лампы не выключает остальные.
'
+ +'- В машине фары, магнитола, освещение салона — все параллельно через аккумулятор.
'
+ +'
'
+ );
+
+ /* IV1 — конструктор параллельной цепи */
+ h += ''
+ +''
+ +'
Меняй $R_1$ и $R_2$ — увидь токи в каждой ветви и общий $R$.
'
+ +'
'
+ +''
+ +''
+ +'
'
+ +'
'
+ +'
'
+ +'$R_{общ} = R_1 R_2 / (R_1+R_2)$ = 4 Ом'
+ +'При $U = 12$ В: $I_1 = U/R_1 = $ 2 А'
+ +'$I_2 = U/R_2 = $ 1 А'
+ +'Общий ток $I = I_1 + I_2$ = 3 А'
+ +'
'
+ +'
';
+
+ /* IV2 — викторина «послед. или паралл.» */
+ h += ''
+ +''
+ +'
По описанию определи тип соединения.
'
+ +'
'
+ +'
'
+ +'
Раунд: 1 / 6Правильно: 0
'
+ +'
';
+
+ /* IV3 — DnD формулы */
+ h += ''
+ +''
+ +'
Распредели формулы.
'
+ +'
'
+ +'
'
+ +'
'
+ +'
'
+ +'
';
+
+ /* IV4 — задачи */
+ h += ''
+ +''
+ +'
4+ — +15 XP.
'
+ +'
'
+ +'
Задача: 1 / 6Правильно: 0
'
+ +'
';
+
+ box.innerHTML = h + secNavFor('p25') + readButton('p25');
+ renderMath(box);
+ wireReadBtn('p25');
+
+ _initP25_calc();
+ _initP25_quiz();
+ _initP25_dnd();
+ _initP25_tasks();
+}
+
+function _initP25_calc(){
+ const svg = document.getElementById('p25-sim'); if(!svg) return;
+ function update(){
+ const R1 = +document.getElementById('p25-r1').value;
+ const R2 = +document.getElementById('p25-r2').value;
+ document.getElementById('p25-r1v').textContent = R1;
+ document.getElementById('p25-r2v').textContent = R2;
+ const Rt = (R1*R2)/(R1+R2);
+ const U = 12;
+ const I1 = U/R1;
+ const I2 = U/R2;
+ document.getElementById('p25-rt').textContent = Rt.toFixed(2);
+ document.getElementById('p25-i1').textContent = I1.toFixed(2);
+ document.getElementById('p25-i2').textContent = I2.toFixed(2);
+ document.getElementById('p25-it2').textContent = (I1+I2).toFixed(2);
+ /* SVG */
+ let s = '';
+ /* батарея слева */
+ s += window.PHYS.batteryEMF(60, 110, '12 В', 'h');
+ /* провод вверх */
+ s += window.PHYS.wire(60, 92, 60, 60);
+ s += window.PHYS.wire(60, 60, 380, 60);
+ /* провод вниз */
+ s += window.PHYS.wire(60, 130, 60, 170);
+ s += window.PHYS.wire(60, 170, 380, 170);
+ /* развилка верх */
+ s += window.PHYS.wire(150, 60, 150, 80);
+ s += window.PHYS.wire(270, 60, 270, 80);
+ /* верхняя ветвь */
+ s += window.PHYS.resistor(190, 80, R1, 'h');
+ /* нижняя ветвь */
+ s += window.PHYS.wire(150, 130, 150, 150);
+ s += window.PHYS.wire(270, 130, 270, 150);
+ s += window.PHYS.resistor(190, 130, R2, 'h');
+ /* подписи токов */
+ s += 'I₁ = '+I1.toFixed(2)+' А';
+ s += 'I₂ = '+I2.toFixed(2)+' А';
+ /* провода к развилке снизу */
+ s += window.PHYS.wire(150, 100, 270, 100);
+ s += window.PHYS.wire(150, 150, 270, 150);
+ svg.innerHTML = s;
+ }
+ document.getElementById('p25-r1').addEventListener('input', update);
+ document.getElementById('p25-r2').addEventListener('input', update);
+ update();
+}
+
+function _initP25_quiz(){
+ const QS = [
+ {sit:'Все лампы в гирлянде гаснут при поломке одной', ans:'S', why:'Это последовательное соединение.'},
+ {sit:'В розетке: ТВ и чайник работают независимо', ans:'P', why:'Параллельно — оба под 220 В.'},
+ {sit:'Лампа, амперметр, батарея — в одной петле', ans:'S', why:'Последовательно.'},
+ {sit:'Два резистора имеют одно и то же напряжение', ans:'P', why:'Параллельно — общее $U$.'},
+ {sit:'Через два резистора течёт один и тот же ток', ans:'S', why:'Последовательно — общее $I$.'},
+ {sit:'Общее $R$ меньше любого из $R_1$, $R_2$', ans:'P', why:'Параллельное соединение.'}
+ ];
+ let i = 0, ok = 0;
+ function render(){
+ const q = QS[i]; const wrap = document.getElementById('p25-quiz'); if(!wrap) return;
+ wrap.innerHTML =
+ ''+q.sit+'
'
+ +''
+ +''
+ +''
+ +'
'
+ +'';
+ document.getElementById('p25-quiz-r').textContent = (i+1);
+ document.getElementById('p25-quiz-ok').textContent = ok;
+ wrap.querySelectorAll('[data-pick]').forEach(btn=>{
+ btn.addEventListener('click', ()=>{
+ if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
+ const fb = document.getElementById('p25-quiz-fb');
+ if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p25-quiz'); bumpProgress('p25', 4); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
+ document.getElementById('p25-quiz-ok').textContent = ok;
+ });
+ });
+ }
+ document.getElementById('p25-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
+ render();
+}
+
+function _initP25_dnd(){
+ const items = [
+ {id:'a', cat:'ser', html:'$I = I_1 = I_2$'},
+ {id:'b', cat:'ser', html:'$U = U_1 + U_2$'},
+ {id:'c', cat:'ser', html:'$R = R_1 + R_2$'},
+ {id:'d', cat:'ser', html:'обрыв $\\to$ ничего не работает'},
+ {id:'e', cat:'par', html:'$U = U_1 = U_2$'},
+ {id:'f', cat:'par', html:'$I = I_1 + I_2$'},
+ {id:'g', cat:'par', html:'$1/R = 1/R_1 + 1/R_2$'},
+ {id:'h', cat:'par', html:'обрыв $\\to$ остальные работают'}
+ ];
+ const dnd = setupSorter({ poolId:'p25-dnd-pool', scopeSelector:'#sec-p25', cats:['ser','par'], items, columnLayout:false });
+ document.getElementById('p25-dnd-check').addEventListener('click', ()=>{
+ const fb = document.getElementById('p25-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='✓ Идеально! +15 XP. Главное отличие: послед.→общий I, паралл.→общее U.'; addXp(15,'p25-dnd'); bumpProgress('p25', 20); renderMath(fb); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; renderMath(fb); }
+ });
+ document.getElementById('p25-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p25-dnd-fb'); fb.style.display='none'; });
+}
+
+function _initP25_tasks(){
+ const TASKS = [
+ {q:'$R_1 = 6$, $R_2 = 12$ Ом параллельно. Найди $R_{общ}$ (Ом).', ans:4, tol:0.1, why:'$R = 6\\cdot12/(6+12) = 72/18 = 4$ Ом.'},
+ {q:'Два резистора по $R = 10$ Ом параллельно. $R_{общ}$ (Ом)?', ans:5, tol:0.1, why:'$R/2 = 5$ Ом.'},
+ {q:'$R_1 = R_2 = R_3 = 9$ Ом, все параллельно. $R_{общ}$ (Ом)?', ans:3, tol:0.1, why:'$R/N = 9/3 = 3$ Ом.'},
+ {q:'Параллельно $R_1 = 4$, $R_2 = 4$ Ом, $U = 12$ В. Найди ток в одной ветви (А).', ans:3, tol:0.1, why:'$I_1 = U/R_1 = 12/4 = 3$ А.'},
+ {q:'$R_1 = 6$, $R_2 = ?$ параллельно, $R_{общ} = 4$ Ом. Найди $R_2$.', ans:12, tol:0.3, why:'$1/4 = 1/6 + 1/R_2 \\Rightarrow 1/R_2 = 1/12 \\Rightarrow R_2 = 12$ Ом.'},
+ {q:'Параллельно к 220 В подключены утюг ($R = 44$ Ом) и лампа ($R = 220$ Ом). Какой общий ток (А)?', ans:6, tol:0.2, why:'$I_1 = 220/44 = 5$, $I_2 = 220/220 = 1$, $I = 6$ А.'}
+ ];
+ let i = 0, ok = 0, done = 0, awarded = false;
+ function render(){
+ const t = TASKS[i]; const wrap = document.getElementById('p25-task'); if(!wrap) return;
+ wrap.innerHTML =
+ 'Задача '+(i+1)+'. '+t.q+'
'
+ +''
+ +''
+ +''
+ +'
'
+ +''+t.why+'
'
+ +'';
+ document.getElementById('p25-task-i').textContent = (i+1);
+ document.getElementById('p25-task-ok').textContent = ok;
+ document.getElementById('p25-task-go').addEventListener('click', ()=>{
+ const v = parseFloat((document.getElementById('p25-task-inp').value || '').replace(',','.'));
+ const fb = document.getElementById('p25-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='✓ Верно! '+t.why; addXp(4,'p25-task'); bumpProgress('p25', 6); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
+ document.getElementById('p25-task-ok').textContent = ok;
+ renderMath(wrap);
+ if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p25-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p25-task-bonus'); bumpProgress('p25', 15); }, 600); }
+ });
+ document.getElementById('p25-task-hint').addEventListener('click', ()=>{ document.getElementById('p25-task-hint-txt').classList.toggle('show'); });
+ document.getElementById('p25-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);