feat(phys8 ch1): Phase 1 Wave 3 — §6 (Q=cmΔT) + §7 (Q=qm)

§6 — Расчёт количества теплоты:
- 3 теории: закон Q=cmΔT, удельная теплоёмкость, баланс
- IV-1: калькулятор Q=cmΔT с термометром и анимированным кубиком,
  выбор из 11 веществ (вода/лёд/металлы/стекло/...)
- IV-2: калькулятор смешивания 2 порций воды по m₁T₁+m₂T₂/(m₁+m₂)
- IV-3: DnD-ранжирование 5 веществ по возрастанию c
- IV-4: 6 числовых задач с допуском, подсказки

§7 — Горение и теплота сгорания:
- 3 теории: закон Q=qm, таблица q топлив, КПД
- IV-1: калькулятор Q=qm с анимированным пламенем (высота ∝ m),
  выбор из 8 топлив, перевод в кВт·ч и эквивалент нагрева воды
- IV-2: 6 раундов «какое топливо мощнее»
- IV-3: DnD ранжирование 5 топлив по возрастанию q
- IV-4: 5 числовых задач с подсказками

Добавлены константы MAT_C и MAT_Q — табличные данные для §6, §7.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-29 22:59:46 +03:00
parent 2ae70dd48f
commit d8141087cd
+485 -6
View File
@@ -301,8 +301,25 @@ const SIDEBARS = {
["Излучают всё","чем горячее, тем сильнее"],
["Тёмные тела","поглощают и излучают сильнее светлых"]
]},
p6:{title:"Шпаргалка § 6",rows:[["В разработке","Phase 1 Wave 3"]]},
p7:{title:"Шпаргалка § 7",rows:[["В разработке","Phase 1 Wave 3"]]},
p6:{title:"Шпаргалка § 6",rows:[
["Закон","$Q = c m \\Delta T$"],
["$c$ — уд. теплоёмкость","Дж/(кг·К)"],
["вода","$c = 4200$"],
["лёд","$c = 2100$"],
["алюминий","$c = 920$"],
["медь","$c = 380$"],
["железо","$c = 460$"],
["Баланс","$Q_{отд} = Q_{пол}$"]
]},
p7:{title:"Шпаргалка § 7",rows:[
["Закон","$Q = q m$"],
["$q$ — уд. теплота сгорания","Дж/кг"],
["дрова","$q = 10^7$"],
["уголь","$q = 3 \\cdot 10^7$"],
["бензин","$q = 4{,}6 \\cdot 10^7$"],
["природ. газ","$q = 4{,}4 \\cdot 10^7$"],
["КПД котла","$\\eta = Q_{пол}/(q m)$"]
]},
p8:{title:"Шпаргалка § 8",rows:[["В разработке","Phase 1 Wave 4"]]},
p9:{title:"Шпаргалка § 9",rows:[["В разработке","Phase 1 Wave 4"]]},
p10:{title:"Шпаргалка § 10",rows:[["В разработке","Phase 1 Wave 5"]]},
@@ -316,8 +333,8 @@ const TIPS=[
{sec:'p3',html:"Один конец металлического стержня в огне — другой нагревается, хотя ничто не движется. Это <b>теплопроводность</b>: молекулы передают энергию соседям. У металлов это работает быстро, у дерева — медленно."},
{sec:'p4',html:"Тёплый воздух легче холодного и поднимается вверх. Так батарея греет всю комнату — это <b>конвекция</b>. В твёрдых телах конвекции нет, потому что молекулы не могут свободно двигаться."},
{sec:'p5',html:"Солнце греет Землю через космический вакуум — теплопроводность и конвекция тут невозможны. Это <b>излучение</b> электромагнитными волнами. Чёрная футболка в жаркий день нагревается сильнее белой."},
{sec:'p6',html:"Параграф § 6 будет реализован в Phase 1 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p7',html:араграф § 7 будет реализован в Phase 1 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p6',html:"Чтобы нагреть тело массой $m$ на $\\Delta T$ градусов, нужно $Q = c m \\Delta T$. Здесь $c$ — это «сколько энергии съедает 1 кг этого вещества на 1 градус». У воды $c$ самое большое — поэтому вода долго греется и долго остывает."},
{sec:'p7',html:ри сгорании 1 кг топлива выделяется $q$ Дж энергии. Полное выделение: $Q = q m$. У бензина $q$ в 4,5 раза больше, чем у дров, — поэтому литр бензина греет дольше, чем литр дров."},
{sec:'p8',html:"Параграф § 8 будет реализован в Phase 1 Wave 4. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p9',html:"Параграф § 9 будет реализован в Phase 1 Wave 4. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p10',html:"Параграф § 10 будет реализован в Phase 1 Wave 5. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
@@ -331,8 +348,8 @@ const BUILDERS = {
p3: ()=>{ build_p3(); },
p4: ()=>{ build_p4(); },
p5: ()=>{ build_p5(); },
p6: ()=>{ const box=document.getElementById('p6-body'); box.innerHTML = buildStub('p6', 'Расчёт количества теплоты при нагревании и охлаждении. Удельная теплоёмкость', 'Phase 1 Wave 3') + secNavFor('p6') + readButton('p6'); renderMath(box); wireReadBtn('p6'); },
p7: ()=>{ const box=document.getElementById('p7-body'); box.innerHTML = buildStub('p7', 'Горение. Удельная теплота сгорания топлива', 'Phase 1 Wave 3') + secNavFor('p7') + readButton('p7'); renderMath(box); wireReadBtn('p7'); },
p6: ()=>{ build_p6(); },
p7: ()=>{ build_p7(); },
p8: ()=>{ const box=document.getElementById('p8-body'); box.innerHTML = buildStub('p8', 'Плавление и кристаллизация', 'Phase 1 Wave 4') + secNavFor('p8') + readButton('p8'); renderMath(box); wireReadBtn('p8'); },
p9: ()=>{ const box=document.getElementById('p9-body'); box.innerHTML = buildStub('p9', 'Удельная теплота плавления и кристаллизации', 'Phase 1 Wave 4') + secNavFor('p9') + readButton('p9'); renderMath(box); wireReadBtn('p9'); },
p10: ()=>{ const box=document.getElementById('p10-body'); box.innerHTML = buildStub('p10', 'Испарение жидкостей. Факторы, влияющие на скорость испарения', 'Phase 1 Wave 5') + secNavFor('p10') + readButton('p10'); renderMath(box); wireReadBtn('p10'); },
@@ -2030,6 +2047,468 @@ function _initP5_mcq(){
render();
}
/* ======================================================================
PHASE 1 · WAVE 3 — §6, §7
====================================================================== */
/* Таблица удельных теплоёмкостей (Дж/(кг·К)) */
const MAT_C = [
{key:'water', name:'вода', c:4200},
{key:'ice', name:'лёд', c:2100},
{key:'oil', name:'масло раст.',c:2000},
{key:'wood', name:'дерево', c:2400},
{key:'glass', name:'стекло', c:840 },
{key:'al', name:'алюминий', c:920 },
{key:'fe', name:'железо', c:460 },
{key:'brass', name:'латунь', c:380 },
{key:'cu', name:'медь', c:380 },
{key:'lead', name:'свинец', c:130 },
{key:'hg', name:'ртуть', c:140 }
];
/* Таблица удельных теплот сгорания (Дж/кг) */
const MAT_Q = [
{key:'wood', name:'дрова', q:1.0e7},
{key:'peat', name:'торф', q:1.5e7},
{key:'coal', name:'каменный уголь', q:3.0e7},
{key:'alc', name:'спирт', q:2.7e7},
{key:'oil', name:'нефть', q:4.4e7},
{key:'gas', name:'природный газ', q:4.4e7},
{key:'kero', name:'керосин', q:4.6e7},
{key:'gasoline',name:'бензин', q:4.6e7}
];
/* ======== §6 — Q = cm ΔT ======== */
function build_p6(){
const box = document.getElementById('p6-body');
let h = '';
h += makeCard('theory', 'Закон нагревания', '§ 6.1',
'<p>Чтобы изменить температуру тела массой $m$ на $\\Delta T = T_2 - T_1$, нужно сообщить ему (или отнять у него) количество теплоты:</p>'
+'<p style="text-align:center;margin:8px 0">$$Q = c\\,m\\,\\Delta T$$</p>'
+'<ul style="padding-left:20px;margin:6px 0">'
+'<li>$Q$ — количество теплоты, Дж;</li>'
+'<li>$c$ — <b>удельная теплоёмкость</b> вещества, Дж/(кг·К);</li>'
+'<li>$m$ — масса, кг;</li>'
+'<li>$\\Delta T$ — изменение температуры, К или &#176;C (разница одна).</li>'
+'</ul>'
+'<p>Если $T_2 > T_1$ — тело нагревается, $Q > 0$. Если $T_2 < T_1$ — остывает, $Q < 0$.</p>'
);
h += makeCard('rule', 'Что такое удельная теплоёмкость', '§ 6.2',
'<p><b>$c$</b> — количество теплоты, нужное чтобы нагреть <b>1 кг</b> вещества на <b>1 К</b> (или 1 &#176;C).</p>'
+'<p>У воды $c = 4200$ Дж/(кг·К) — это очень много. Поэтому:</p>'
+'<ul style="padding-left:20px;margin:6px 0">'
+'<li>вода долго греется на плите;</li>'
+'<li>вода долго остывает (поэтому грелка из воды держит тепло);</li>'
+'<li>океан смягчает климат прибрежных стран.</li>'
+'</ul>'
+'<p>У металлов $c$ маленькая: медь 380, железо 460. Они быстро нагреваются и быстро остывают.</p>'
);
h += makeCard('example', 'Уравнение теплового баланса', '§ 6.3',
'<p>Когда горячее тело отдаёт тепло холодному в изолированной системе (без потерь), вся отданная теплота получена холодным:</p>'
+'<p style="text-align:center;margin:8px 0">$$Q_{отд} = Q_{пол}$$</p>'
+'<p>Если смешать массы $m_1$ при $T_1$ и $m_2$ при $T_2$ одного вещества:</p>'
+'<p style="text-align:center">$$T = \\dfrac{m_1 T_1 + m_2 T_2}{m_1 + m_2}$$</p>'
+'<p>Это <b>средневзвешенная</b> температура.</p>'
);
/* IV1 — калькулятор Q = cmΔT с анимацией */
let optsC = '';
MAT_C.forEach(m=>{ optsC += '<option value="'+m.c+'">'+m.name+' (c = '+m.c+')</option>'; });
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Калькулятор $Q = cm\\Delta T$</div></div>'
+'<div class="wg-help">Выбери вещество, массу и изменение температуры — увидь, сколько энергии нужно. Термометр покажет процесс.</div>'
+'<div class="sliders" style="margin-bottom:10px">'
+'<label>Вещество: <select id="p6-mat" class="tinp" style="width:auto;padding:6px 10px;font-size:.92rem">'+optsC+'</select></label>'
+'<label>$m$, кг: <b id="p6-mv">1.0</b><input type="range" id="p6-m" min="0.1" max="10" step="0.1" value="1"></label>'
+'<label>$\\Delta T$, &#176;C: <b id="p6-dv">50</b><input type="range" id="p6-d" min="-50" max="100" step="5" value="50"></label>'
+'</div>'
+'<svg id="p6-sim" viewBox="0 0 460 160" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
+'<span>$c$ = <b id="p6-cv">4200</b> Дж/(кг·К)</span>'
+'<span>$Q$ = <b id="p6-q">2.10 &times; 10^5</b> Дж = <b id="p6-qkj">210</b> кДж</span>'
+'<span style="font-size:.84rem;color:var(--muted)">Это столько энергии съедает плита или электрочайник.</span>'
+'</div>'
+'</div>';
/* IV2 — калькулятор смешивания */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Смешивание воды</div></div>'
+'<div class="wg-help">В термос налили $m_1$ кг воды при $T_1$ &#176;C и долили $m_2$ кг воды при $T_2$ &#176;C. Какая будет итоговая температура (без потерь)? Формула: $T = (m_1 T_1 + m_2 T_2)/(m_1 + m_2)$.</div>'
+'<div class="sliders" style="margin-bottom:10px">'
+'<label>$m_1$, кг: <b id="p6-mxv1">1.0</b><input type="range" id="p6-mx1" min="0.1" max="5" step="0.1" value="1"></label>'
+'<label>$T_1$, &#176;C: <b id="p6-txv1">90</b><input type="range" id="p6-tx1" min="0" max="100" step="5" value="90"></label>'
+'<label>$m_2$, кг: <b id="p6-mxv2">2.0</b><input type="range" id="p6-mx2" min="0.1" max="5" step="0.1" value="2"></label>'
+'<label>$T_2$, &#176;C: <b id="p6-txv2">10</b><input type="range" id="p6-tx2" min="0" max="100" step="5" value="10"></label>'
+'</div>'
+'<div class="score-display" style="margin-top:6px"><span>$T_{итог} = $ <b id="p6-tres">36.7</b> &#176;C</span></div>'
+'</div>';
/* IV3 — DnD ранжирование c */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">У какого вещества $c$ больше?</div></div>'
+'<div class="wg-help">Перетащи вещества так, чтобы они шли от <b>меньшего</b> $c$ к <b>большему</b>. Подсказка: у воды $c$ рекордно велика, у металлов — мала.</div>'
+'<div id="p6-dnd-pool"></div>'
+'<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:10px">'
+'<div class="drop-box"><h5>1. Меньше всех</h5><div class="drop-items" data-cat="r1"></div></div>'
+'<div class="drop-box"><h5>2</h5><div class="drop-items" data-cat="r2"></div></div>'
+'<div class="drop-box"><h5>3</h5><div class="drop-items" data-cat="r3"></div></div>'
+'<div class="drop-box"><h5>4</h5><div class="drop-items" data-cat="r4"></div></div>'
+'<div class="drop-box"><h5>5. Больше всех</h5><div class="drop-items" data-cat="r5"></div></div>'
+'</div>'
+'<div class="actions"><button class="btn primary" id="p6-dnd-check">Проверить</button><button class="btn" id="p6-dnd-reset">Сброс</button></div>'
+'<div class="feedback" id="p6-dnd-fb"></div>'
+'</div>';
/* IV4 — тренажёр расчётных задач */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 расчётных задач</div></div>'
+'<div class="wg-help">Введи числовой ответ. 4+ верных решения — +15 XP. Допуск ±2%.</div>'
+'<div id="p6-task"></div>'
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p6-task-i">1</b> / 6</span><span>Правильно: <b id="p6-task-ok">0</b></span></div>'
+'</div>';
box.innerHTML = h + secNavFor('p6') + readButton('p6');
renderMath(box);
wireReadBtn('p6');
_initP6_calc();
_initP6_mix();
_initP6_dnd();
_initP6_tasks();
}
function _initP6_calc(){
const svg = document.getElementById('p6-sim'); if(!svg) return;
function fmtSci(x){
if(Math.abs(x) < 1000) return x.toFixed(0);
const e = Math.floor(Math.log10(Math.abs(x)));
const mant = (x / Math.pow(10, e)).toFixed(2);
return mant+' &times; 10<sup>'+e+'</sup>';
}
function update(){
const c = +document.getElementById('p6-mat').value;
const m = +document.getElementById('p6-m').value;
const d = +document.getElementById('p6-d').value;
document.getElementById('p6-mv').textContent = m.toFixed(1);
document.getElementById('p6-dv').textContent = d;
document.getElementById('p6-cv').textContent = c;
const Q = c * m * d;
document.getElementById('p6-q').innerHTML = fmtSci(Q);
document.getElementById('p6-qkj').textContent = (Q/1000).toFixed(1);
/* sim: куб + термометр, цвет по итоговой T (20 + d) */
const Tfinal = 20 + d;
const col = window.PHYS.tempColor(Tfinal, -50, 150);
let s = '';
s += '<rect x="60" y="40" width="100" height="80" fill="'+col+'" stroke="#0f172a" stroke-width="2" rx="6"/>';
s += '<text x="110" y="86" text-anchor="middle" font-family="Inter,sans-serif" font-size="13" font-weight="800" fill="'+(Tfinal>50?'#fff':'#0f172a')+'">m = '+m.toFixed(1)+' кг</text>';
s += '<text x="110" y="140" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" fill="#475569">'+(d>0?'нагреваем':d<0?'охлаждаем':'без изменения')+'</text>';
/* термометр */
s += window.PHYS.thermometer(220, 30, 100, -50, 150, Tfinal);
/* подпись Q */
s += '<text x="320" y="60" font-family="JetBrains Mono,monospace" font-size="13" fill="#0f172a">Q = c &middot; m &middot; &Delta;T</text>';
s += '<text x="320" y="82" font-family="JetBrains Mono,monospace" font-size="12" fill="#475569">= '+c+' &middot; '+m.toFixed(1)+' &middot; '+d+'</text>';
s += '<text x="320" y="104" font-family="JetBrains Mono,monospace" font-size="14" font-weight="800" fill="'+(Q>=0?'#dc2626':'#2563eb')+'">Q = '+(Q/1000).toFixed(1)+' кДж</text>';
svg.innerHTML = s;
}
document.getElementById('p6-mat').addEventListener('change', update);
document.getElementById('p6-m').addEventListener('input', update);
document.getElementById('p6-d').addEventListener('input', update);
update();
}
function _initP6_mix(){
function update(){
const m1 = +document.getElementById('p6-mx1').value;
const t1 = +document.getElementById('p6-tx1').value;
const m2 = +document.getElementById('p6-mx2').value;
const t2 = +document.getElementById('p6-tx2').value;
document.getElementById('p6-mxv1').textContent = m1.toFixed(1);
document.getElementById('p6-txv1').textContent = t1;
document.getElementById('p6-mxv2').textContent = m2.toFixed(1);
document.getElementById('p6-txv2').textContent = t2;
const T = (m1*t1 + m2*t2) / (m1 + m2);
document.getElementById('p6-tres').textContent = T.toFixed(1);
}
['p6-mx1','p6-tx1','p6-mx2','p6-tx2'].forEach(id => document.getElementById(id).addEventListener('input', update));
update();
}
function _initP6_dnd(){
/* 5 веществ по возрастанию c: свинец(130) → железо(460) → стекло(840) → дерево(2400) → вода(4200) */
const items = [
{id:'pb', cat:'r1', html:'свинец (130)'},
{id:'fe', cat:'r2', html:'железо (460)'},
{id:'gl', cat:'r3', html:'стекло (840)'},
{id:'wd', cat:'r4', html:'дерево (2400)'},
{id:'wa', cat:'r5', html:'вода (4200)'}
];
const dnd = setupSorter({ poolId:'p6-dnd-pool', scopeSelector:'#sec-p6', cats:['r1','r2','r3','r4','r5'], items, columnLayout:false });
document.getElementById('p6-dnd-check').addEventListener('click', ()=>{
const fb = document.getElementById('p6-dnd-fb');
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально! +15 XP. У воды $c$ рекордно велика — её сложно нагреть и сложно охладить.'; addXp(15,'p6-dnd'); bumpProgress('p6', 20); renderMath(fb); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'. Подсказка: металлы — мало, вода — рекорд.'; }
});
document.getElementById('p6-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p6-dnd-fb'); fb.style.display='none'; });
}
function _initP6_tasks(){
const TASKS = [
{q:'Сколько энергии в кДж нужно, чтобы нагреть 2 кг воды от 20 до 100 &#176;C? ($c_{воды} = 4200$)', ans: 672, tol: 14, why:'$Q = 4200 \\cdot 2 \\cdot 80 = 672\\,000$ Дж = $672$ кДж.'},
{q:'Какую массу алюминия (в кг) можно нагреть на 50 &#176;C, имея 92 кДж? ($c = 920$)', ans: 2, tol: 0.05, why:'$m = Q/(c \\Delta T) = 92\\,000/(920 \\cdot 50) = 2$ кг.'},
{q:'На сколько градусов нагреется 0,5 кг меди при $Q = 19\\,000$ Дж? ($c = 380$)', ans: 100, tol: 2, why:'$\\Delta T = Q/(cm) = 19\\,000/(380 \\cdot 0{,}5) = 100$ К.'},
{q:'Смешали 1 кг воды при 80 &#176;C и 3 кг воды при 20 &#176;C. Какая итоговая температура (&#176;C)?', ans: 35, tol: 0.5, why:'$T = (1 \\cdot 80 + 3 \\cdot 20)/4 = 140/4 = 35$ &#176;C.'},
{q:'Какова удельная теплоёмкость (Дж/(кг·К)) вещества, если 3 кг его при $\\Delta T = 40$ К получили 48 кДж?', ans: 400, tol: 10, why:'$c = Q/(m\\Delta T) = 48\\,000/(3 \\cdot 40) = 400$. Это близко к меди.'},
{q:'Найди $Q$ (в кДж) для остывания 4 кг железа с 200 до 50 &#176;C. ($c = 460$). Запиши абсолютную величину.', ans: 276, tol: 6, why:'$|Q| = 460 \\cdot 4 \\cdot 150 = 276\\,000$ Дж = $276$ кДж.'}
];
let i = 0, ok = 0, done = 0, awarded = false;
function render(){
const t = TASKS[i]; const wrap = document.getElementById('p6-task'); if(!wrap) return;
wrap.innerHTML =
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p6-task-inp" placeholder="число" style="width:140px">'
+'<button class="btn primary" id="p6-task-go">Ответ</button>'
+'<button class="btn" id="p6-task-hint">Подсказка</button>'
+'<button class="btn" id="p6-task-next">Следующая</button></div>'
+'<div class="boss-hint-txt" id="p6-task-hint-txt">'+t.why+'</div>'
+'<div class="feedback" id="p6-task-fb"></div>';
document.getElementById('p6-task-i').textContent = (i+1);
document.getElementById('p6-task-ok').textContent = ok;
document.getElementById('p6-task-go').addEventListener('click', ()=>{
const v = parseFloat((document.getElementById('p6-task-inp').value || '').replace(',','.'));
const fb = document.getElementById('p6-task-fb');
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
done++;
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно! '+t.why; addXp(4,'p6-task'); bumpProgress('p6', 6); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. Правильный ответ: '+t.ans+'. '+t.why; }
document.getElementById('p6-task-ok').textContent = ok;
renderMath(wrap);
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p6-task-fb'); wf.className='feedback ok'; wf.innerHTML='&#10003; +15 XP — расчёты сданы ('+ok+'/'+TASKS.length+').'; addXp(15,'p6-task-bonus'); bumpProgress('p6', 15); }, 600); }
});
document.getElementById('p6-task-hint').addEventListener('click', ()=>{ document.getElementById('p6-task-hint-txt').classList.toggle('show'); });
document.getElementById('p6-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
renderMath(wrap);
}
render();
}
/* ======== §7 — Q = qm ======== */
function build_p7(){
const box = document.getElementById('p7-body');
let h = '';
h += makeCard('theory', 'Горение и теплота сгорания', '§ 7.1',
'<p>При <b>горении</b> топливо реагирует с кислородом и выделяет энергию в виде тепла. Энергия эта запасена в химических связях молекул топлива.</p>'
+'<p>Количество теплоты, выделившееся при <b>полном сгорании</b> массы $m$ топлива:</p>'
+'<p style="text-align:center;margin:8px 0">$$Q = q\\,m$$</p>'
+'<p>$q$ — <b>удельная теплота сгорания</b>, Дж/кг. Это энергия, которую даёт сгорание 1 кг данного топлива.</p>'
);
h += makeCard('rule', 'Топлива и их $q$', '§ 7.2',
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><thead><tr style="background:rgba(15,23,42,.04)"><th style="padding:6px;text-align:left">Топливо</th><th style="padding:6px;text-align:right">$q$, $\\dfrac{\\text{Дж}}{\\text{кг}}$</th></tr></thead><tbody>'
+ MAT_Q.map(m=>'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">'+m.name+'</td><td style="padding:6px;text-align:right;border-bottom:1px dashed var(--border)"><code>'+m.q.toExponential(1).replace('+','')+'</code></td></tr>').join('')
+'</tbody></table>'
+'<p style="margin-top:8px">Чем больше $q$, тем «энергоёмче» топливо. Бензин примерно в 4,5 раза мощнее дров на кг.</p>'
);
h += makeCard('example', 'КПД нагревательного устройства', '§ 7.3',
'<p>Реально <b>не вся</b> выделившаяся при сгорании энергия идёт на полезное дело (нагрев воды, движение машины). Часть теряется в виде тепла в окружающую среду.</p>'
+'<p>$$\\eta = \\dfrac{Q_{пол}}{Q_{сгор}} = \\dfrac{Q_{пол}}{q m}$$</p>'
+'<p>У хорошего котла $\\eta \\approx 80\\%$, у плохой буржуйки — 30%.</p>'
);
/* IV1 — калькулятор Q = qm */
let optsQ = '';
MAT_Q.forEach(m=>{ optsQ += '<option value="'+m.q+'">'+m.name+' ($q = '+m.q.toExponential(1).replace('+','').replace('.','{,}')+'$)</option>'; });
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Калькулятор $Q = qm$</div></div>'
+'<div class="wg-help">Выбери топливо и массу — увидь, сколько энергии выделится при его полном сгорании.</div>'
+'<div class="sliders" style="margin-bottom:10px">'
+'<label>Топливо: <select id="p7-fuel" class="tinp" style="width:auto;padding:6px 10px;font-size:.92rem">'
+ MAT_Q.map(m=>'<option value="'+m.q+'">'+m.name+' (q='+m.q.toExponential(1).replace('+','')+')</option>').join('')
+'</select></label>'
+'<label>$m$, кг: <b id="p7-mv">1.0</b><input type="range" id="p7-m" min="0.1" max="20" step="0.1" value="1"></label>'
+'</div>'
+'<svg id="p7-sim" viewBox="0 0 460 140" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
+'<span>$q$ = <b id="p7-qv">10<sup>7</sup></b> Дж/кг</span>'
+'<span>$Q$ = <b id="p7-q">10 МДж</b> = <b id="p7-qkw">2.8</b> кВт·ч</span>'
+'<span style="font-size:.84rem;color:var(--muted)">Эквивалент: нагрев <b id="p7-eqkg">30</b> кг воды от 20 до 100 &#176;C.</span>'
+'</div>'
+'</div>';
/* IV2 — викторина «какое топливо мощнее» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Какое топливо мощнее?</div></div>'
+'<div class="wg-help">Выбери топливо с большей удельной теплотой сгорания.</div>'
+'<div id="p7-quiz"></div>'
+'<div class="actions"><button class="btn" id="p7-quiz-next">Следующий раунд</button></div>'
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p7-quiz-r">1</b> / 6</span><span>Правильно: <b id="p7-quiz-ok">0</b></span></div>'
+'</div>';
/* IV3 — DnD ранжирование топлив */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Расставь топлива по $q$ (по возрастанию)</div></div>'
+'<div class="wg-help">От самого слабого до самого мощного по теплоте сгорания.</div>'
+'<div id="p7-dnd-pool"></div>'
+'<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:10px">'
+'<div class="drop-box"><h5>1. Меньше</h5><div class="drop-items" data-cat="r1"></div></div>'
+'<div class="drop-box"><h5>2</h5><div class="drop-items" data-cat="r2"></div></div>'
+'<div class="drop-box"><h5>3</h5><div class="drop-items" data-cat="r3"></div></div>'
+'<div class="drop-box"><h5>4</h5><div class="drop-items" data-cat="r4"></div></div>'
+'<div class="drop-box"><h5>5. Больше</h5><div class="drop-items" data-cat="r5"></div></div>'
+'</div>'
+'<div class="actions"><button class="btn primary" id="p7-dnd-check">Проверить</button><button class="btn" id="p7-dnd-reset">Сброс</button></div>'
+'<div class="feedback" id="p7-dnd-fb"></div>'
+'</div>';
/* IV4 — тренажёр расчётных задач */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
+'<div class="wg-help">4+ верных — +15 XP. Допуск ±3 %.</div>'
+'<div id="p7-task"></div>'
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p7-task-i">1</b> / 5</span><span>Правильно: <b id="p7-task-ok">0</b></span></div>'
+'</div>';
box.innerHTML = h + secNavFor('p7') + readButton('p7');
renderMath(box);
wireReadBtn('p7');
_initP7_calc();
_initP7_quiz();
_initP7_dnd();
_initP7_tasks();
}
function _initP7_calc(){
const svg = document.getElementById('p7-sim'); if(!svg) return;
function update(){
const q = +document.getElementById('p7-fuel').value;
const m = +document.getElementById('p7-m').value;
document.getElementById('p7-mv').textContent = m.toFixed(1);
document.getElementById('p7-qv').innerHTML = q.toExponential(1).replace('+','').replace('e', ' &times; 10<sup>')+'</sup>';
const Q = q * m;
document.getElementById('p7-q').innerHTML = (Q/1e6).toFixed(1)+' МДж';
document.getElementById('p7-qkw').textContent = (Q/3.6e6).toFixed(2);
/* эквивалент: нагрев воды от 20 до 100 → ΔT=80, Q=cmΔT, m = Q/(c·80) */
document.getElementById('p7-eqkg').textContent = (Q/(4200*80)).toFixed(1);
/* SVG: огонь + котелок */
let s = '';
/* печь */
s += '<rect x="40" y="50" width="120" height="80" fill="#374151" stroke="#0f172a" stroke-width="2" rx="4"/>';
/* пламя */
const flameH = 30 + Math.min(50, m*5);
s += '<path d="M 70 90 Q 65 '+(90-flameH)+' 80 '+(80-flameH/2)+' Q 90 '+(85-flameH)+' 100 '+(70-flameH/2)+' Q 110 '+(85-flameH)+' 120 '+(80-flameH/2)+' Q 135 '+(90-flameH)+' 130 90 Z" fill="#f59e0b"/>';
s += '<path d="M 80 90 Q 78 '+(90-flameH*0.6)+' 90 '+(85-flameH*0.3)+' Q 100 '+(88-flameH*0.6)+' 110 '+(85-flameH*0.3)+' Q 122 '+(90-flameH*0.6)+' 120 90 Z" fill="#fbbf24"/>';
/* топливо */
s += '<text x="100" y="115" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" fill="#fde047">'+m.toFixed(1)+' кг</text>';
/* стрелка-энергия */
s += '<text x="200" y="60" font-family="JetBrains Mono,monospace" font-size="13" fill="#0f172a">Q = q m</text>';
s += '<text x="200" y="84" font-family="JetBrains Mono,monospace" font-size="12" fill="#475569">= '+q.toExponential(1).replace('+','')+' &middot; '+m.toFixed(1)+'</text>';
s += '<text x="200" y="108" font-family="JetBrains Mono,monospace" font-size="14" font-weight="800" fill="#dc2626">Q = '+(Q/1e6).toFixed(1)+' МДж</text>';
s += '<text x="200" y="128" font-family="Inter,sans-serif" font-size="11" fill="#475569">'+(Q/3.6e6).toFixed(2)+' кВт&middot;ч</text>';
svg.innerHTML = s;
}
document.getElementById('p7-fuel').addEventListener('change', update);
document.getElementById('p7-m').addEventListener('input', update);
update();
}
function _initP7_quiz(){
const QS = [
{A:'дрова', B:'бензин', ans:'B', why:'У бензина $q \\approx 4{,}6 \\cdot 10^7$, у дров $\\approx 10^7$ — бензин в 4,5 раза мощнее.'},
{A:'торф', B:'каменный уголь', ans:'B', why:'У угля $q$ вдвое больше, чем у торфа.'},
{A:'спирт', B:'природный газ', ans:'B', why:'У газа $4{,}4 \\cdot 10^7$, у спирта $2{,}7 \\cdot 10^7$.'},
{A:'керосин', B:'дрова', ans:'A', why:'Керосин — продукт переработки нефти, $q$ в 4,6 раза больше.'},
{A:'нефть', B:'бензин', ans:'B', why:'У бензина чуть больше: $4{,}6$ против $4{,}4 \\cdot 10^7$.'},
{A:'торф', B:'дрова', ans:'B', why:'У дров $q \\approx 10^7$, у торфа $1{,}5 \\cdot 10^7$ — торф мощнее. Правильный ответ: <b>торф</b>, ответ A.', flip:true}
];
let i = 0, ok = 0;
function render(){
const q = QS[i]; const wrap = document.getElementById('p7-quiz'); if(!wrap) return;
/* для flip-задачи правильный ответ A */
const correctAns = q.flip ? 'A' : q.ans;
wrap.innerHTML =
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:8px">'
+'<button class="btn" data-pick="A" style="padding:14px"><b>A.</b> '+q.A+'</button>'
+'<button class="btn" data-pick="B" style="padding:14px"><b>B.</b> '+q.B+'</button>'
+'</div>'
+'<div class="feedback" id="p7-quiz-fb"></div>';
document.getElementById('p7-quiz-r').textContent = (i+1);
document.getElementById('p7-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('p7-quiz-fb');
if(btn.dataset.pick === correctAns){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(3,'p7-quiz'); bumpProgress('p7', 4); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p7-quiz-ok').textContent = ok;
renderMath(wrap);
});
});
renderMath(wrap);
}
document.getElementById('p7-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
render();
}
function _initP7_dnd(){
/* 5 топлив по возрастанию q: дрова(1) → торф(1.5) → спирт(2.7) → уголь(3) → бензин(4.6), все ×10^7 */
const items = [
{id:'wd', cat:'r1', html:'дрова ($10^7$)'},
{id:'pt', cat:'r2', html:'торф ($1{,}5 \\cdot 10^7$)'},
{id:'al', cat:'r3', html:'спирт ($2{,}7 \\cdot 10^7$)'},
{id:'cl', cat:'r4', html:'уголь ($3 \\cdot 10^7$)'},
{id:'gs', cat:'r5', html:'бензин ($4{,}6 \\cdot 10^7$)'}
];
const dnd = setupSorter({ poolId:'p7-dnd-pool', scopeSelector:'#sec-p7', cats:['r1','r2','r3','r4','r5'], items, columnLayout:false });
document.getElementById('p7-dnd-check').addEventListener('click', ()=>{
const fb = document.getElementById('p7-dnd-fb');
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально! +15 XP. Углеводороды (нефть, бензин, газ) — самые энергоёмкие.'; addXp(15,'p7-dnd'); bumpProgress('p7', 20); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'. Подсказка: бензин — самый мощный из распространённых.'; }
});
document.getElementById('p7-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p7-dnd-fb'); fb.style.display='none'; });
}
function _initP7_tasks(){
const TASKS = [
{q:'Сколько энергии (в МДж) выделится при полном сгорании 2 кг бензина? ($q = 4{,}6 \\cdot 10^7$)', ans: 92, tol: 2, why:'$Q = qm = 4{,}6 \\cdot 10^7 \\cdot 2 = 9{,}2 \\cdot 10^7 = 92$ МДж.'},
{q:'Какую массу (в кг) дров нужно сжечь, чтобы получить 50 МДж энергии? ($q = 10^7$)', ans: 5, tol: 0.1, why:'$m = Q/q = 5 \\cdot 10^7 / 10^7 = 5$ кг.'},
{q:'При сгорании 0,5 кг угля выделилось 15 МДж. Чему равно $q$ (в МДж/кг)?', ans: 30, tol: 1, why:'$q = Q/m = 15/0{,}5 = 30$ МДж/кг — это каменный уголь.'},
{q:'Котёл с $\\eta = 80\\%$ сжёг 2 кг дров. Какая полезная энергия (в МДж)? ($q = 10^7$)', ans: 16, tol: 0.3, why:'$Q_{сгор}=2 \\cdot 10^7 = 20$ МДж. $Q_{пол} = \\eta \\cdot Q_{сгор} = 0{,}8 \\cdot 20 = 16$ МДж.'},
{q:'Сколько кг бензина даст столько же энергии, что и 9,2 кг дров? ($q_{дров}=10^7$, $q_{бенз}=4{,}6 \\cdot 10^7$)', ans: 2, tol: 0.05, why:'Энергия дров: $9{,}2 \\cdot 10^7$ Дж. $m_{бенз}=E/q_{бенз}=9{,}2 \\cdot 10^7/(4{,}6 \\cdot 10^7) = 2$ кг.'}
];
let i = 0, ok = 0, done = 0, awarded = false;
function render(){
const t = TASKS[i]; const wrap = document.getElementById('p7-task'); if(!wrap) return;
wrap.innerHTML =
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p7-task-inp" placeholder="число" style="width:140px">'
+'<button class="btn primary" id="p7-task-go">Ответ</button>'
+'<button class="btn" id="p7-task-hint">Подсказка</button>'
+'<button class="btn" id="p7-task-next">Следующая</button></div>'
+'<div class="boss-hint-txt" id="p7-task-hint-txt">'+t.why+'</div>'
+'<div class="feedback" id="p7-task-fb"></div>';
document.getElementById('p7-task-i').textContent = (i+1);
document.getElementById('p7-task-ok').textContent = ok;
document.getElementById('p7-task-go').addEventListener('click', ()=>{
const v = parseFloat((document.getElementById('p7-task-inp').value || '').replace(',','.'));
const fb = document.getElementById('p7-task-fb');
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
done++;
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно! '+t.why; addXp(4,'p7-task'); bumpProgress('p7', 6); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. Правильный ответ: '+t.ans+'. '+t.why; }
document.getElementById('p7-task-ok').textContent = ok;
renderMath(wrap);
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p7-task-fb'); wf.className='feedback ok'; wf.innerHTML='&#10003; +15 XP — расчёты сданы ('+ok+'/'+TASKS.length+').'; addXp(15,'p7-task-bonus'); bumpProgress('p7', 15); }, 600); }
});
document.getElementById('p7-task-hint').addEventListener('click', ()=>{ document.getElementById('p7-task-hint-txt').classList.toggle('show'); });
document.getElementById('p7-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);