feat(phys10 ch2 wave2): §13 «Количество теплоты» + §14 «Первый закон ТД»

Наполнены параграфы §13 и §14 (build_p13, build_p14) — теория, формулы,
4 интерактива каждый.

§13:
- 3 теоретические карточки (Q=cmΔT, фазовые переходы, баланс)
- ИНТ1: универсальный калькулятор Q (4 режима: нагрев/плавл/исп/сгор)
- ИНТ2: SVG-график нагревания льда → воды → пара (4 сегмента)
- ИНТ3: DnD-сортер 6 явлений → 4 типа процессов
- ИНТ4: тренажёр 6 задач

§14:
- 3 теоретические карточки (формулировка, изопроцессы, адиабата)
- ИНТ1: визуализатор первого закона с бар-чартом Q, ΔU, A для 4 процессов
- ИНТ2: калькулятор Q = ΔU + A (3 режима поиска)
- ИНТ3: квикфайр 'что неизменно' (T/V/p/Q)
- ИНТ4: тренажёр 5 задач

Файл: 1537 → 2325 строк. KaTeX-делимитеры, renderMath, secNav, wireReadBtn.
This commit is contained in:
Maxim Dolgolyov
2026-05-29 17:06:13 +03:00
parent e1a694ed90
commit f2398dd078
+800 -12
View File
@@ -1334,34 +1334,822 @@ function build_p12(){
function build_p13(){
const box = document.getElementById('p13-body');
let html = '';
html += makeCard('theory', "Количество теплоты", "§13", `
<p><b>Количество теплоты</b> — этот параграф в разработке (Phase 1+).</p>
<p>Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.</p>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem">
<b>Phase 0:</b> создан скелет учебника. <b>Phase 2+:</b> наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
</p>
/* THEORY 1 — Количество теплоты и удельная теплоёмкость */
html += makeCard('theory', "Количество теплоты и удельная теплоёмкость", "§13", `
<p><b>Количество теплоты</b> $Q$ — энергия, передаваемая телу при теплообмене (без совершения работы). Единица — джоуль (Дж).</p>
<p style="margin-top:8px">Для <b>нагревания или охлаждения</b> (без фазового перехода):</p>
<p style="text-align:center;margin:10px 0">$$Q = c\\,m\\,\\Delta T$$</p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>$c$ — <b>удельная теплоёмкость</b>, Дж/(кг·К);</li>
<li>$m$ — масса тела, кг;</li>
<li>$\\Delta T = T_{кон} - T_{нач}$ — разность температур (К или °C, числовое значение совпадает).</li>
</ul>
<p><b>Удельная теплоёмкость</b> — это $Q$, нужное, чтобы нагреть 1 кг вещества на 1 К. Характеристика вещества:</p>
<table style="width:100%;border-collapse:collapse;margin:10px 0;font-size:.92rem">
<thead><tr style="background:var(--sec-acc-soft)"><th style="padding:8px;border:1px solid var(--border);text-align:left">Вещество</th><th style="padding:8px;border:1px solid var(--border)">$c$, Дж/(кг·К)</th></tr></thead>
<tbody>
<tr><td style="padding:8px;border:1px solid var(--border)"><b style="color:#2563eb">Вода</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center">4200</td></tr>
<tr><td style="padding:8px;border:1px solid var(--border)">Воздух</td><td style="padding:8px;border:1px solid var(--border);text-align:center">1000</td></tr>
<tr><td style="padding:8px;border:1px solid var(--border)">Алюминий</td><td style="padding:8px;border:1px solid var(--border);text-align:center">920</td></tr>
<tr><td style="padding:8px;border:1px solid var(--border)">Железо</td><td style="padding:8px;border:1px solid var(--border);text-align:center">460</td></tr>
<tr><td style="padding:8px;border:1px solid var(--border)">Медь</td><td style="padding:8px;border:1px solid var(--border);text-align:center">390</td></tr>
</tbody>
</table>
<p style="padding:10px 14px;background:var(--warn-bg,#fef3c7);border-left:4px solid var(--warn,#f59e0b);border-radius:9px"><b>Вода имеет аномально большую $c$:</b> поэтому моря медленно нагреваются и медленно остывают — именно так формируется морской климат.</p>
`);
/* THEORY 2 — Фазовые переходы */
html += makeCard('rule', "Фазовые переходы: плавление и парообразование", "§13", `
<p><b>Плавление и кристаллизация</b> (температура не меняется):</p>
<p style="text-align:center;margin:10px 0">$$Q = \\lambda\\,m$$</p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>$\\lambda$ — <b>удельная теплота плавления</b>, Дж/кг;</li>
<li>лёд: $\\lambda = 3{,}3 \\cdot 10^5$ Дж/кг ($= 330$ кДж/кг);</li>
<li>при плавлении $Q > 0$ (поглощается), при кристаллизации $Q < 0$ (выделяется).</li>
</ul>
<p><b>Парообразование и конденсация</b>:</p>
<p style="text-align:center;margin:10px 0">$$Q = r\\,m$$</p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>$r$ — <b>удельная теплота парообразования</b>, Дж/кг;</li>
<li>вода: $r = 2{,}26 \\cdot 10^6$ Дж/кг ($= 2260$ кДж/кг).</li>
</ul>
<p style="padding:10px 14px;background:var(--warn-bg,#fef3c7);border-left:4px solid var(--warn,#f59e0b);border-radius:9px"><b>Важно:</b> $r > \\lambda$ — испарение требует значительно больше энергии, чем плавление. Поэтому ожог паром гораздо опаснее ожога кипятком.</p>
`);
/* THEORY 3 — Сгорание топлива и тепловой баланс */
html += makeCard('example', "Сгорание топлива. Уравнение теплового баланса", "§13", `
<p><b>Сгорание топлива</b>:</p>
<p style="text-align:center;margin:10px 0">$$Q = q\\,m$$</p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>$q$ — <b>удельная теплота сгорания</b>, Дж/кг;</li>
<li>бензин: $q = 4{,}4 \\cdot 10^7$ Дж/кг;</li>
<li>уголь: $q \\approx 2{,}9 \\cdot 10^7$ Дж/кг;</li>
<li>дрова сухие: $q \\approx 1{,}3 \\cdot 10^7$ Дж/кг.</li>
</ul>
<p><b>Уравнение теплового баланса</b> для изолированной системы (нет теплообмена с окружением):</p>
<p style="text-align:center;margin:10px 0">$$\\sum Q_i = 0$$</p>
<p>Теплота, отданная горячими телами, равна теплоте, полученной холодными:</p>
<p style="text-align:center;margin:10px 0">$$Q_{отд} = Q_{пол}$$</p>
<p><b>Пример.</b> В калориметр наливают холодную воду и опускают горячий кусок металла. Установится общая температура $T$, при которой</p>
<p style="text-align:center;margin:10px 0">$$c_1 m_1 (T - T_1) = c_2 m_2 (T_2 - T)$$</p>
<p>отсюда:</p>
<p style="text-align:center;margin:10px 0">$$T = \\dfrac{c_1 m_1 T_1 + c_2 m_2 T_2}{c_1 m_1 + c_2 m_2}$$</p>
`);
/* INTERACTIVE 1 — Универсальный калькулятор Q */
html += `<div class="wg" id="p13-iv1">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Калькулятор количества теплоты $Q$</div></div>
<div class="wg-help">Выбери тип процесса — введи параметры — получи формулу и значение в Дж и кДж.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-bottom:10px" id="p13-iv1-tabs">
<button class="btn primary" data-mode="heat">Нагревание $Q = cm\\Delta T$</button>
<button class="btn" data-mode="melt">Плавление $Q = \\lambda m$</button>
<button class="btn" data-mode="evap">Испарение $Q = rm$</button>
<button class="btn" data-mode="burn">Сгорание $Q = qm$</button>
</div>
<div id="p13-iv1-inputs" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;margin-bottom:10px"></div>
<div class="actions" style="justify-content:center"><button class="btn primary" id="p13-iv1-go">Вычислить $Q$</button></div>
<div id="p13-iv1-out" style="margin-top:10px;padding:12px 14px;background:var(--card);border-radius:9px;font-size:.94rem;min-height:60px;line-height:1.85"></div>
<div class="feedback" id="p13-iv1-fb"></div>
</div>`;
/* INTERACTIVE 2 — График нагревания и плавления льда */
html += `<div class="wg" id="p13-iv2">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">График нагревания льда → воды → пара</div></div>
<div class="wg-help">Меняй массу — четыре сегмента ломаной: нагрев льда, плавление, нагрев воды, испарение.</div>
<div class="sliders">
<label>Масса $m$: <b id="p13-iv2-mL">1.0</b> кг <input type="range" id="p13-iv2-m" min="0.5" max="2" value="1.0" step="0.1"></label>
</div>
<div style="display:flex;gap:12px;flex-wrap:wrap;justify-content:center;margin-bottom:8px;font-size:.84rem">
<span style="display:inline-flex;align-items:center;gap:6px"><span style="width:18px;height:3px;background:#0ea5e9;border-radius:2px"></span> Лёд</span>
<span style="display:inline-flex;align-items:center;gap:6px"><span style="width:18px;height:0;border-top:3px dashed #2563eb"></span> Плавление</span>
<span style="display:inline-flex;align-items:center;gap:6px"><span style="width:18px;height:3px;background:#ea580c;border-radius:2px"></span> Вода</span>
<span style="display:inline-flex;align-items:center;gap:6px"><span style="width:18px;height:0;border-top:3px dashed #dc2626"></span> Испарение</span>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:8px">
<svg id="p13-iv2-svg" viewBox="0 0 420 280" width="100%" style="height:auto"></svg>
</div>
<div id="p13-iv2-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem;line-height:1.75"></div>
</div>`;
/* INTERACTIVE 3 — DnD сортер */
html += `<div class="wg" id="p13-iv3">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Какой это тепловой процесс?</div></div>
<div class="wg-help">6 явлений — 4 типа процессов.</div>
<div class="dnd-hint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11V6a3 3 0 0 1 6 0v5"/><path d="M9 11h6v8a4 4 0 0 1-8 0z"/></svg> 6 ситуаций — 4 ящика</div>
<div id="p13-iv3-pool"></div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px;margin-top:8px">
<div class="drop-box"><h5 data-cat="heat">Нагревание/охлаждение</h5><div class="drop-items" data-cat="heat"></div></div>
<div class="drop-box"><h5 data-cat="melt">Плавление/кристаллизация</h5><div class="drop-items" data-cat="melt"></div></div>
<div class="drop-box"><h5 data-cat="evap">Парообразование/конденсация</h5><div class="drop-items" data-cat="evap"></div></div>
<div class="drop-box"><h5 data-cat="burn">Сгорание топлива</h5><div class="drop-items" data-cat="burn"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p13-iv3-check">Проверить</button><button class="btn" id="p13-iv3-reset">Сначала</button></div>
<div class="feedback" id="p13-iv3-fb"></div>
</div>`;
/* INTERACTIVE 4 — Тренажёр теплоты */
html += `<div class="wg" id="p13-iv4">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр теплоты</div></div>
<div class="wg-help">6 задач. $c_{воды} = 4200$, $\\lambda_{льда} = 3{,}3 \\cdot 10^5$, $r_{воды} = 2{,}26 \\cdot 10^6$, $q_{бенз} = 4{,}4 \\cdot 10^7$ (СИ). Допуск $\\pm 5\\%$.</div>
<div class="score-display"><span>Задача <b id="p13-iv4-i">1</b> / 6</span><span>Очки: <b id="p13-iv4-s">0</b> / 6</span></div>
<div id="p13-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">
<span style="font-family:'JetBrains Mono',monospace">ответ =</span>
<input type="number" id="p13-iv4-ans" class="tinp" style="width:140px;text-align:center" step="any">
<button class="btn primary" id="p13-iv4-go">Проверить</button>
<button class="btn" id="p13-iv4-start">Заново</button>
</div>
<div class="feedback" id="p13-iv4-fb"></div>
</div>`;
html += secNav('p12', 'p14');
html += readButton('p13');
box.innerHTML = html;
renderMath(box);
/* IV1 — Универсальный калькулятор Q */
(function(){
const tabs = document.getElementById('p13-iv1-tabs');
const inpsBox = document.getElementById('p13-iv1-inputs');
const out = document.getElementById('p13-iv1-out');
const fb = document.getElementById('p13-iv1-fb');
const used = new Set(); let _done = false;
let mode = 'heat';
const C_MAP = { water:4200, air:1000, alum:920, iron:460, copper:390 };
const C_LBL = { water:'Вода', air:'Воздух', alum:'Алюминий', iron:'Железо', copper:'Медь' };
const L_MAP = { ice:330000, lead:25000, iron:270000 };
const L_LBL = { ice:'Лёд (330 кДж/кг)', lead:'Свинец (25 кДж/кг)', iron:'Железо (270 кДж/кг)' };
const R_MAP = { water:2260000, eth:360000, alc:850000 };
const R_LBL = { water:'Вода (2260 кДж/кг)', eth:'Эфир (360 кДж/кг)', alc:'Спирт (850 кДж/кг)' };
const Q_MAP = { gas:4.4e7, coal:2.9e7, wood:1.3e7 };
const Q_LBL = { gas:'Бензин (44 МДж/кг)', coal:'Уголь (29 МДж/кг)', wood:'Дрова (13 МДж/кг)' };
function selectHTML(id, map, lblMap){
let h = '<select id="'+id+'" class="tinp" style="width:100%;margin-top:6px;padding:6px 8px">';
Object.keys(map).forEach(k => { h += '<option value="'+k+'">'+lblMap[k]+'</option>'; });
h += '</select>';
return h;
}
function field(id, label, val){
return '<label style="display:block;font-size:.9rem;color:var(--muted);background:var(--card);padding:8px 12px;border-radius:8px;border:1px solid var(--border)">'+label+' <input type="number" id="'+id+'" class="tinp" style="width:100%;margin-top:6px" value="'+val+'" step="any"></label>';
}
function pickField(id, label, mapHtml){
return '<label style="display:block;font-size:.9rem;color:var(--muted);background:var(--card);padding:8px 12px;border-radius:8px;border:1px solid var(--border)">'+label+mapHtml+'</label>';
}
function build(){
let h = '';
if(mode === 'heat'){
h += pickField('p13-iv1-sub','Вещество',selectHTML('p13-iv1-c', C_MAP, C_LBL));
h += field('p13-iv1-m','$m$, кг','1');
h += field('p13-iv1-dt','$\\Delta T$, К','50');
} else if(mode === 'melt'){
h += pickField('p13-iv1-sub','Вещество',selectHTML('p13-iv1-lam', L_MAP, L_LBL));
h += field('p13-iv1-m','$m$, кг','1');
} else if(mode === 'evap'){
h += pickField('p13-iv1-sub','Вещество',selectHTML('p13-iv1-r', R_MAP, R_LBL));
h += field('p13-iv1-m','$m$, кг','1');
} else {
h += pickField('p13-iv1-sub','Топливо',selectHTML('p13-iv1-q', Q_MAP, Q_LBL));
h += field('p13-iv1-m','$m$, кг','1');
}
inpsBox.innerHTML = h;
renderMath(inpsBox);
out.innerHTML = '';
fb.style.display = 'none';
}
function num(id){ const el = document.getElementById(id); return el ? parseFloat((el.value||'').replace(',','.')) : NaN; }
function fmtJ(v){ const k = v/1000, M = v/1e6; if(Math.abs(v) >= 1e6) return v.toExponential(2)+' Дж ($\\approx '+M.toFixed(2)+'$ МДж)'; if(Math.abs(v) >= 1000) return v.toFixed(0)+' Дж ($= '+k.toFixed(1)+'$ кДж)'; return v.toFixed(1)+' Дж'; }
function calc(){
let Q = 0, res = '';
const m = num('p13-iv1-m');
if(!isFinite(m) || m <= 0){ feedback(fb,false,'&#10007; Масса должна быть положительной.'); return; }
if(mode === 'heat'){
const sel = document.getElementById('p13-iv1-c').value;
const c = C_MAP[sel];
const dT = num('p13-iv1-dt');
if(!isFinite(dT)){ feedback(fb,false,'&#10007; Введи $\\Delta T$.'); return; }
Q = c * m * dT;
res = '$Q = c\\,m\\,\\Delta T = '+c+' \\cdot '+m+' \\cdot '+dT+' = '+Q.toFixed(0)+'$ Дж';
} else if(mode === 'melt'){
const sel = document.getElementById('p13-iv1-lam').value;
const lam = L_MAP[sel];
Q = lam * m;
res = '$Q = \\lambda\\,m = '+lam.toExponential(2)+' \\cdot '+m+' = '+Q.toFixed(0)+'$ Дж';
} else if(mode === 'evap'){
const sel = document.getElementById('p13-iv1-r').value;
const r = R_MAP[sel];
Q = r * m;
res = '$Q = r\\,m = '+r.toExponential(2)+' \\cdot '+m+' = '+Q.toFixed(0)+'$ Дж';
} else {
const sel = document.getElementById('p13-iv1-q').value;
const q = Q_MAP[sel];
Q = q * m;
res = '$Q = q\\,m = '+q.toExponential(2)+' \\cdot '+m+' = '+Q.toFixed(0)+'$ Дж';
}
out.innerHTML = '<div style="margin-bottom:8px">'+res+'</div>'
+ '<div><b>Ответ:</b> <span style="font-weight:700;color:var(--pri2)">'+fmtJ(Q)+'</span></div>';
renderMath(out);
feedback(fb, true, '&#10003; Вычислено.');
used.add(mode);
if(!_done && used.size === 4){ _done = true; addXp(10,'p13-iv1'); bumpProgress('p13', 15); }
}
tabs.querySelectorAll('button').forEach(b => {
b.addEventListener('click', () => {
mode = b.dataset.mode;
tabs.querySelectorAll('button').forEach(x => { x.className = 'btn'; });
b.className = 'btn primary';
build();
});
});
document.getElementById('p13-iv1-go').addEventListener('click', calc);
build();
})();
/* IV2 — График нагревания льда */
(function(){
const svg = document.getElementById('p13-iv2-svg');
const mIn = document.getElementById('p13-iv2-m');
const mL = document.getElementById('p13-iv2-mL');
const info = document.getElementById('p13-iv2-info');
const seen = new Set(); let _done = false;
const C_ICE = 2100, C_WATER = 4200, LAMBDA = 330000, R_VAP = 2260000;
function render(){
const m = +mIn.value;
mL.textContent = m.toFixed(1);
// Q-сегменты в Дж
const Q1 = C_ICE * m * 20; // -20 → 0
const Q2 = LAMBDA * m; // плавление
const Q3 = C_WATER * m * 100; // 0 → 100
const Q4 = R_VAP * m; // испарение
// в кДж для оси X
const q1 = Q1/1000, q2 = Q2/1000, q3 = Q3/1000, q4 = Q4/1000;
const Qtotal_kJ = q1 + q2 + q3 + q4;
// оси: X 0..6000 кДж × Y -20..120 °C
const W=420, H=280, pad=44;
// расширяем X-предел чтобы Q4 поместилось
const xMax = Math.ceil((Qtotal_kJ + 200) / 500) * 500;
// axes2D рисует целые тики; используем напрямую координатную сетку
// Зайдём в систему: вычислим toX/toY вручную
const xmin = 0, xmax = xMax, ymin = -20, ymax = 120;
const ux = (W - 2*pad) / (xmax - xmin);
const uy = (H - 2*pad) / (ymax - ymin);
const toX = v => pad + (v - xmin) * ux;
const toY = v => H - pad - (v - ymin) * uy;
let g = '';
g += '<rect x="'+pad+'" y="'+pad+'" width="'+(W-2*pad)+'" height="'+(H-2*pad)+'" fill="none" stroke="#e5e7eb"/>';
// сетка X
g += '<g stroke="#e5e7eb" stroke-width="1">';
const xStep = xMax / 10;
for(let xv = 0; xv <= xMax; xv += xStep){
g += '<line x1="'+toX(xv)+'" y1="'+pad+'" x2="'+toX(xv)+'" y2="'+(H-pad)+'"/>';
}
for(let yv = -20; yv <= 120; yv += 20){
g += '<line x1="'+pad+'" y1="'+toY(yv)+'" x2="'+(W-pad)+'" y2="'+toY(yv)+'"/>';
}
g += '</g>';
// оси (Y=0 линия)
g += '<line x1="'+pad+'" y1="'+toY(0)+'" x2="'+(W-pad)+'" y2="'+toY(0)+'" stroke="#0f172a" stroke-width="1.5"/>';
g += '<line x1="'+pad+'" y1="'+pad+'" x2="'+pad+'" y2="'+(H-pad)+'" stroke="#0f172a" stroke-width="1.5"/>';
// подписи осей
g += '<text x="'+(W-pad+2)+'" y="'+(H-pad+14)+'" font-size="10" fill="#0f172a">Q, кДж</text>';
g += '<text x="'+(pad-26)+'" y="'+(pad-6)+'" font-size="10" fill="#0f172a">T, °C</text>';
// тики X
g += '<g font-size="9" fill="#64748b">';
for(let xv = 0; xv <= xMax; xv += xStep){
g += '<text x="'+(toX(xv)-8)+'" y="'+(H-pad+11)+'">'+Math.round(xv)+'</text>';
}
for(let yv = -20; yv <= 120; yv += 20){
g += '<text x="'+(pad-26)+'" y="'+(toY(yv)+3)+'">'+yv+'</text>';
}
g += '</g>';
// Сегменты ломаной
let xCur = 0;
// 1) лёд -20 → 0 (голубой)
g += '<line x1="'+toX(xCur)+'" y1="'+toY(-20)+'" x2="'+toX(xCur+q1)+'" y2="'+toY(0)+'" stroke="#0ea5e9" stroke-width="3" stroke-linecap="round"/>';
xCur += q1;
// 2) плавление 0 → 0 (синий пунктир)
g += '<line x1="'+toX(xCur)+'" y1="'+toY(0)+'" x2="'+toX(xCur+q2)+'" y2="'+toY(0)+'" stroke="#2563eb" stroke-width="3" stroke-dasharray="6 4" stroke-linecap="round"/>';
xCur += q2;
// 3) вода 0 → 100 (оранжевый)
g += '<line x1="'+toX(xCur)+'" y1="'+toY(0)+'" x2="'+toX(xCur+q3)+'" y2="'+toY(100)+'" stroke="#ea580c" stroke-width="3" stroke-linecap="round"/>';
xCur += q3;
// 4) испарение 100 → 100 (красный пунктир)
g += '<line x1="'+toX(xCur)+'" y1="'+toY(100)+'" x2="'+toX(xCur+q4)+'" y2="'+toY(100)+'" stroke="#dc2626" stroke-width="3" stroke-dasharray="6 4" stroke-linecap="round"/>';
xCur += q4;
// точки переходов
let xMark = 0;
const marks = [
{x:xMark, y:-20, color:'#0ea5e9'},
{x:(xMark+=q1), y:0, color:'#2563eb'},
{x:(xMark+=q2), y:0, color:'#ea580c'},
{x:(xMark+=q3), y:100, color:'#dc2626'},
{x:(xMark+=q4), y:100, color:'#7c2d12'},
];
marks.forEach(p => { g += '<circle cx="'+toX(p.x)+'" cy="'+toY(p.y)+'" r="3.5" fill="'+p.color+'"/>'; });
svg.innerHTML = g;
const totalMJ = Qtotal_kJ/1000;
info.innerHTML = '<div style="margin-bottom:6px"><b>Масса:</b> $m = '+m.toFixed(1)+'$ кг.</div>'
+ '<div style="margin-bottom:4px">$Q_1 = c_{льда}\\,m\\,\\Delta T = 2100 \\cdot '+m.toFixed(1)+' \\cdot 20 = '+Q1.toFixed(0)+'$ Дж $\\approx '+q1.toFixed(0)+'$ кДж</div>'
+ '<div style="margin-bottom:4px">$Q_2 = \\lambda\\,m = '+LAMBDA+' \\cdot '+m.toFixed(1)+' = '+Q2.toFixed(0)+'$ Дж $\\approx '+q2.toFixed(0)+'$ кДж</div>'
+ '<div style="margin-bottom:4px">$Q_3 = c_{воды}\\,m \\cdot 100 = 4200 \\cdot '+m.toFixed(1)+' \\cdot 100 = '+Q3.toFixed(0)+'$ Дж $\\approx '+q3.toFixed(0)+'$ кДж</div>'
+ '<div style="margin-bottom:6px">$Q_4 = r\\,m = '+R_VAP+' \\cdot '+m.toFixed(1)+' = '+Q4.toFixed(0)+'$ Дж $\\approx '+q4.toFixed(0)+'$ кДж</div>'
+ '<div><b>Итого:</b> $Q_{общ} = Q_1+Q_2+Q_3+Q_4 \\approx '+totalMJ.toFixed(2)+'$ МДж</div>';
renderMath(info);
seen.add(Math.round(m*10));
if(!_done && seen.size >= 4){ _done = true; addXp(10,'p13-iv2'); bumpProgress('p13', 15); }
}
mIn.addEventListener('input', render);
render();
})();
/* IV3 — DnD сортер: тип процесса */
(function(){
const items = [
{ id:'b1', cat:'heat', html:'Нагрев кастрюли с водой на плите' },
{ id:'b2', cat:'melt', html:'Тает лёд в стакане чая' },
{ id:'b3', cat:'evap', html:'Кипит чайник на огне' },
{ id:'b4', cat:'burn', html:'Сжигание бензина в двигателе' },
{ id:'b5', cat:'heat', html:'Чашка кофе постепенно остывает' },
{ id:'b6', cat:'melt', html:'Замерзает вода в формочке' },
];
const sorter = setupSorter({
poolId:'p13-iv3-pool',
scopeSelector:'#p13-iv3',
items: items,
cats:['heat','melt','evap','burn'],
columnLayout:false,
});
document.getElementById('p13-iv3-check').addEventListener('click', () => {
const fb = document.getElementById('p13-iv3-fb');
const placedCount = items.filter(it => sorter.placed[it.id]).length;
const correct = items.filter(it => sorter.placed[it.id] === it.cat).length;
if(placedCount < items.length){ feedback(fb, false, '&#10007; Размести все 6 явлений.'); return; }
if(correct === items.length){ feedback(fb, true, '&#10003; Все 6 верно! +10 XP'); addXp(10,'p13-iv3'); bumpProgress('p13', 15); }
else feedback(fb, false, '&#10007; Правильно ' + correct + ' из 6. Попробуй ещё.');
});
document.getElementById('p13-iv3-reset').addEventListener('click', () => { sorter.reset(); document.getElementById('p13-iv3-fb').style.display = 'none'; });
})();
/* IV4 — Тренажёр теплоты */
(function(){
const Q = [
{ q:'Нагреть 2 кг воды от 20°C до 80°C. $Q$ в кДж?', ans:504, tol:10, hint:'$Q = c m \\Delta T = 4200 \\cdot 2 \\cdot 60 = 504000$ Дж = 504 кДж' },
{ q:'Растопить 0{,}5 кг льда при 0°C. $Q$ в кДж?', ans:165, tol:5, hint:'$Q = \\lambda m = 330000 \\cdot 0{,}5 = 165$ кДж' },
{ q:'Испарить 1 кг воды при 100°C. $Q$ в кДж?', ans:2260, tol:50, hint:'$Q = r m = 2{,}26 \\cdot 10^6 \\cdot 1 = 2260$ кДж' },
{ q:'Сжечь 0{,}5 кг бензина ($q = 4{,}4 \\cdot 10^7$ Дж/кг). $Q$ в МДж?', ans:22, tol:1, hint:'$Q = q m = 4{,}4 \\cdot 10^7 \\cdot 0{,}5 = 2{,}2 \\cdot 10^7$ Дж = 22 МДж' },
{ q:'В калориметр налили 100 г воды при 20°C и опустили 200 г меди при 100°C ($c_{Cu} = 390$). Конечная $T$ в °C?', ans:33, tol:1.5, hint:'$4200 \\cdot 0{,}1 \\cdot (T-20) = 390 \\cdot 0{,}2 \\cdot (100-T)$ → $T \\approx 32{,}5$°C' },
{ q:'Нагреть 1 кг алюминия ($c = 920$) от 20°C до 100°C. $Q$ в кДж?', ans:73.6, tol:2, hint:'$Q = 920 \\cdot 1 \\cdot 80 = 73600$ Дж = 73{,}6 кДж' },
];
let i = 0, score = 0;
function show(){
if(i >= Q.length){
document.getElementById('p13-iv4-q').innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
if(score === Q.length){ addXp(15, 'p13-iv4'); bumpProgress('p13', 25); }
else if(score >= 4){ addXp(8, 'p13-iv4'); bumpProgress('p13', 15); }
return;
}
document.getElementById('p13-iv4-i').textContent = (i+1);
document.getElementById('p13-iv4-s').textContent = score;
document.getElementById('p13-iv4-q').innerHTML = Q[i].q;
document.getElementById('p13-iv4-ans').value = '';
renderMath(document.getElementById('p13-iv4-q'));
document.getElementById('p13-iv4-fb').style.display = 'none';
}
function go(){
if(i >= Q.length) return;
const fb = document.getElementById('p13-iv4-fb');
const raw = document.getElementById('p13-iv4-ans').value.replace(',', '.');
const ans = parseFloat(raw);
if(isNaN(ans)){ feedback(fb, false, '&#10007; Введи число.'); return; }
if(Math.abs(ans - Q[i].ans) <= Q[i].tol + 0.001){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].hint+'. Дальше ▶'); }
else feedback(fb, false, '&#10007; Неверно. Ответ: $'+Q[i].ans+'$. '+Q[i].hint+'. Дальше ▶');
document.getElementById('p13-iv4-s').textContent = score;
i++;
setTimeout(show, 1800);
}
document.getElementById('p13-iv4-go').addEventListener('click', go);
document.getElementById('p13-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); });
document.getElementById('p13-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); });
show();
})();
wireReadBtn('p13');
}
function build_p14(){
const box = document.getElementById('p14-body');
let html = '';
html += makeCard('theory', "Первый закон термодинамики", "§14", `
<p><b>Первый закон термодинамики</b> — этот параграф в разработке (Phase 1+).</p>
<p>Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.</p>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem">
<b>Phase 0:</b> создан скелет учебника. <b>Phase 2+:</b> наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
</p>
/* THEORY 1 — Формулировка первого закона ТД */
html += makeCard('theory', "Формулировка первого закона термодинамики", "§14", `
<p><b>Первый закон термодинамики</b> — закон сохранения энергии для термодинамической системы:</p>
<p style="text-align:center;margin:10px 0">$$\\Delta U = Q + A_{внеш}$$</p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>$\\Delta U$ — изменение внутренней энергии системы;</li>
<li>$Q$ — количество теплоты, переданное системе ($Q > 0$, если получено);</li>
<li>$A_{внеш}$ — работа внешних сил над системой.</li>
</ul>
<p>Через работу газа (учитывая $A_{внеш} = -A_{газ}$):</p>
<p style="text-align:center;margin:10px 0">$$Q = \\Delta U + A_{газ}$$</p>
<p style="padding:10px 14px;background:var(--warn-bg,#fef3c7);border-left:4px solid var(--warn,#f59e0b);border-radius:9px"><b>Словами:</b> теплота, полученная газом, расходуется на изменение его внутренней энергии и на совершение работы газом.</p>
<p>Правила знаков:</p>
<table style="width:100%;border-collapse:collapse;margin:10px 0;font-size:.92rem">
<thead><tr style="background:var(--sec-acc-soft)"><th style="padding:8px;border:1px solid var(--border);text-align:left">Величина</th><th style="padding:8px;border:1px solid var(--border)">$> 0$</th><th style="padding:8px;border:1px solid var(--border)">$< 0$</th></tr></thead>
<tbody>
<tr><td style="padding:8px;border:1px solid var(--border)"><b>$Q$</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center">газ получает</td><td style="padding:8px;border:1px solid var(--border);text-align:center">газ отдаёт</td></tr>
<tr><td style="padding:8px;border:1px solid var(--border)"><b>$A_{газ}$</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center">расширение</td><td style="padding:8px;border:1px solid var(--border);text-align:center">сжатие</td></tr>
<tr><td style="padding:8px;border:1px solid var(--border)"><b>$\\Delta U$</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center">$T$ растёт</td><td style="padding:8px;border:1px solid var(--border);text-align:center">$T$ падает</td></tr>
</tbody>
</table>
`);
/* THEORY 2 — Применение к изопроцессам */
html += makeCard('rule', "Применение к изопроцессам", "§14", `
<p>Первый закон $Q = \\Delta U + A_{газ}$ принимает простой вид для каждого изопроцесса.</p>
<p style="margin-top:8px"><b>1) Изотермический</b> ($T = \\text{const}$, для идеального газа $\\Delta U = 0$):</p>
<p style="text-align:center;margin:8px 0">$$Q = A_{газ}$$</p>
<p>Вся подведённая теплота превращается в работу газа.</p>
<p style="margin-top:8px"><b>2) Изохорный</b> ($V = \\text{const}$, $A_{газ} = 0$):</p>
<p style="text-align:center;margin:8px 0">$$Q = \\Delta U = \\dfrac{3}{2}\\,\\nu R\\,\\Delta T$$</p>
<p>Вся теплота идёт на увеличение внутренней энергии.</p>
<p style="margin-top:8px"><b>3) Изобарный</b> ($p = \\text{const}$):</p>
<p style="text-align:center;margin:8px 0">$$Q = \\Delta U + p\\,\\Delta V$$</p>
<p>Часть теплоты — на $\\Delta U$, часть — на работу.</p>
<p style="margin-top:8px"><b>4) Адиабатный</b> ($Q = 0$, нет теплообмена):</p>
<p style="text-align:center;margin:8px 0">$$\\Delta U = -A_{газ}$$</p>
<p>Работа совершается за счёт внутренней энергии: расширение → охлаждение, сжатие → нагрев.</p>
`);
/* THEORY 3 — Адиабатный процесс и примеры */
html += makeCard('example', "Адиабатный процесс и примеры", "§14", `
<p><b>Адиабатный процесс</b> — без теплообмена ($Q = 0$). Реализуется:</p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>в теплоизолированных сосудах;</li>
<li>при <b>быстрых</b> процессах — теплообмен не успевает произойти.</li>
</ul>
<p><b>Примеры:</b></p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li><b>Дизельный двигатель.</b> Быстрое сжатие воздуха разогревает его до $\\sim 700°$C — этого достаточно для самовоспламенения солярки (без свечи зажигания).</li>
<li><b>Образование облаков.</b> Тёплый влажный воздух поднимается, адиабатно расширяется, охлаждается — водяной пар конденсируется в капли.</li>
<li><b>Холодильник.</b> Рабочее тело расширяется через дроссель — охлаждается; затем сжимается компрессором — нагревается.</li>
<li><b>Велонасос.</b> При быстром сжатии воздух заметно нагревается — это адиабатный процесс.</li>
</ul>
<p style="padding:10px 14px;background:var(--warn-bg,#fef3c7);border-left:4px solid var(--warn,#f59e0b);border-radius:9px"><b>Уравнение Пуассона</b> для адиабаты: $pV^{\\gamma} = \\text{const}$, где $\\gamma = c_p/c_v$ — показатель адиабаты. Для одноатомного газа $\\gamma = 5/3$, для двухатомного $\\gamma = 7/5$.</p>
`);
/* INTERACTIVE 1 — Первый закон в действии (бар-чарт по 4 процессам) */
html += `<div class="wg" id="p14-iv1">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Первый закон в действии</div></div>
<div class="wg-help">Выбери процесс и сдвигай параметр — смотри бар-чарт $Q$, $\\Delta U$, $A_{газ}$.</div>
<div style="display:flex;gap:14px;flex-wrap:wrap;justify-content:center;margin-bottom:10px">
<label style="display:inline-flex;align-items:center;gap:6px;font-size:.92rem"><input type="radio" name="p14-iv1-proc" value="iso" checked> <span style="color:#ea580c;font-weight:700">Изотермический</span></label>
<label style="display:inline-flex;align-items:center;gap:6px;font-size:.92rem"><input type="radio" name="p14-iv1-proc" value="hor"> <span style="color:#10b981;font-weight:700">Изохорный</span></label>
<label style="display:inline-flex;align-items:center;gap:6px;font-size:.92rem"><input type="radio" name="p14-iv1-proc" value="bar"> <span style="color:#2563eb;font-weight:700">Изобарный</span></label>
<label style="display:inline-flex;align-items:center;gap:6px;font-size:.92rem"><input type="radio" name="p14-iv1-proc" value="adi"> <span style="color:#7c3aed;font-weight:700">Адиабатный</span></label>
</div>
<div class="sliders" id="p14-iv1-sliders"></div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:8px">
<svg id="p14-iv1-svg" viewBox="0 0 420 240" width="100%" style="height:auto"></svg>
</div>
<div id="p14-iv1-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem;line-height:1.85"></div>
</div>`;
/* INTERACTIVE 2 — Калькулятор первого закона */
html += `<div class="wg" id="p14-iv2">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор первого закона</div></div>
<div class="wg-help">Введи две величины — получи третью по формуле $Q = \\Delta U + A_{газ}$.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-bottom:10px" id="p14-iv2-tabs">
<button class="btn primary" data-find="dU">Найти $\\Delta U$</button>
<button class="btn" data-find="Q">Найти $Q$</button>
<button class="btn" data-find="A">Найти $A_{газ}$</button>
</div>
<div id="p14-iv2-inputs" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;margin-bottom:10px"></div>
<div class="actions" style="justify-content:center"><button class="btn primary" id="p14-iv2-go">Вычислить</button></div>
<div id="p14-iv2-out" style="margin-top:10px;padding:12px 14px;background:var(--card);border-radius:9px;font-size:.94rem;min-height:60px;line-height:1.85"></div>
<div class="feedback" id="p14-iv2-fb"></div>
</div>`;
/* INTERACTIVE 3 — Что неизменно? (квикфайр) */
html += `<div class="wg" id="p14-iv3">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Что неизменно в этом процессе?</div></div>
<div class="wg-help">6 ситуаций. Выбери постоянную величину.</div>
<div class="score-display"><span>Задание <b id="p14-iv3-i">1</b> / 6</span><span>Очки: <b id="p14-iv3-s">0</b> / 6</span></div>
<div id="p14-iv3-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap">
<button class="btn primary" data-ans="T">$T = \\text{const}$</button>
<button class="btn primary" data-ans="V">$V = \\text{const}$</button>
<button class="btn primary" data-ans="p">$p = \\text{const}$</button>
<button class="btn primary" data-ans="Q">$Q = 0$</button>
</div>
<div class="feedback" id="p14-iv3-fb"></div>
</div>`;
/* INTERACTIVE 4 — Тренажёр первого закона */
html += `<div class="wg" id="p14-iv4">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр первого закона</div></div>
<div class="wg-help">5 задач. $R = 8{,}3$ Дж/(моль·К). Допуск $\\pm 5\\%$.</div>
<div class="score-display"><span>Задача <b id="p14-iv4-i">1</b> / 5</span><span>Очки: <b id="p14-iv4-s">0</b> / 5</span></div>
<div id="p14-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">
<span style="font-family:'JetBrains Mono',monospace">ответ =</span>
<input type="number" id="p14-iv4-ans" class="tinp" style="width:140px;text-align:center" step="any">
<button class="btn primary" id="p14-iv4-go">Проверить</button>
<button class="btn" id="p14-iv4-start">Заново</button>
</div>
<div class="feedback" id="p14-iv4-fb"></div>
</div>`;
html += secNav('p13', 'p15');
html += readButton('p14');
box.innerHTML = html;
renderMath(box);
/* IV1 — Первый закон в действии: бар-чарт */
(function(){
const R = 8.314;
const slBox = document.getElementById('p14-iv1-sliders');
const svg = document.getElementById('p14-iv1-svg');
const info = document.getElementById('p14-iv1-info');
const COL = { iso:'#ea580c', hor:'#10b981', bar:'#2563eb', adi:'#7c3aed' };
const seen = new Set(); let _done = false;
function getMode(){ const r = document.querySelector('input[name="p14-iv1-proc"]:checked'); return r ? r.value : 'iso'; }
function buildSliders(){
const m = getMode();
let h = '';
if(m === 'iso'){
h += '<label>$T$: <b id="p14-iv1-tL">300</b> К <input type="range" id="p14-iv1-t" min="200" max="500" value="300" step="10"></label>';
h += '<label>Отношение $V_2/V_1$: <b id="p14-iv1-rL">2.0</b> <input type="range" id="p14-iv1-r" min="0.5" max="4" value="2.0" step="0.1"></label>';
} else if(m === 'hor'){
h += '<label>$\\Delta T$: <b id="p14-iv1-dtL">+50</b> К <input type="range" id="p14-iv1-dt" min="-100" max="200" value="50" step="10"></label>';
} else if(m === 'bar'){
h += '<label>$\\Delta T$: <b id="p14-iv1-dtL">+50</b> К <input type="range" id="p14-iv1-dt" min="-100" max="200" value="50" step="10"></label>';
} else {
h += '<label>$A_{газ}$: <b id="p14-iv1-aL">+400</b> Дж <input type="range" id="p14-iv1-a" min="-800" max="800" value="400" step="20"></label>';
}
slBox.innerHTML = h;
renderMath(slBox);
slBox.querySelectorAll('input[type=range]').forEach(i => i.addEventListener('input', render));
}
function drawBars(Q, dU, A, mode){
const W=420, H=240, pad=44;
const innerW = W - 2*pad, innerH = H - 2*pad;
const maxAbs = Math.max(Math.abs(Q), Math.abs(dU), Math.abs(A), 100);
const ySc = innerH / (2 * maxAbs * 1.15);
const y0 = H/2; // ось 0
const barW = innerW / 4;
const labels = ['Q', 'ΔU', 'A_{газ}'];
const vals = [Q, dU, A];
const cols = [COL[mode], '#0ea5e9', '#f59e0b'];
let g = '';
// фон
g += '<rect x="'+pad+'" y="'+pad+'" width="'+innerW+'" height="'+innerH+'" fill="#fafbfc" stroke="#e5e7eb"/>';
// ось 0
g += '<line x1="'+pad+'" y1="'+y0+'" x2="'+(W-pad)+'" y2="'+y0+'" stroke="#0f172a" stroke-width="1.5"/>';
g += '<text x="'+(pad-30)+'" y="'+(y0+4)+'" font-size="10" fill="#0f172a">0</text>';
// подсказки уровней
for(const lv of [-maxAbs, -maxAbs/2, maxAbs/2, maxAbs]){
const y = y0 - lv * ySc;
if(y > pad && y < H - pad){
g += '<line x1="'+pad+'" y1="'+y+'" x2="'+(W-pad)+'" y2="'+y+'" stroke="#e5e7eb" stroke-dasharray="3 3"/>';
g += '<text x="'+(pad-36)+'" y="'+(y+3)+'" font-size="9" fill="#64748b">'+lv.toFixed(0)+'</text>';
}
}
// бары
vals.forEach((v, i) => {
const cx = pad + innerW * (i+0.5) / 3;
const bx = cx - barW/2;
const h = Math.abs(v) * ySc;
const by = v >= 0 ? y0 - h : y0;
g += '<rect x="'+bx+'" y="'+by+'" width="'+barW+'" height="'+h+'" fill="'+cols[i]+'" opacity="0.85" stroke="'+cols[i]+'" stroke-width="2"/>';
g += '<text x="'+cx+'" y="'+(H-pad+18)+'" font-size="12" font-weight="700" text-anchor="middle" fill="#0f172a">'+labels[i]+'</text>';
const labY = v >= 0 ? by - 6 : by + h + 14;
g += '<text x="'+cx+'" y="'+labY+'" font-size="11" font-weight="700" text-anchor="middle" fill="'+cols[i]+'">'+v.toFixed(0)+' Дж</text>';
});
svg.innerHTML = g;
}
function render(){
const m = getMode();
let Q = 0, dU = 0, A = 0, descr = '', formula = '';
const NU = 1;
if(m === 'iso'){
const T = +document.getElementById('p14-iv1-t').value;
const r = +document.getElementById('p14-iv1-r').value;
document.getElementById('p14-iv1-tL').textContent = T;
document.getElementById('p14-iv1-rL').textContent = r.toFixed(1);
dU = 0;
A = NU * R * T * Math.log(r);
Q = A;
descr = 'Изотермический процесс: $T = \\text{const}$, $\\Delta U = 0$.';
formula = '$Q = A_{газ} = \\nu RT\\ln(V_2/V_1) = '+A.toFixed(0)+'$ Дж';
} else if(m === 'hor'){
const dT = +document.getElementById('p14-iv1-dt').value;
document.getElementById('p14-iv1-dtL').textContent = (dT >= 0 ? '+' : '') + dT;
A = 0;
dU = 1.5 * NU * R * dT;
Q = dU;
descr = 'Изохорный процесс: $V = \\text{const}$, $A_{газ} = 0$.';
formula = '$Q = \\Delta U = \\tfrac{3}{2}\\nu R \\Delta T = '+dU.toFixed(0)+'$ Дж';
} else if(m === 'bar'){
const dT = +document.getElementById('p14-iv1-dt').value;
document.getElementById('p14-iv1-dtL').textContent = (dT >= 0 ? '+' : '') + dT;
dU = 1.5 * NU * R * dT;
A = NU * R * dT; // p ΔV = νR ΔT
Q = dU + A;
descr = 'Изобарный процесс: $p = \\text{const}$. Часть теплоты — на $\\Delta U$, часть — на работу.';
formula = '$Q = \\Delta U + p\\Delta V = '+dU.toFixed(0)+' + '+A.toFixed(0)+' = '+Q.toFixed(0)+'$ Дж';
} else {
const av = +document.getElementById('p14-iv1-a').value;
document.getElementById('p14-iv1-aL').textContent = (av >= 0 ? '+' : '') + av;
Q = 0;
A = av;
dU = -A;
descr = 'Адиабатный процесс: $Q = 0$, $\\Delta U = -A_{газ}$.';
formula = '$\\Delta U = -A_{газ} = '+dU.toFixed(0)+'$ Дж'+(A > 0 ? ' (расширение → охлаждение)' : (A < 0 ? ' (сжатие → нагрев)' : ''));
}
drawBars(Q, dU, A, m);
info.innerHTML = '<div style="margin-bottom:6px">'+descr+'</div>'
+ '<div style="margin-bottom:6px">'+formula+'</div>'
+ '<div><b>Проверка $Q = \\Delta U + A_{газ}$:</b> '+Q.toFixed(0)+' = '+dU.toFixed(0)+' + '+A.toFixed(0)+' ✓</div>';
renderMath(info);
seen.add(m);
if(!_done && seen.size === 4){ _done = true; addXp(10,'p14-iv1'); bumpProgress('p14', 15); }
}
document.querySelectorAll('input[name="p14-iv1-proc"]').forEach(r => r.addEventListener('change', () => { buildSliders(); render(); }));
buildSliders();
render();
})();
/* IV2 — Калькулятор первого закона */
(function(){
const tabs = document.getElementById('p14-iv2-tabs');
const inpsBox = document.getElementById('p14-iv2-inputs');
const out = document.getElementById('p14-iv2-out');
const fb = document.getElementById('p14-iv2-fb');
const used = new Set(); let _done = false;
let mode = 'dU';
function field(id, label, val){
return '<label style="display:block;font-size:.9rem;color:var(--muted);background:var(--card);padding:8px 12px;border-radius:8px;border:1px solid var(--border)">'+label+' <input type="number" id="'+id+'" class="tinp" style="width:100%;margin-top:6px" value="'+val+'" step="any"></label>';
}
function build(){
let h = '';
if(mode === 'dU'){
h += field('p14-iv2-Q','$Q$, Дж','500');
h += field('p14-iv2-A','$A_{газ}$, Дж','300');
} else if(mode === 'Q'){
h += field('p14-iv2-dU','$\\Delta U$, Дж','400');
h += field('p14-iv2-A','$A_{газ}$, Дж','300');
} else {
h += field('p14-iv2-Q','$Q$, Дж','500');
h += field('p14-iv2-dU','$\\Delta U$, Дж','200');
}
inpsBox.innerHTML = h;
renderMath(inpsBox);
out.innerHTML = '';
fb.style.display = 'none';
}
function num(id){ const el = document.getElementById(id); return el ? parseFloat((el.value||'').replace(',','.')) : NaN; }
function calc(){
let res = '', val = 0;
if(mode === 'dU'){
const Q = num('p14-iv2-Q'), A = num('p14-iv2-A');
if(![Q,A].every(isFinite)){ feedback(fb,false,'&#10007; Введи оба числа.'); return; }
val = Q - A;
res = '$\\Delta U = Q - A_{газ} = '+Q+' - ('+A+') = '+val.toFixed(0)+'$ Дж';
} else if(mode === 'Q'){
const dU = num('p14-iv2-dU'), A = num('p14-iv2-A');
if(![dU,A].every(isFinite)){ feedback(fb,false,'&#10007; Введи оба числа.'); return; }
val = dU + A;
res = '$Q = \\Delta U + A_{газ} = '+dU+' + ('+A+') = '+val.toFixed(0)+'$ Дж';
} else {
const Q = num('p14-iv2-Q'), dU = num('p14-iv2-dU');
if(![Q,dU].every(isFinite)){ feedback(fb,false,'&#10007; Введи оба числа.'); return; }
val = Q - dU;
res = '$A_{газ} = Q - \\Delta U = '+Q+' - ('+dU+') = '+val.toFixed(0)+'$ Дж';
}
const labels = { dU:'\\Delta U', Q:'Q', A:'A_{газ}' };
out.innerHTML = '<div style="margin-bottom:8px">'+res+'</div>'
+ '<div><b>Ответ:</b> <span style="font-weight:700;color:var(--pri2)">$'+labels[mode]+' = '+val.toFixed(0)+'$ Дж</span></div>';
renderMath(out);
feedback(fb, true, '&#10003; Вычислено.');
used.add(mode);
if(!_done && used.size === 3){ _done = true; addXp(10,'p14-iv2'); bumpProgress('p14', 15); }
}
tabs.querySelectorAll('button').forEach(b => {
b.addEventListener('click', () => {
mode = b.dataset.find;
tabs.querySelectorAll('button').forEach(x => { x.className = 'btn'; });
b.className = 'btn primary';
build();
});
});
document.getElementById('p14-iv2-go').addEventListener('click', calc);
build();
})();
/* IV3 — Что неизменно? */
(function(){
const Q = [
{ q:'Изотермический процесс — что постоянно?', ans:'T' },
{ q:'Изохорный процесс — что постоянно?', ans:'V' },
{ q:'Изобарный процесс — что постоянно?', ans:'p' },
{ q:'Адиабатный процесс — какая величина равна нулю?', ans:'Q' },
{ q:'Вода кипит при $T = 100°$C — какой параметр постоянен?', ans:'T' },
{ q:'Газ в герметичном баллоне греют. Что неизменно?', ans:'V' },
];
let i = 0, score = 0; let _done = false;
const box = document.getElementById('p14-iv3');
function show(){
const qEl = document.getElementById('p14-iv3-q');
const fb = document.getElementById('p14-iv3-fb');
if(i >= Q.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
renderMath(qEl);
if(!_done){
_done = true;
if(score === Q.length){ addXp(15,'p14-iv3'); bumpProgress('p14', 25); }
else if(score >= 4){ addXp(8,'p14-iv3'); bumpProgress('p14', 15); }
}
return;
}
document.getElementById('p14-iv3-i').textContent = (i+1);
document.getElementById('p14-iv3-s').textContent = score;
qEl.innerHTML = Q[i].q;
renderMath(qEl);
fb.style.display = 'none';
}
box.querySelectorAll('button[data-ans]').forEach(b => {
b.addEventListener('click', () => {
if(i >= Q.length) return;
const fb = document.getElementById('p14-iv3-fb');
const ans = b.dataset.ans;
if(ans === Q[i].ans){ score++; feedback(fb, true, '&#10003; Верно! Дальше ▶'); }
else {
const labels = {T:'$T = \\text{const}$', V:'$V = \\text{const}$', p:'$p = \\text{const}$', Q:'$Q = 0$'};
feedback(fb, false, '&#10007; Неверно. Правильно: '+labels[Q[i].ans]+'. Дальше ▶');
}
document.getElementById('p14-iv3-s').textContent = score;
i++;
setTimeout(show, 1500);
});
});
show();
})();
/* IV4 — Тренажёр первого закона */
(function(){
const Q = [
{ q:'Газ получил $Q = 500$ Дж тепла и совершил работу $A_{газ} = 300$ Дж. Найди $\\Delta U$ в Дж.', ans:200, tol:5, hint:'$\\Delta U = Q - A = 500 - 300 = 200$' },
{ q:'Изохорно нагрели 1 моль газа на $\\Delta T = 50$ К. $\\Delta U$ в Дж?', ans:622, tol:30, hint:'$\\Delta U = \\tfrac{3}{2}\\nu R\\Delta T = 1{,}5 \\cdot 1 \\cdot 8{,}3 \\cdot 50 \\approx 622$' },
{ q:'Изотермически 1 моль газа при $T = 300$ К расширили вдвое ($V_2 = 2V_1$). $Q$ в Дж?', ans:1726, tol:50, hint:'$Q = A = \\nu RT\\ln 2 = 8{,}3 \\cdot 300 \\cdot 0{,}693 \\approx 1726$' },
{ q:'В адиабатном процессе газ совершил $A_{газ} = 400$ Дж. $\\Delta U$ в Дж (со знаком)?', ans:-400, tol:5, hint:'$Q = 0 \\Rightarrow \\Delta U = -A = -400$' },
{ q:'Газ изобарно расширился, при этом $\\Delta U = 600$ Дж, $A_{газ} = 400$ Дж. $Q$ в Дж?', ans:1000, tol:20, hint:'$Q = \\Delta U + A = 600 + 400 = 1000$' },
];
let i = 0, score = 0;
function show(){
if(i >= Q.length){
document.getElementById('p14-iv4-q').innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
if(score === Q.length){ addXp(15, 'p14-iv4'); bumpProgress('p14', 25); }
else if(score >= 3){ addXp(8, 'p14-iv4'); bumpProgress('p14', 15); }
return;
}
document.getElementById('p14-iv4-i').textContent = (i+1);
document.getElementById('p14-iv4-s').textContent = score;
document.getElementById('p14-iv4-q').innerHTML = Q[i].q;
document.getElementById('p14-iv4-ans').value = '';
renderMath(document.getElementById('p14-iv4-q'));
document.getElementById('p14-iv4-fb').style.display = 'none';
}
function go(){
if(i >= Q.length) return;
const fb = document.getElementById('p14-iv4-fb');
const raw = document.getElementById('p14-iv4-ans').value.replace(',', '.');
const ans = parseFloat(raw);
if(isNaN(ans)){ feedback(fb, false, '&#10007; Введи число.'); return; }
if(Math.abs(ans - Q[i].ans) <= Q[i].tol + 0.001){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].hint+'. Дальше ▶'); }
else feedback(fb, false, '&#10007; Неверно. Ответ: $'+Q[i].ans+'$. '+Q[i].hint+'. Дальше ▶');
document.getElementById('p14-iv4-s').textContent = score;
i++;
setTimeout(show, 1800);
}
document.getElementById('p14-iv4-go').addEventListener('click', go);
document.getElementById('p14-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); });
document.getElementById('p14-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); });
show();
})();
wireReadBtn('p14');
}