diff --git a/frontend/textbooks/physics_10_ch4.html b/frontend/textbooks/physics_10_ch4.html
index 124d8d6..be929a3 100644
--- a/frontend/textbooks/physics_10_ch4.html
+++ b/frontend/textbooks/physics_10_ch4.html
@@ -622,52 +622,966 @@ function wireReadBtn(paraId){
function build_p25(){
const box = document.getElementById('p25-body');
let html = '';
- html += makeCard('theory', "ЭДС источника тока", "§25", `
-
ЭДС источника тока — этот параграф в разработке (Phase 1+).
- Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.
-
- Phase 0: создан скелет учебника. Phase 4+: наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
-
+
+ /* THEORY 1 — Электрический ток и условия его существования */
+ html += makeCard('theory', "Электрический ток и условия его существования", "§25", `
+ Электрический ток — упорядоченное движение электрических зарядов (свободных носителей: электронов в металлах, ионов в электролитах и т. д.).
+ Сила тока $I$ — заряд, проходящий через сечение проводника за единицу времени:
+ $$I = \\dfrac{q}{t}$$
+ Единица: Ампер (А) $= 1$ Кл / 1 с.
+ Условия существования постоянного тока:
+
+ Свободные заряженные частицы в проводнике.
+ Электрическое поле в проводнике (поддерживается источником тока).
+ Замкнутая цепь.
+
+ Если поле не поддерживать — заряды перераспределятся и ток прекратится за доли секунды.
`);
+
+ /* THEORY 2 — Сторонние силы. ЭДС */
+ html += makeCard('rule', "Сторонние силы. ЭДС", "§25", `
+ Сторонние силы — силы неэлектрической природы, которые в источнике тока производят работу по разделению зарядов и поддерживают разность потенциалов на полюсах. Виды сторонних сил:
+
+ Химические — в гальванических элементах и аккумуляторах.
+ Механические — в генераторах (вращение ротора).
+ Световые — в фотоэлементах (солнечных батареях).
+ Тепловые — в термоэлементах.
+
+ ЭДС источника $\\mathcal{E}$ — отношение работы сторонних сил $A_{ст}$ по перемещению заряда $q$ внутри источника к самому заряду:
+ $$\\mathcal{E} = \\dfrac{A_{ст}}{q}$$
+ Единица: Вольт (В) — та же, что для напряжения.
+ ЭДС — характеристика источника, не зависит от заряда: при $q = 1$ Кл работа сторонних сил равна $\\mathcal{E}$ Дж.
+ `);
+
+ /* THEORY 3 — Различие ЭДС и напряжения */
+ html += makeCard('example', "Различие ЭДС и напряжения на полюсах", "§25", `
+ Разомкнутая цепь (ток не течёт): напряжение на клеммах равно ЭДС:
+ $$U_{кл} = \\mathcal{E}$$
+ Замкнутая цепь (ток $I$ течёт): напряжение на клеммах меньше ЭДС:
+ $$U_{кл} = \\mathcal{E} - I r$$
+ где $r$ — внутреннее сопротивление источника.
+ Внутреннее сопротивление возникает из-за движения зарядов внутри самого источника (электролит в батарейке, обмотка в генераторе).
+ Пример. Новая батарейка АА: $\\mathcal{E} \\approx 1{,}5$ В, $r \\approx 0{,}2$ Ом. Старая батарейка — $r$ может вырасти до нескольких ом, и напряжение на клеммах при том же токе падает заметно.
+ `);
+
+ /* INTERACTIVE 1 — Источник тока: разомкнутая vs замкнутая цепь */
+ html += `
+
+
Меняй $\\mathcal{E}$, $r$, $R$ и переключатель цепи. Смотри, как меняется ток и показания вольтметра на клеммах.
+
+ $\\mathcal{E}$: 4.5 В
+ $r$: 0.5 Ом
+ $R$: 10 Ом
+
+
+ Замкнуто
+ Разомкнуто
+
+
+
+
+
+
`;
+
+ /* INTERACTIVE 2 — Калькулятор ЭДС */
+ html += `
+
+
$\\mathcal{E} = A_{ст}/q$. Выбери, что искать.
+
+ Найти $\\mathcal{E}$
+ Найти $A_{ст}$
+ Найти $q$
+
+
+
+ Вычислить
+
+
+
`;
+
+ /* INTERACTIVE 3 — Какие силы? */
+ html += `
+
+
Выбери природу сторонних сил для каждого источника тока.
+
Задача 1 / 6 Очки: 0 / 6
+
+
+
+
Начать заново
+
`;
+
+ /* INTERACTIVE 4 — Тренажёр ЭДС */
+ html += `
+
+
5 задач. Допуск $\\pm 5\\%$.
+
Задача 1 / 5 Очки: 0 / 5
+
+
+ ответ =
+
+ Проверить
+ Заново
+
+
+
`;
+
html += secNav(null, 'p26');
html += readButton('p25');
+
box.innerHTML = html;
renderMath(box);
+
+ /* IV1 — Разомкнутая vs замкнутая цепь */
+ (function(){
+ const svg = document.getElementById('p25-iv1-svg');
+ const ES = document.getElementById('p25-iv1-E');
+ const rS = document.getElementById('p25-iv1-r');
+ const RS = document.getElementById('p25-iv1-R');
+ const EL = document.getElementById('p25-iv1-EL');
+ const rL = document.getElementById('p25-iv1-rL');
+ const RL = document.getElementById('p25-iv1-RL');
+ const bCl = document.getElementById('p25-iv1-cl');
+ const bOp = document.getElementById('p25-iv1-op');
+ const out = document.getElementById('p25-iv1-out');
+ const seen = new Set();
+ let _done = false;
+ let closed = true;
+
+ function setClosed(v){
+ closed = v;
+ if(v){ bCl.classList.add('primary'); bOp.classList.remove('primary'); }
+ else { bOp.classList.add('primary'); bCl.classList.remove('primary'); }
+ render();
+ }
+
+ function render(){
+ const E = +ES.value, r = +rS.value, R = +RS.value;
+ EL.textContent = E.toFixed(1);
+ rL.textContent = r.toFixed(1);
+ RL.textContent = R.toFixed(0);
+
+ const I = closed ? E / (R + r) : 0;
+ const Ucl = closed ? (E - I*r) : E;
+
+ // Раскладка: батарея слева, резистор справа, провода сверху/снизу, вольтметр сверху над клеммами
+ const W = 480, H = 260;
+ let g = '';
+ g += ' ';
+ g += 'Электрическая цепь ';
+
+ // Координаты ключевых точек
+ const battX = 110, battY = 150;
+ const resX = 360, resY = 150;
+ const wireTopY = 80;
+ const wireBotY = 220;
+
+ // Источник с внутренним сопротивлением: батарея + маленький резистор r
+ g += PHYS.batteryEMF(battX, battY, E.toFixed(1), 'v');
+ // r — маленький резистор справа от батареи
+ g += ' ';
+ g += 'r='+r.toFixed(1)+' ';
+ // Внешняя нагрузка
+ g += PHYS.resistor(resX, resY, R.toFixed(0), 'v');
+
+ // Провода: верх — батарея(+) → резистор; низ — резистор → батарея(−)
+ // Верх: от точки над батареей до точки над резистором
+ const topL_x = battX, topR_x = resX;
+ const botL_x = battX+25, botR_x = resX;
+ // Вертикальный провод от батареи вверх к шине
+ g += PHYS.wire(topL_x, battY-18, topL_x, wireTopY);
+ g += PHYS.wire(topL_x, wireTopY, topR_x, wireTopY);
+ g += PHYS.wire(topR_x, wireTopY, topR_x, resY-20);
+
+ // Нижний провод (с разрывом если разомкнуто)
+ g += PHYS.wire(botL_x, battY+6, botL_x, wireBotY);
+ if(closed){
+ g += PHYS.wire(botL_x, wireBotY, botR_x, wireBotY);
+ } else {
+ // Разрыв в середине
+ const midX = (botL_x + botR_x)/2;
+ g += PHYS.wire(botL_x, wireBotY, midX-18, wireBotY);
+ g += PHYS.wire(midX+18, wireBotY, botR_x, wireBotY);
+ // ключ-разрыв
+ g += ' ';
+ g += ' ';
+ g += ' ';
+ g += 'разомкнуто ';
+ }
+ g += PHYS.wire(botR_x, wireBotY, botR_x, resY+20);
+
+ // Вольтметр между клеммами источника (поперёк) — слева от батареи
+ const volX = 50, volY = 150;
+ g += PHYS.voltmeterSymbol(volX, volY, 16);
+ // провода от вольтметра к клеммам батареи
+ g += PHYS.wire(volX, volY-16, volX, wireTopY);
+ g += PHYS.wire(volX, wireTopY, topL_x, wireTopY);
+ g += PHYS.wire(volX, volY+16, volX, wireBotY);
+ g += PHYS.wire(volX, wireBotY, botL_x, wireBotY);
+ // показание вольтметра
+ g += ''+Ucl.toFixed(2)+' В ';
+
+ // Стрелки тока (только если замкнуто и I>0)
+ if(closed && I > 0.001){
+ // Стрелка по верхнему проводу — слева направо
+ g += PHYS.drawArrow(180, wireTopY, 240, wireTopY, '#dc2626', 2.4, 9);
+ g += 'I = '+I.toFixed(2)+' А ';
+ } else if(!closed) {
+ g += 'I = 0 ';
+ }
+
+ svg.innerHTML = g;
+
+ // Текстовый вывод
+ let txt = '';
+ if(closed){
+ txt += '$I = \\dfrac{\\mathcal{E}}{R+r} = \\dfrac{'+E.toFixed(1)+'}{'+R.toFixed(0)+'+'+r.toFixed(1)+'} = '+I.toFixed(3)+'$ А ';
+ txt += '$U_{кл} = \\mathcal{E} - Ir = '+E.toFixed(1)+' - '+I.toFixed(3)+'\\cdot '+r.toFixed(1)+' = '+Ucl.toFixed(2)+'$ В ';
+ } else {
+ txt += 'Разомкнуто: $I = 0$, $U_{кл} = \\mathcal{E} = '+E.toFixed(1)+'$ В ';
+ }
+ out.innerHTML = txt;
+ renderMath(out);
+
+ seen.add((closed?'C':'O')+':'+E.toFixed(1)+':'+r.toFixed(1)+':'+R.toFixed(0));
+ if(!_done && seen.size >= 4){ _done = true; addXp(10, 'p25-iv1'); bumpProgress('p25', 15); }
+ }
+ bCl.addEventListener('click', () => setClosed(true));
+ bOp.addEventListener('click', () => setClosed(false));
+ ES.addEventListener('input', render);
+ rS.addEventListener('input', render);
+ RS.addEventListener('input', render);
+ setClosed(true);
+ })();
+
+ /* IV2 — Калькулятор ЭДС */
+ (function(){
+ let mode = 'E';
+ const bE = document.getElementById('p25-iv2-mE');
+ const bA = document.getElementById('p25-iv2-mA');
+ const bQ = document.getElementById('p25-iv2-mQ');
+ const inputs = document.getElementById('p25-iv2-inputs');
+ const out = document.getElementById('p25-iv2-out');
+ const seen = new Set();
+ let _done = false;
+
+ function setMode(m){
+ mode = m;
+ [bE,bA,bQ].forEach(x => x.classList.remove('primary'));
+ ({E:bE, A:bA, Q:bQ}[m]).classList.add('primary');
+ if(m === 'E'){
+ inputs.innerHTML = '$A_{ст}$ (Дж): '
+ + '$q$ (Кл): ';
+ } else if(m === 'A'){
+ inputs.innerHTML = '$\\mathcal{E}$ (В): '
+ + '$q$ (Кл): ';
+ } else {
+ inputs.innerHTML = '$A_{ст}$ (Дж): '
+ + '$\\mathcal{E}$ (В): ';
+ }
+ renderMath(inputs);
+ out.innerHTML = '';
+ }
+
+ function calc(){
+ let html = '';
+ if(mode === 'E'){
+ const A = parseFloat(document.getElementById('p25-iv2-A').value);
+ const q = parseFloat(document.getElementById('p25-iv2-q').value);
+ if(!isFinite(A) || !isFinite(q) || q <= 0){ out.innerHTML = 'Введи корректные значения. '; return; }
+ const E = A / q;
+ html += '$\\mathcal{E} = \\dfrac{A_{ст}}{q} = \\dfrac{'+A+'}{'+q+'} = '+E.toFixed(3)+'$ В ';
+ } else if(mode === 'A'){
+ const E = parseFloat(document.getElementById('p25-iv2-E').value);
+ const q = parseFloat(document.getElementById('p25-iv2-q').value);
+ if(!isFinite(E) || !isFinite(q)){ out.innerHTML = 'Введи корректные значения. '; return; }
+ const A = E * q;
+ html += '$A_{ст} = \\mathcal{E}\\cdot q = '+E+'\\cdot '+q+' = '+A.toFixed(3)+'$ Дж ';
+ } else {
+ const A = parseFloat(document.getElementById('p25-iv2-A').value);
+ const E = parseFloat(document.getElementById('p25-iv2-E').value);
+ if(!isFinite(A) || !isFinite(E) || E <= 0){ out.innerHTML = 'Введи корректные значения. '; return; }
+ const q = A / E;
+ html += '$q = \\dfrac{A_{ст}}{\\mathcal{E}} = \\dfrac{'+A+'}{'+E+'} = '+q.toFixed(3)+'$ Кл ';
+ }
+ out.innerHTML = html;
+ renderMath(out);
+ seen.add(mode+':'+Date.now());
+ if(!_done && seen.size >= 3){ _done = true; addXp(10, 'p25-iv2'); bumpProgress('p25', 15); }
+ }
+ bE.addEventListener('click', () => setMode('E'));
+ bA.addEventListener('click', () => setMode('A'));
+ bQ.addEventListener('click', () => setMode('Q'));
+ document.getElementById('p25-iv2-go').addEventListener('click', calc);
+ setMode('E');
+ })();
+
+ /* IV3 — Какие сторонние силы? */
+ (function(){
+ const OPTS = ['Химические','Механические','Световые','Тепловые'];
+ const Q = [
+ { q:'В гальваническом элементе (батарейке).', ans:0, why:'Реакция между электродами и электролитом разделяет заряды.' },
+ { q:'В генераторе электростанции.', ans:1, why:'Вращение ротора в магнитном поле разделяет заряды.' },
+ { q:'В фотоэлементе (солнечной батарее).', ans:2, why:'Световой поток выбивает электроны и создаёт ЭДС.' },
+ { q:'В аккумуляторе автомобиля.', ans:0, why:'Это тоже химический источник тока.' },
+ { q:'В термоэлементе (термопаре).', ans:3, why:'Разность температур контактов разных металлов создаёт ЭДС.' },
+ { q:'В велосипедной динамо-машине.', ans:1, why:'Вращение магнита от колеса — механическая сила.' }
+ ];
+ let i = 0, score = 0;
+ const qEl = document.getElementById('p25-iv3-q');
+ const oEl = document.getElementById('p25-iv3-opts');
+ const fb = document.getElementById('p25-iv3-fb');
+ const iEl = document.getElementById('p25-iv3-i');
+ const sEl = document.getElementById('p25-iv3-s');
+
+ function show(){
+ if(i >= Q.length){
+ qEl.innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length;
+ oEl.innerHTML = '';
+ if(score === Q.length){ addXp(15, 'p25-iv3'); bumpProgress('p25', 25); }
+ else if(score >= 4){ addXp(8, 'p25-iv3'); bumpProgress('p25', 15); }
+ return;
+ }
+ iEl.textContent = (i+1);
+ sEl.textContent = score;
+ qEl.innerHTML = Q[i].q;
+ oEl.innerHTML = OPTS.map((t, k) => '' + t + ' ').join('');
+ fb.style.display = 'none';
+ renderMath(qEl);
+ oEl.querySelectorAll('button').forEach(b => {
+ b.addEventListener('click', () => {
+ const v = +b.dataset.v;
+ if(v === Q[i].ans){ score++; feedback(fb, true, '✓ Верно! ' + Q[i].why + ' Дальше ▶'); }
+ else feedback(fb, false, '✗ Верно: ' + OPTS[Q[i].ans] + '. ' + Q[i].why + ' Дальше ▶');
+ sEl.textContent = score;
+ oEl.querySelectorAll('button').forEach(x => x.disabled = true);
+ i++;
+ setTimeout(show, 1800);
+ });
+ });
+ }
+ document.getElementById('p25-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); });
+ show();
+ })();
+
+ /* IV4 — Тренажёр ЭДС */
+ (function(){
+ const Q = [
+ { q:'Сторонние силы совершили работу $A = 10$ Дж при заряде $q = 5$ Кл. ЭДС в В?', ans:2, tol:0.1, hint:'$\\mathcal{E} = A/q = 10/5 = 2$ В.' },
+ { q:'Аккумулятор $\\mathcal{E} = 12$ В, $r = 0{,}5$ Ом, нагрузка $R = 5{,}5$ Ом. Сила тока в А?', ans:2, tol:0.1, hint:'$I = \\mathcal{E}/(R+r) = 12/6 = 2$ А.' },
+ { q:'Тот же аккумулятор. Напряжение на клеммах в В?', ans:11, tol:0.6, hint:'$U_{кл} = \\mathcal{E} - Ir = 12 - 2\\cdot 0{,}5 = 11$ В.' },
+ { q:'За $t = 5$ с через сечение прошёл заряд $q = 2$ Кл. Сила тока в А?', ans:0.4, tol:0.05, hint:'$I = q/t = 2/5 = 0{,}4$ А.' },
+ { q:'Идеальная батарейка $\\mathcal{E} = 1{,}5$ В, $r = 0$, $R = 3$ Ом. Сила тока в А?', ans:0.5, tol:0.05, hint:'$I = \\mathcal{E}/R = 1{,}5/3 = 0{,}5$ А.' }
+ ];
+ let i = 0, score = 0;
+ function show(){
+ if(i >= Q.length){
+ document.getElementById('p25-iv4-q').innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length;
+ if(score === Q.length){ addXp(15, 'p25-iv4'); bumpProgress('p25', 25); }
+ else if(score >= 3){ addXp(8, 'p25-iv4'); bumpProgress('p25', 15); }
+ return;
+ }
+ document.getElementById('p25-iv4-i').textContent = (i+1);
+ document.getElementById('p25-iv4-s').textContent = score;
+ document.getElementById('p25-iv4-q').innerHTML = Q[i].q;
+ document.getElementById('p25-iv4-ans').value = '';
+ renderMath(document.getElementById('p25-iv4-q'));
+ document.getElementById('p25-iv4-fb').style.display = 'none';
+ }
+ function go(){
+ if(i >= Q.length) return;
+ const fb = document.getElementById('p25-iv4-fb');
+ const raw = document.getElementById('p25-iv4-ans').value.replace(',', '.');
+ const ans = parseFloat(raw);
+ if(isNaN(ans)){ feedback(fb, false, '✗ Введи число.'); return; }
+ if(Math.abs(ans - Q[i].ans) <= Q[i].tol + 0.001){ score++; feedback(fb, true, '✓ Верно! '+Q[i].hint+' Дальше ▶'); }
+ else feedback(fb, false, '✗ Неверно. Ответ: $'+Q[i].ans+'$. '+Q[i].hint+' Дальше ▶');
+ document.getElementById('p25-iv4-s').textContent = score;
+ i++;
+ setTimeout(show, 1800);
+ }
+ document.getElementById('p25-iv4-go').addEventListener('click', go);
+ document.getElementById('p25-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); });
+ document.getElementById('p25-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); });
+ show();
+ })();
+
wireReadBtn('p25');
}
function build_p26(){
const box = document.getElementById('p26-body');
let html = '';
+
+ /* THEORY 1 — Закон Ома для полной цепи */
html += makeCard('theory', "Закон Ома для полной цепи", "§26", `
- Закон Ома для полной цепи — этот параграф в разработке (Phase 1+).
- Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.
-
- Phase 0: создан скелет учебника. Phase 4+: наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
-
+ Закон Ома для полной электрической цепи:
+ $$I = \\dfrac{\\mathcal{E}}{R + r}$$
+
+ $\\mathcal{E}$ — ЭДС источника (В)
+ $R$ — сопротивление внешней цепи (нагрузки) — Ом
+ $r$ — внутреннее сопротивление источника — Ом
+ $I$ — сила тока в цепи (А)
+
+ Эту формулу легко понять физически: ЭДС «толкает» ток через две последовательно соединённых «препятствия» — внешнее $R$ и внутреннее $r$.
+ Закон Ома для участка цепи (повторение из 8 класса): $I = U/R$. Это частный случай — для участка без источника.
`);
+
+ /* THEORY 2 — Напряжение и КПД источника */
+ html += makeCard('rule', "Напряжение на полюсах и КПД источника", "§26", `
+ Напряжение на внешней цепи (= на клеммах источника, когда есть ток):
+ $$U = IR = \\mathcal{E} - I r$$
+ Падение напряжения внутри источника: $\\mathcal{E} - U = Ir$.
+ КПД источника тока — отношение полезной мощности (на нагрузке) к полной мощности источника:
+ $$\\eta = \\dfrac{U}{\\mathcal{E}} = \\dfrac{R}{R+r}$$
+ Чем меньше $r$ (или больше $R$), тем выше КПД.
+ Максимальная мощность во внешней цепи достигается при $R = r$. При этом $\\eta = 50\\%$, а $P_{max} = \\dfrac{\\mathcal{E}^2}{4r}$.
+ `);
+
+ /* THEORY 3 — Короткое замыкание */
+ html += makeCard('example', "Короткое замыкание", "§26", `
+ Короткое замыкание (КЗ) — соединение клемм источника проводником с очень малым сопротивлением (когда $R \\ll r$ или $R \\approx 0$).
+ Ток короткого замыкания:
+ $$I_{кз} = \\dfrac{\\mathcal{E}}{r}$$
+ Это максимально возможный ток от данного источника. Если $r$ мало — $I_{кз}$ огромен. Последствия:
+
+ Перегрев проводов.
+ Расплавление изоляции.
+ Пожар.
+ Взрыв батареи (особенно у аккумуляторов).
+
+ Защита от КЗ:
+
+ Предохранители — плавкие или электронные.
+ Автоматические выключатели в щитке.
+ В бытовой технике — встроенная электронная защита.
+
+ Пример. Автомобильный аккумулятор $\\mathcal{E} = 12$ В, $r = 0{,}005$ Ом. $I_{кз} = 12/0{,}005 = 2400$ А — расплавит любой тонкий провод за секунды.
+ `);
+
+ /* INTERACTIVE 1 — Конструктор электрической цепи */
+ html += `
+
+
Двигай $\\mathcal{E}$, $r$, $R$. Смотри ток, напряжение на клеммах, мощность и КПД в реальном времени.
+
+ $\\mathcal{E}$: 6 В
+ $r$: 0.5 Ом
+ $R$: 5 Ом
+
+
+
+
+
+
⚠ Сопротивление почти ноль — это близко к режиму короткого замыкания!
+
`;
+
+ /* INTERACTIVE 2 — Универсальный калькулятор Ома */
+ html += `
+
+
$I = \\mathcal{E}/(R+r)$. Выбери, что искать.
+
+ Найти $I$
+ Найти $\\mathcal{E}$
+ Найти $R$
+ Найти $r$
+
+
+
+ Вычислить
+
+
+
`;
+
+ /* INTERACTIVE 3 — Что произойдёт с током? */
+ html += `
+
+
Опираясь на $I = \\mathcal{E}/(R+r)$, выбери, как изменится ток.
+
Задача 1 / 6 Очки: 0 / 6
+
+
+
+
Начать заново
+
`;
+
+ /* INTERACTIVE 4 — Тренажёр закона Ома */
+ html += `
+
+
6 задач. Допуск $\\pm 5\\%$.
+
Задача 1 / 6 Очки: 0 / 6
+
+
+ ответ =
+
+ Проверить
+ Заново
+
+
+
`;
+
html += secNav('p25', 'final4');
html += readButton('p26');
+
box.innerHTML = html;
renderMath(box);
+
+ /* IV1 — Конструктор цепи */
+ (function(){
+ const svg = document.getElementById('p26-iv1-svg');
+ const ES = document.getElementById('p26-iv1-E');
+ const rS = document.getElementById('p26-iv1-r');
+ const RS = document.getElementById('p26-iv1-R');
+ const EL = document.getElementById('p26-iv1-EL');
+ const rL = document.getElementById('p26-iv1-rL');
+ const RL = document.getElementById('p26-iv1-RL');
+ const out = document.getElementById('p26-iv1-out');
+ const warn = document.getElementById('p26-iv1-warn');
+ const seen = new Set();
+ let _done = false;
+
+ function render(){
+ const E = +ES.value, r = +rS.value, R = +RS.value;
+ EL.textContent = E.toFixed(1);
+ rL.textContent = r.toFixed(1);
+ RL.textContent = R.toFixed(1);
+
+ const I = E / (R + r);
+ const Ucl = E - I*r;
+ const Pvn = I*I * R;
+ const eta = R / (R + r) * 100;
+
+ const W = 480, H = 320;
+ let g = '';
+ g += ' ';
+ g += 'Полная электрическая цепь ';
+
+ // Прямоугольная цепь
+ const battX = 90, battY = 180;
+ const amX = 240, amY = 80; // амперметр сверху по центру
+ const resX = 390, resY = 180;
+ const volX = 60, volY = 240; // вольтметр снизу-слева
+
+ // Источник
+ g += PHYS.batteryEMF(battX, battY, E.toFixed(1), 'v');
+ // Внутреннее сопротивление r — рядом
+ g += ' ';
+ g += 'r='+r.toFixed(1)+' ';
+ // Внешняя нагрузка
+ g += PHYS.resistor(resX, resY, R.toFixed(1), 'v');
+ // Амперметр сверху
+ g += PHYS.ammeterSymbol(amX, amY, 16);
+
+ // Провода
+ // (+) батареи вверх → амперметр → к резистору
+ g += PHYS.wire(battX, battY-18, battX, amY);
+ g += PHYS.wire(battX, amY, amX-16, amY);
+ g += PHYS.wire(amX+16, amY, resX, amY);
+ g += PHYS.wire(resX, amY, resX, resY-20);
+
+ // (−) батареи вниз → к резистору снизу
+ g += PHYS.wire(battX+25, battY+6, battX+25, 270);
+ g += PHYS.wire(battX+25, 270, resX, 270);
+ g += PHYS.wire(resX, 270, resX, resY+20);
+
+ // Вольтметр между клеммами источника (по бокам, слева)
+ g += PHYS.voltmeterSymbol(volX, volY, 16);
+ g += PHYS.wire(volX, volY-16, volX, amY);
+ g += PHYS.wire(volX, amY, battX, amY);
+ g += PHYS.wire(volX, volY+16, volX, 270);
+ g += PHYS.wire(volX, 270, battX+25, 270);
+ g += ''+Ucl.toFixed(2)+' В ';
+
+ // Стрелка тока и подпись возле амперметра
+ g += PHYS.drawArrow(amX-50, amY-22, amX-18, amY-22, '#dc2626', 2.2, 9);
+ g += 'I = '+I.toFixed(2)+' А ';
+
+ svg.innerHTML = g;
+
+ let txt = '';
+ txt += '$I = \\dfrac{\\mathcal{E}}{R+r} = \\dfrac{'+E.toFixed(1)+'}{'+R.toFixed(1)+'+'+r.toFixed(1)+'} = '+I.toFixed(3)+'$ А ';
+ txt += '$U_{кл} = '+Ucl.toFixed(2)+'$ В $P_{вн} = I^2R = '+Pvn.toFixed(2)+'$ Вт $\\eta = '+eta.toFixed(1)+'\\%$ ';
+ out.innerHTML = txt;
+ renderMath(out);
+
+ warn.style.display = (R < 0.5) ? 'block' : 'none';
+
+ seen.add(E.toFixed(1)+':'+r.toFixed(1)+':'+R.toFixed(1));
+ if(!_done && seen.size >= 4){ _done = true; addXp(10, 'p26-iv1'); bumpProgress('p26', 15); }
+ }
+ ES.addEventListener('input', render);
+ rS.addEventListener('input', render);
+ RS.addEventListener('input', render);
+ render();
+ })();
+
+ /* IV2 — Универсальный калькулятор */
+ (function(){
+ let mode = 'I';
+ const bI = document.getElementById('p26-iv2-mI');
+ const bE = document.getElementById('p26-iv2-mE');
+ const bR = document.getElementById('p26-iv2-mR');
+ const br = document.getElementById('p26-iv2-mr');
+ const inputs = document.getElementById('p26-iv2-inputs');
+ const out = document.getElementById('p26-iv2-out');
+ const seen = new Set();
+ let _done = false;
+
+ function setMode(m){
+ mode = m;
+ [bI,bE,bR,br].forEach(x => x.classList.remove('primary'));
+ ({I:bI, E:bE, R:bR, r:br}[m]).classList.add('primary');
+ if(m === 'I'){
+ inputs.innerHTML = '$\\mathcal{E}$ (В): '
+ + '$R$ (Ом): '
+ + '$r$ (Ом): ';
+ } else if(m === 'E'){
+ inputs.innerHTML = '$I$ (А): '
+ + '$R$ (Ом): '
+ + '$r$ (Ом): ';
+ } else if(m === 'R'){
+ inputs.innerHTML = '$\\mathcal{E}$ (В): '
+ + '$I$ (А): '
+ + '$r$ (Ом): ';
+ } else {
+ inputs.innerHTML = '$\\mathcal{E}$ (В): '
+ + '$I$ (А): '
+ + '$R$ (Ом): ';
+ }
+ renderMath(inputs);
+ out.innerHTML = '';
+ }
+
+ function val(id){ return parseFloat(document.getElementById(id).value); }
+
+ function calc(){
+ let html = '';
+ if(mode === 'I'){
+ const E = val('p26-iv2-E'), R = val('p26-iv2-R'), r = val('p26-iv2-r');
+ if(!isFinite(E)||!isFinite(R)||!isFinite(r)||(R+r)<=0){ out.innerHTML='Введи корректные значения. '; return; }
+ const I = E/(R+r);
+ html += '$I = \\dfrac{\\mathcal{E}}{R+r} = \\dfrac{'+E+'}{'+R+'+'+r+'} = '+I.toFixed(3)+'$ А ';
+ } else if(mode === 'E'){
+ const I = val('p26-iv2-I'), R = val('p26-iv2-R'), r = val('p26-iv2-r');
+ if(!isFinite(I)||!isFinite(R)||!isFinite(r)){ out.innerHTML='Введи корректные значения. '; return; }
+ const E = I*(R+r);
+ html += '$\\mathcal{E} = I(R+r) = '+I+'\\cdot ('+R+'+'+r+') = '+E.toFixed(3)+'$ В ';
+ } else if(mode === 'R'){
+ const E = val('p26-iv2-E'), I = val('p26-iv2-I'), r = val('p26-iv2-r');
+ if(!isFinite(E)||!isFinite(I)||!isFinite(r)||I<=0){ out.innerHTML='Введи корректные значения. '; return; }
+ const R = E/I - r;
+ html += '$R = \\dfrac{\\mathcal{E}}{I} - r = \\dfrac{'+E+'}{'+I+'} - '+r+' = '+R.toFixed(3)+'$ Ом ';
+ } else {
+ const E = val('p26-iv2-E'), I = val('p26-iv2-I'), R = val('p26-iv2-R');
+ if(!isFinite(E)||!isFinite(I)||!isFinite(R)||I<=0){ out.innerHTML='Введи корректные значения. '; return; }
+ const r = E/I - R;
+ html += '$r = \\dfrac{\\mathcal{E}}{I} - R = \\dfrac{'+E+'}{'+I+'} - '+R+' = '+r.toFixed(3)+'$ Ом ';
+ }
+ out.innerHTML = html;
+ renderMath(out);
+ seen.add(mode+':'+Date.now());
+ if(!_done && seen.size >= 3){ _done = true; addXp(10, 'p26-iv2'); bumpProgress('p26', 15); }
+ }
+ bI.addEventListener('click', () => setMode('I'));
+ bE.addEventListener('click', () => setMode('E'));
+ bR.addEventListener('click', () => setMode('R'));
+ br.addEventListener('click', () => setMode('r'));
+ document.getElementById('p26-iv2-go').addEventListener('click', calc);
+ setMode('I');
+ })();
+
+ /* IV3 — Что произойдёт с током? */
+ (function(){
+ const OPTS = ['Увеличится','Уменьшится','Не изменится'];
+ const Q = [
+ { q:'Увеличить $R$ (при постоянных $\\mathcal{E}$ и $r$).', ans:1, why:'$I = \\mathcal{E}/(R+r)$ — рост знаменателя уменьшает ток.' },
+ { q:'Уменьшить $R$ (при постоянных $\\mathcal{E}$ и $r$).', ans:0, why:'Знаменатель уменьшился — ток вырос.' },
+ { q:'Увеличить $\\mathcal{E}$ (при постоянных $R$ и $r$).', ans:0, why:'Числитель вырос — ток увеличился.' },
+ { q:'Уменьшить $\\mathcal{E}$ (при постоянных $R$ и $r$).', ans:1, why:'Числитель уменьшился — ток упал.' },
+ { q:'Разомкнуть цепь.', ans:1, why:'Цепь разорвана — ток падает до нуля.' },
+ { q:'Замкнуть цепь накоротко ($R \\to 0$).', ans:0, why:'$I \\to \\mathcal{E}/r$ — это максимально возможный ток.' }
+ ];
+ let i = 0, score = 0;
+ const qEl = document.getElementById('p26-iv3-q');
+ const oEl = document.getElementById('p26-iv3-opts');
+ const fb = document.getElementById('p26-iv3-fb');
+ const iEl = document.getElementById('p26-iv3-i');
+ const sEl = document.getElementById('p26-iv3-s');
+
+ function show(){
+ if(i >= Q.length){
+ qEl.innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length;
+ oEl.innerHTML = '';
+ if(score === Q.length){ addXp(15, 'p26-iv3'); bumpProgress('p26', 25); }
+ else if(score >= 4){ addXp(8, 'p26-iv3'); bumpProgress('p26', 15); }
+ return;
+ }
+ iEl.textContent = (i+1);
+ sEl.textContent = score;
+ qEl.innerHTML = Q[i].q;
+ oEl.innerHTML = OPTS.map((t, k) => '' + t + ' ').join('');
+ fb.style.display = 'none';
+ renderMath(qEl);
+ oEl.querySelectorAll('button').forEach(b => {
+ b.addEventListener('click', () => {
+ const v = +b.dataset.v;
+ if(v === Q[i].ans){ score++; feedback(fb, true, '✓ Верно! ' + Q[i].why + ' Дальше ▶'); }
+ else feedback(fb, false, '✗ Верно: ' + OPTS[Q[i].ans] + '. ' + Q[i].why + ' Дальше ▶');
+ sEl.textContent = score;
+ oEl.querySelectorAll('button').forEach(x => x.disabled = true);
+ i++;
+ setTimeout(show, 1800);
+ });
+ });
+ }
+ document.getElementById('p26-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); });
+ show();
+ })();
+
+ /* IV4 — Тренажёр закона Ома */
+ (function(){
+ const Q = [
+ { q:'$\\mathcal{E} = 12$ В, $r = 1$ Ом, $R = 5$ Ом. Сила тока $I$ в А?', ans:2, tol:0.1, hint:'$I = \\mathcal{E}/(R+r) = 12/6 = 2$ А.' },
+ { q:'Те же данные: $\\mathcal{E} = 12$ В, $r = 1$ Ом, $R = 5$ Ом. Напряжение на клеммах $U_{кл}$ в В?', ans:10, tol:0.5, hint:'$U_{кл} = IR = 2\\cdot 5 = 10$ В.' },
+ { q:'$\\mathcal{E} = 10$ В, $r = 0{,}5$ Ом. Ток короткого замыкания в А?', ans:20, tol:1, hint:'$I_{кз} = \\mathcal{E}/r = 10/0{,}5 = 20$ А.' },
+ { q:'$\\mathcal{E} = 6$ В, $r = 0{,}5$ Ом, $R = 2{,}5$ Ом. КПД источника в %?', ans:83, tol:1, hint:'$\\eta = R/(R+r) = 2{,}5/3 \\approx 0{,}833 \\approx 83\\%$.' },
+ { q:'Батарея $\\mathcal{E} = 4{,}5$ В, $I = 0{,}9$ А, $r = 0{,}5$ Ом. Внешнее сопротивление $R$ в Ом?', ans:4.5, tol:0.3, hint:'$R = \\mathcal{E}/I - r = 5 - 0{,}5 = 4{,}5$ Ом.' },
+ { q:'При условии $R = r$ — каков КПД источника в %?', ans:50, tol:1, hint:'$\\eta = R/(R+r) = R/(2R) = 0{,}5 = 50\\%$.' }
+ ];
+ let i = 0, score = 0;
+ function show(){
+ if(i >= Q.length){
+ document.getElementById('p26-iv4-q').innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length;
+ if(score === Q.length){ addXp(15, 'p26-iv4'); bumpProgress('p26', 25); }
+ else if(score >= 4){ addXp(8, 'p26-iv4'); bumpProgress('p26', 15); }
+ return;
+ }
+ document.getElementById('p26-iv4-i').textContent = (i+1);
+ document.getElementById('p26-iv4-s').textContent = score;
+ document.getElementById('p26-iv4-q').innerHTML = Q[i].q;
+ document.getElementById('p26-iv4-ans').value = '';
+ renderMath(document.getElementById('p26-iv4-q'));
+ document.getElementById('p26-iv4-fb').style.display = 'none';
+ }
+ function go(){
+ if(i >= Q.length) return;
+ const fb = document.getElementById('p26-iv4-fb');
+ const raw = document.getElementById('p26-iv4-ans').value.replace(',', '.');
+ const ans = parseFloat(raw);
+ if(isNaN(ans)){ feedback(fb, false, '✗ Введи число.'); return; }
+ if(Math.abs(ans - Q[i].ans) <= Q[i].tol + 0.001){ score++; feedback(fb, true, '✓ Верно! '+Q[i].hint+' Дальше ▶'); }
+ else feedback(fb, false, '✗ Неверно. Ответ: $'+Q[i].ans+'$. '+Q[i].hint+' Дальше ▶');
+ document.getElementById('p26-iv4-s').textContent = score;
+ i++;
+ setTimeout(show, 1800);
+ }
+ document.getElementById('p26-iv4-go').addEventListener('click', go);
+ document.getElementById('p26-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); });
+ document.getElementById('p26-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); });
+ show();
+ })();
+
wireReadBtn('p26');
}
function build_final4(){
const box = document.getElementById('final4-body');
let html = '';
- html += makeCard('theory', "Финал главы 4", "★", `
- Финал главы 4 — этот параграф в разработке (Phase 1+).
- Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.
-
- Phase 0: создан скелет учебника. Phase 4+: наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
-
- `);
+
+ /* Часть А — Шпаргалка главы (2 mini-карточки) */
+ const SHEET = [
+ { t:'§ 25 · ЭДС источника', icon:' ', body:'$\\mathcal{E} = A_{ст}/q$. Сторонние силы: химические, механические, световые, тепловые. $I = q/t$ (А).' },
+ { t:'§ 26 · Закон Ома для полной цепи', icon:' ', body:'$I = \\mathcal{E}/(R+r)$. $U_{кл} = \\mathcal{E} - Ir$. $\\eta = R/(R+r)$. КЗ: $I_{кз} = \\mathcal{E}/r$.' },
+ ];
+
+ html += `
+
+
+
Ключевые формулы и идеи двух параграфов главы — повтори перед битвой с боссами.
+
+ ${SHEET.map(s => `
`).join('')}
+
+
+
`;
+
+ /* Часть Б — 5 боссов intro */
+ html += `
+
+
+
5 интегрированных задач по §§25–26. За каждого побеждённого босса: +10 XP, +18% к прогрессу . Победишь всех — ачивка «Мастер тока» и +50 XP бонус .
+
Допуск $\\pm 5\\%$.
+
+
`;
+
+ html += '
';
+
+ html += `
+
Прогресс по боссам
+
0 / 5 боссов побеждено
+
+
+
Мастер тока
+
Глава 4 пройдена! Все 5 боссов повержены. +50 XP бонус.
+
Дальше: Глава 5
+
+
`;
+
html += secNav('p26', null);
- html += readButton('final4');
+
box.innerHTML = html;
renderMath(box);
- wireReadBtn('final4');
+
+ /* Боссы */
+ const BOSSES = [
+ {
+ n:1, color:'#0ea5e9',
+ title:'Страж Силы Тока',
+ tag:'§ 25',
+ q:'Через сечение проводника прошёл заряд $q = 30$ Кл за время $t = 60$ с. Сила тока $I$ в А?',
+ ans:0.5, tol:0.05,
+ hint:'$I = q/t = 30/60 = 0{,}5$ А.'
+ },
+ {
+ n:2, color:'#10b981',
+ title:'Хранитель ЭДС',
+ tag:'§ 25',
+ q:'Сторонние силы совершили работу $A_{ст} = 18$ Дж при перемещении заряда $q = 6$ Кл. Найди ЭДС в В.',
+ ans:3, tol:0.2,
+ hint:'$\\mathcal{E} = A_{ст}/q = 18/6 = 3$ В.'
+ },
+ {
+ n:3, color:'#f59e0b',
+ title:'Повелитель Закона Ома',
+ tag:'§ 26',
+ q:'Источник $\\mathcal{E} = 24$ В, $r = 1$ Ом, нагрузка $R = 5$ Ом. Сила тока в А?',
+ ans:4, tol:0.2,
+ hint:'$I = \\mathcal{E}/(R+r) = 24/6 = 4$ А.'
+ },
+ {
+ n:4, color:'#7c3aed',
+ title:'Властелин КПД',
+ tag:'§ 26',
+ q:'$\\mathcal{E} = 10$ В, $r = 0{,}2$ Ом, $R = 4{,}8$ Ом. Найди КПД источника в %.',
+ ans:96, tol:1,
+ hint:'$\\eta = R/(R+r) = 4{,}8/5 = 0{,}96 = 96\\%$.'
+ },
+ {
+ n:5, color:'#dc2626',
+ title:'Магистр Постоянного Тока',
+ tag:'§§ 25–26',
+ q:'Аккумулятор $\\mathcal{E} = 6$ В, $r = 0{,}5$ Ом. При замыкании на лампочку напряжение на клеммах упало до $U_{кл} = 5$ В. Найди сопротивление лампочки в Ом.',
+ ans:2.5, tol:0.15,
+ hint:'$Ir = \\mathcal{E} - U_{кл} = 1$ В $\\Rightarrow I = 1/0{,}5 = 2$ А. $R = U_{кл}/I = 5/2 = 2{,}5$ Ом.'
+ },
+ ];
+
+ const cont = document.getElementById('ch4-bosses-container');
+ const STATE_KEY = 'physics10_ch4_bosses';
+ const BOSS_STATE = (function(){
+ try{ const s = localStorage.getItem(STATE_KEY); if(s){ const p = JSON.parse(s); if(Array.isArray(p) && p.length === BOSSES.length) return p; } }catch(e){}
+ return BOSSES.map(()=>({defeated:false}));
+ })();
+ function saveBosses(){ try{ localStorage.setItem(STATE_KEY, JSON.stringify(BOSS_STATE)); }catch(e){} }
+
+ cont.innerHTML = BOSSES.map((b)=>{
+ return ''
+ +'
'
+ +'
'
+ +'
Босс '+b.n+': '+b.title+'
'
+ +'
'+b.tag+'
'
+ +'
'
+ +'
'+b.q+'
'
+ +'
'
+ +'ответ = '
+ +' '
+ +'Атаковать '
+ +'Подсказка '
+ +'
'
+ +'
'
+ +'
';
+ }).join('');
+ renderMath(cont);
+
+ function refreshOverall(){
+ const won = BOSS_STATE.filter(s => s.defeated).length;
+ const txt = document.getElementById('ch4-boss-overall');
+ const fill = document.getElementById('ch4-boss-overall-fill');
+ if(txt) txt.textContent = won + ' / ' + BOSSES.length + ' боссов побеждено';
+ if(fill) fill.style.width = (won * 100 / BOSSES.length) + '%';
+ if(won >= BOSSES.length){
+ const reward = document.getElementById('ch4-final-reward');
+ if(reward && reward.style.display === 'none'){
+ reward.style.display = 'block';
+ if(!STATE.achievements.has('ch4_done')){
+ achievement('ch4_done','Мастер тока');
+ addXp(50, 'ch4-bonus');
+ bumpProgress('final4', 30);
+ if(window.confetti){ try{ confetti(); }catch(e){} }
+ }
+ }
+ }
+ }
+
+ BOSSES.forEach((b, idx)=>{
+ const card = document.getElementById('boss4-'+b.n+'-card');
+ const goBtn = document.getElementById('boss4-'+b.n+'-go');
+ const hintBtn = document.getElementById('boss4-'+b.n+'-hint');
+ const ansInp = document.getElementById('boss4-'+b.n+'-ans');
+ if(BOSS_STATE[idx].defeated){
+ card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))';
+ card.classList.add('glow');
+ goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.textContent = '✓ Повержен';
+ ansInp.disabled = true;
+ }
+ goBtn.addEventListener('click', ()=>{
+ if(BOSS_STATE[idx].defeated) return;
+ const fb = document.getElementById('boss4-'+b.n+'-fb');
+ const raw = ansInp.value.replace(',', '.');
+ const val = parseFloat(raw);
+ if(isNaN(val)){ feedback(fb, false, '✗ Введи число.'); return; }
+ const tol = (typeof b.tol === 'number') ? b.tol : Math.max(0.05 * Math.abs(b.ans), 0.05);
+ if(Math.abs(val - b.ans) < tol + 0.001){
+ BOSS_STATE[idx].defeated = true; saveBosses();
+ feedback(fb, true, '✓ Босс '+b.n+' повержен! +10 XP. '+b.hint);
+ addXp(10, 'boss-ch4-'+b.n);
+ bumpProgress('final4', 18);
+ goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.textContent = '✓ Повержен';
+ ansInp.disabled = true;
+ card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))';
+ card.classList.add('glow','pulse');
+ setTimeout(()=>card.classList.remove('pulse'), 900);
+ refreshOverall();
+ } else {
+ feedback(fb, false, '✗ Промах. Попробуй ещё. Подсказка доступна.');
+ }
+ });
+ hintBtn.addEventListener('click', ()=>{
+ const fb = document.getElementById('boss4-'+b.n+'-fb');
+ fb.className = 'feedback ok';
+ fb.innerHTML = 'Подсказка: '+b.hint;
+ fb.style.display = 'block';
+ fb.style.background = 'var(--warn-bg)';
+ fb.style.color = '#92400e';
+ fb.style.borderLeftColor = 'var(--warn)';
+ renderMath(fb);
+ });
+ ansInp.addEventListener('keydown', e=>{ if(e.key === 'Enter') goBtn.click(); });
+ });
+
+ refreshOverall();
}
/* ===== Search ===== */