Files
Learn_System/frontend/js/phys7_ch4_widgets.js
Maxim Dolgolyov c7345a71cf feat(phys7 ch4): Phase 5 — Давление, §§28-35 + финал «Властелин давления»
Глава 4 «Давление» закрыта целиком. Файл phys7_ch4_widgets.js (1300 строк,
9 экспортов: p28..p35 + final4). Палитра amber.

§28 Давление и единицы:
- 3 карточки + таблица сравнения 5 объектов (гвоздь / балерина / человек / лыжник / трактор)
- IV-1 КАЛЬК p=F/S с автосравнением (лыжник на снегу / каблук на паркете / ГПа гвоздь)
- IV-2 СИМ: 3 сценария «один человек — разные опоры» (ботинки / лыжи / каблук)
- DnD 6→3 / тренажёр 5

§29 Давление газа:
- 3 карточки (удары молекул / что увеличивает p / шар и шина)
- IV-1 СИМ: анимация молекул в сосуде, slider N и T, подсчёт ударов о стенки в реальном времени
- DnD 6→2 (растёт/падает) / квиз 4 / тренажёр 4

§30 Закон Паскаля + гидравлический пресс:
- 3 карточки (закон / формула F2/F1=S2/S1 / применения)
- IV-1 СИМ: использует PHYS.hydraulicPress, 3 slider'а S1/S2/F1, вывод F2 + выигрыш
- IV-2 КАЛЬК с формулой
- DnD 6→2 / тренажёр 4

§31 Гидростатика:
- 3 карточки + таблица «глубина / давление»
- IV-1 КАЛЬК ρgh с выбором жидкости (вода/бензин/морская/ртуть/спирт)
- IV-2 СИМ: гидростатический парадокс — 3 сосуда разной формы (цилиндр/широкий/узкий),
  один уровень → одинаковое p на дне
- DnD 6→2 / тренажёр 5

§32 Сообщающиеся сосуды:
- 3 карточки + IV-1 СИМ: использует PHYS.connectedVessels, 3 варианта форм
  (2 цилиндра / цилиндр+широкий / узкий+широкий), slider уровня
- DnD 6→2 / квиз 3 / тренажёр 4

§33 Газы и их вес:
- 3 карточки (m=ρV / опыт со взвешиванием шара)
- IV-1 КАЛЬК: 3 slider'а a/b/c комнаты → V, m, P воздуха с автосравнением
  (школьник / человек / пианино / автомобиль)
- DnD 6→2 (легче/тяжелее воздуха): He/H2/CH4 vs CO2/Cl2/Rn
- квиз 3 / тренажёр 4

§34 Атмосферное давление:
- 3 карточки (опыт Торричелли / падение с высотой 1мм/12м)
- IV-1 СИМ: PHYS.mercuryBarometer, slider 400..800 мм рт.ст. с описанием погоды
- IV-2 КАЛЬК: slider высоты 0..5000 м → давление с автоописанием места
- DnD 6→3 (норма/выше/ниже) / тренажёр 5

§35 БАРОМЕТРЫ И МАНОМЕТРЫ — ГЛАВНЫЙ ВИЗУАЛ ГЛАВЫ 4:
- 3 карточки (3 прибора / где какой / манометр на баллоне)
- IV-1 СИМ: три прибора рядом — Торричелли + Анероид + U-манометр (все 3
  PHYS-хелпера). Один slider давления → видишь одно давление в трёх формах.
- DnD 6→2 (баро/мано) / квиз 4 / тренажёр 4

ФИНАЛ ГЛАВЫ 4 (7 боссов + ачивка «Властелин давления» +50 XP):
1. p кирпича (5000 Па)
2. Гидравлический пресс (8000 Н)
3. Дайвер 20 м в море (206 кПа)
4. Сообщ. сосуды (одинаковый уровень 18 см)
5. Давление на высоте 480 м (720 мм)
6. Барометр → Па (98 400 Па)
7. Властелин: полное давление дайвера = атмосферное + гидростатич. (400 кПа)

Parse OK, smoke (9 экспортов) OK.
2026-05-30 11:34:12 +03:00

1301 lines
97 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Физика 7 · Глава 4 «Давление» · виджеты §§28–35 + финал.
// Палитра главы — amber (#d97706).
(function(){
'use strict';
const ACCENT = '#d97706';
const ACCENT_D = '#92400e';
const ACCENT_SOFT = '#fef3c7';
function renderMath(root){
if(window.renderMathInElement){
try{
window.renderMathInElement(root, {
delimiters: [{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}],
throwOnError: false
});
}catch(e){}
}
}
function makeCard(kind, title, badge, body){
const colorByKind = { theory:ACCENT, rule:'#0284c7', example:'#10b981' };
const labelByKind = { theory:'Теория', rule:'Правило', example:'Пример' };
const c = colorByKind[kind] || ACCENT;
return '<div style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-left:5px solid ' + c + ';border-radius:11px;padding:14px 16px;margin-bottom:14px;box-shadow:0 2px 8px rgba(0,0,0,.05)">'
+ '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap">'
+ '<span style="background:' + c + ';color:#fff;padding:3px 10px;border-radius:99px;font-size:.7rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em">' + labelByKind[kind] + '</span>'
+ '<span style="font-size:.72rem;font-weight:700;color:#64748b;letter-spacing:.04em">' + (badge||'') + '</span>'
+ '<span style="font-family:Unbounded,sans-serif;font-weight:800;font-size:.96rem;color:#0f172a;flex:1;min-width:0">' + title + '</span>'
+ '</div>'
+ '<div style="font-size:.94rem;line-height:1.6;color:#0f172a">' + body + '</div>'
+ '</div>';
}
function wgWrap(id, badge, title, hint, body){
return '<div id="' + id + '" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:12px;padding:14px 16px;margin-bottom:14px;box-shadow:0 2px 8px rgba(0,0,0,.05)">'
+ '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap">'
+ '<span style="background:' + ACCENT + ';color:#fff;padding:3px 10px;border-radius:99px;font-size:.7rem;font-weight:800;letter-spacing:.05em">' + badge + '</span>'
+ '<span style="font-family:Unbounded,sans-serif;font-weight:800;font-size:.92rem;color:#0f172a">' + title + '</span>'
+ '</div>'
+ (hint ? '<div style="font-size:.84rem;color:#64748b;background:' + ACCENT_SOFT + ';border-left:3px solid ' + ACCENT + ';border-radius:6px;padding:8px 12px;margin-bottom:10px;line-height:1.5">' + hint + '</div>' : '')
+ body
+ '</div>';
}
function readButton(pid){
return '<div style="text-align:center;margin-top:18px"><button class="ph7-read-btn" data-pid="' + pid + '" '
+ 'style="background:linear-gradient(135deg,#10b981,#047857);color:#fff;border:none;padding:11px 22px;border-radius:11px;font-weight:700;font-size:.92rem;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;gap:8px;box-shadow:0 4px 14px rgba(16,185,129,.32)">'
+ '<svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"><polyline points="20 6 9 17 4 12"/></svg>'
+ 'Я прочитал § &nbsp;<span style="opacity:.85;font-size:.86rem">+10 XP</span>'
+ '</button></div>';
}
function wireReadBtn(pid){
const btn = document.querySelector('.ph7-read-btn[data-pid="' + pid + '"]');
if(!btn) return;
const KEY = 'physics7_ch4_read_' + pid;
if(localStorage.getItem(KEY) === '1'){
btn.innerHTML = '<svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"><polyline points="20 6 9 17 4 12"/></svg> Прочитано';
btn.disabled = true; btn.style.background = '#94a3b8'; btn.style.cursor = 'default';
return;
}
btn.addEventListener('click', function(){
if(localStorage.getItem(KEY) === '1') return;
localStorage.setItem(KEY, '1');
if(typeof window.bumpProgress === 'function') window.bumpProgress(pid, 30);
if(typeof window.addXp === 'function') window.addXp(10, 'read-' + pid);
btn.innerHTML = '<svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"><polyline points="20 6 9 17 4 12"/></svg> Прочитано';
btn.disabled = true; btn.style.background = '#94a3b8'; btn.style.cursor = 'default';
});
}
function wireDnd(host, items){
const root = document.getElementById(host);
if(!root) return;
const checkBtn = root.querySelector('.dnd-check');
const fb = root.querySelector('.dnd-fb');
let placed = {}, armed = null;
root.querySelectorAll('.dnd-chip').forEach(chip => chip.addEventListener('click', () => {
if(armed === chip){ armed.classList.remove('armed'); armed.style.boxShadow = ''; armed = null; return; }
if(armed){ armed.classList.remove('armed'); armed.style.boxShadow = ''; }
armed = chip;
chip.classList.add('armed');
chip.style.boxShadow = '0 0 0 3px rgba(217,119,6,.3)';
}));
root.querySelectorAll('.drop-box').forEach(box => box.addEventListener('click', () => {
if(!armed) return;
const cat = box.dataset.cat;
const id = armed.dataset.id;
placed[id] = cat;
const clone = armed.cloneNode(true);
clone.classList.remove('armed'); clone.classList.add('placed');
clone.style.background = ACCENT_SOFT; clone.style.borderColor = ACCENT; clone.style.boxShadow = '';
clone.addEventListener('click', e => {
e.stopPropagation();
delete placed[id];
clone.remove();
armed = null;
const orig = root.querySelector('.dnd-chip[data-id="' + id + '"]:not(.placed)');
if(orig) orig.style.display = '';
});
box.querySelector('.drop-items').appendChild(clone);
armed.style.display = 'none';
armed.classList.remove('armed'); armed.style.boxShadow = '';
armed = null;
}));
if(checkBtn) checkBtn.addEventListener('click', () => {
const total = items.length;
let correct = 0;
items.forEach(it => { if(placed[it.id] === it.cat) correct++; });
fb.style.display = 'block';
if(correct === total){
fb.style.background = '#d1fae5'; fb.style.color = '#065f46'; fb.style.borderLeft = '4px solid #10b981';
fb.innerHTML = '&#10003; Идеально! ' + total + '/' + total + '.';
if(typeof window.addXp === 'function') window.addXp(15, 'dnd-' + host);
} else {
fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.innerHTML = '&#10007; Правильно: ' + correct + '/' + total + '. Попробуй ещё раз.';
}
});
}
function dndPool(host, items, cats){
const chips = items.map(it => '<button class="dnd-chip" data-id="' + it.id + '" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:10px;padding:7px 13px;cursor:pointer;font-size:.9rem;font-family:inherit;transition:all .15s">' + it.html + '</button>').join('');
const boxes = cats.map(c => '<div class="drop-box" data-cat="' + c.cat + '" style="background:#fff;border:1.5px dashed ' + ACCENT_SOFT + ';border-radius:10px;padding:10px;min-height:80px"><h5 style="font-family:Unbounded,sans-serif;font-size:.76rem;color:' + ACCENT_D + ';margin-bottom:8px;text-transform:uppercase;letter-spacing:.04em">' + c.label + '</h5><div class="drop-items" style="display:flex;flex-wrap:wrap;gap:6px;min-height:32px"></div></div>').join('');
return '<div id="' + host + '" class="dnd-host">'
+ '<div style="font-size:.86rem;color:#475569;margin-bottom:10px">Кликни по карточке, потом по корзине. Чтобы вернуть — кликни в корзине.</div>'
+ '<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed ' + ACCENT_SOFT + ';border-radius:10px;background:#fffbeb">' + chips + '</div>'
+ '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px;margin-bottom:12px">' + boxes + '</div>'
+ '<div style="display:flex;gap:8px"><button class="dnd-check" type="button" style="background:linear-gradient(135deg,' + ACCENT + ',' + ACCENT_D + ');color:#fff;border:none;padding:9px 18px;border-radius:9px;font-weight:700;font-size:.86rem;cursor:pointer;font-family:inherit">Проверить</button></div>'
+ '<div class="dnd-fb" style="padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none;line-height:1.45"></div>'
+ '</div>';
}
function quizQuestion(host, idx, q, opts, correctIdx, explain){
const optsHtml = opts.map((o,i) => '<button class="qz-opt" data-i="' + i + '" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:9px;padding:9px 14px;cursor:pointer;font-size:.92rem;font-family:inherit;text-align:left;width:100%;margin-bottom:6px">' + o + '</button>').join('');
return '<div class="qz-q" data-idx="' + idx + '" style="background:' + ACCENT_SOFT + ';border:1.5px solid ' + ACCENT_SOFT + ';border-radius:10px;padding:12px 14px;margin-bottom:10px">'
+ '<div style="font-weight:700;margin-bottom:8px;font-size:.94rem">' + (idx+1) + '. ' + q + '</div>'
+ '<div class="qz-opts" data-correct="' + correctIdx + '" data-explain="' + (explain||'').replace(/"/g,'&quot;') + '">' + optsHtml + '</div>'
+ '<div class="qz-fb" style="padding:9px 12px;border-radius:8px;font-size:.86rem;margin-top:6px;display:none;line-height:1.45"></div>'
+ '</div>';
}
function wireQuiz(host, onAllCorrect){
const root = document.getElementById(host);
if(!root) return;
const all = root.querySelectorAll('.qz-q');
const done = new Set();
all.forEach(qDiv => {
const opts = qDiv.querySelectorAll('.qz-opt');
const correct = +qDiv.querySelector('.qz-opts').dataset.correct;
const explain = qDiv.querySelector('.qz-opts').dataset.explain;
const fb = qDiv.querySelector('.qz-fb');
opts.forEach(o => o.addEventListener('click', () => {
if(done.has(qDiv)) return;
const i = +o.dataset.i;
opts.forEach(x => x.disabled = true);
if(i === correct){
o.style.background = '#d1fae5'; o.style.borderColor = '#10b981'; o.style.color = '#065f46';
fb.style.display = 'block'; fb.style.background = '#d1fae5'; fb.style.color = '#065f46'; fb.style.borderLeft = '4px solid #10b981';
fb.innerHTML = '&#10003; Верно!' + (explain ? ' ' + explain : '');
done.add(qDiv);
if(done.size === all.length && typeof onAllCorrect === 'function') onAllCorrect();
} else {
o.style.background = '#fee2e2'; o.style.borderColor = '#dc2626'; o.style.color = '#7f1d1d';
opts[correct].style.background = '#d1fae5'; opts[correct].style.borderColor = '#10b981'; opts[correct].style.color = '#065f46';
fb.style.display = 'block'; fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.innerHTML = '&#10007; Неверно. Правильно: «' + opts[correct].textContent + '».' + (explain ? ' ' + explain : '');
done.add(qDiv);
}
}));
});
}
/* ========================================================== */
/* §28 — Давление. Единицы давления */
/* ========================================================== */
function add_p28(){
const body = document.getElementById('p28-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Что такое давление', '§ 28.1',
'<b>Давление</b> $p$ — это сила, действующая на единицу площади опоры:<br>'
+ '$$p = \\dfrac{F}{S}$$<br>'
+ 'где $F$ — сила (Н), $S$ — площадь (м²). Единица — <b>паскаль</b>: $1$ Па $= 1$ Н/м².<br><br>'
+ 'Одно и то же тело может производить очень разное давление — всё зависит от <b>площади</b> опоры.');
h += makeCard('rule', 'Производные единицы', '§ 28.2',
'<ul style="padding-left:20px;margin:6px 0">'
+ '<li>$1$ кПа $= 1000$ Па</li>'
+ '<li>$1$ МПа $= 10^6$ Па</li>'
+ '<li>$1$ ГПа $= 10^9$ Па</li>'
+ '<li>$1$ Н/см² $= 10\\,000$ Па $= 10$ кПа</li>'
+ '</ul>');
h += makeCard('example', 'Гвоздь, тапок, трактор', '§ 28.3',
'<table style="width:100%;border-collapse:collapse;font-size:.92rem">'
+ '<tr style="background:' + ACCENT_SOFT + '"><th style="padding:6px 10px;text-align:left;border-bottom:2px solid ' + ACCENT + '">Объект</th><th style="padding:6px 10px;text-align:right;border-bottom:2px solid ' + ACCENT + '">F</th><th style="padding:6px 10px;text-align:right;border-bottom:2px solid ' + ACCENT + '">S</th><th style="padding:6px 10px;text-align:right;border-bottom:2px solid ' + ACCENT + '">p</th></tr>'
+ [
['Гвоздь под молотком',100,'0,1 мм² = 10⁻⁷ м²','10⁹ Па'],
['Балерина на пуанте',500,'1 см² = 10⁻⁴ м²','5 МПа'],
['Человек на двух ногах',700,'300 см² = 0,03 м²','23 кПа'],
['Лыжник',700,'0,25 м²','2,8 кПа'],
['Трактор (на гусеницах)',50000,'5 м²','10 кПа']
].map(r => '<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">' + r[0] + '</td><td style="padding:5px 10px;text-align:right;border-bottom:1px solid ' + ACCENT_SOFT + ';font-family:JetBrains Mono,monospace">' + r[1] + ' Н</td><td style="padding:5px 10px;text-align:right;border-bottom:1px solid ' + ACCENT_SOFT + ';font-family:JetBrains Mono,monospace;font-size:.82rem">' + r[2] + '</td><td style="padding:5px 10px;text-align:right;border-bottom:1px solid ' + ACCENT_SOFT + ';font-family:JetBrains Mono,monospace;font-weight:700">' + r[3] + '</td></tr>').join('')
+ '</table>'
+ '<p style="margin-top:8px;font-size:.86rem;color:#475569">Лыжник давит меньше, чем человек без лыж — поэтому не проваливается в снег.</p>');
/* IV-1 КАЛЬК p = F/S */
h += wgWrap('p28-iv1', 'КАЛЬК', 'Калькулятор давления', 'Меняй силу и площадь — увидь, как меняется давление.',
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Сила $F$, Н: <b id="p28-F" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">500</b><input type="range" id="p28-F-r" min="1" max="10000" step="1" value="500" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Площадь $S$, см²: <b id="p28-S" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">100</b><input type="range" id="p28-S-r" min="0.01" max="10000" step="0.01" value="100" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '</div>'
+ '<div style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.94rem;line-height:1.7">'
+ '$p = F/S = $ <b id="p28-p" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">50 000</b> Па $= $ <b id="p28-pkpa" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">50</b> кПа'
+ '<div id="p28-cmp" style="font-size:.84rem;color:#475569;margin-top:4px"></div>'
+ '</div>');
/* IV-2 СИМ: переключатель сценариев */
h += wgWrap('p28-iv2', 'СИМ', 'Один человек — разные ситуации', 'Один и тот же человек давит на грунт по-разному.',
'<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
+ [['boots','В ботинках'],['skis','На лыжах'],['stilet','На каблуке']].map((s, i) =>
'<button class="p28-sc" data-s="' + s[0] + '" type="button" style="background:' + (i===0 ? ACCENT : '#fff') + ';color:' + (i===0 ? '#fff' : ACCENT) + ';border:2px solid ' + ACCENT + ';padding:7px 14px;border-radius:9px;cursor:pointer;font-weight:700;font-family:inherit;font-size:.86rem">' + s[1] + '</button>').join('')
+ '</div>'
+ '<svg id="p28-sc-svg" viewBox="0 0 360 140" width="100%" style="max-width:500px;display:block;margin:0 auto;background:#fffbeb;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p28-sc-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;line-height:1.6"></div>');
/* IV-3 DnD */
h += wgWrap('p28-iv3', 'DnD', 'Кто давит сильнее (большее p)?', '',
dndPool('p28-dnd', [
{ id:'a1', cat:'low', html:'Танк на гусеницах' },
{ id:'a2', cat:'low', html:'Лыжник на снегу' },
{ id:'a3', cat:'mid', html:'Человек в ботинках' },
{ id:'a4', cat:'mid', html:'Стул на 4 ножках' },
{ id:'a5', cat:'high', html:'Балерина на пуанте' },
{ id:'a6', cat:'high', html:'Гвоздь под молотком' }
], [
{ cat:'low', label:'Малое (большая S)' },
{ cat:'mid', label:'Среднее' },
{ cat:'high', label:'Огромное (малая S)' }
]));
/* IV-4 ТРН */
h += wgWrap('p28-iv4', 'ТРН', 'Тренажёр §28', '',
'<div id="p28-tr-host">'
+ quizQuestion('p28-tr', 0, '$F = 200$ Н, $S = 0{,}1$ м². Давление $p$?', ['20 Па','200 Па','2000 Па','20 000 Па'], 2, '$p = 200/0{,}1 = 2000$ Па.')
+ quizQuestion('p28-tr', 1, 'Кирпич $F = 30$ Н стоит на $S = 100$ см² $= 0{,}01$ м². $p$?', ['300 Па','1500 Па','3000 Па','30 000 Па'], 2, '$p = 30/0{,}01 = 3000$ Па.')
+ quizQuestion('p28-tr', 2, 'Какой ответ верный? $1$ кПа $= ?$ Па', ['10','100','1000','10 000'], 2)
+ quizQuestion('p28-tr', 3, 'Чтобы уменьшить давление при той же силе, нужно…', ['Увеличить S','Уменьшить S','Уменьшить F','S не влияет'], 0, 'Из $p = F/S$: чем больше $S$, тем меньше $p$.')
+ quizQuestion('p28-tr', 4, 'Площадь $S = 5$ см², $p = 200$ кПа. Какова сила $F$?', ['1 Н','10 Н','100 Н','1000 Н'], 2, '$S = 5 \\cdot 10^{-4}$ м², $F = pS = 200\\,000 \\cdot 5 \\cdot 10^{-4} = 100$ Н.')
+ '</div>');
h += readButton('p28');
body.innerHTML = h;
// §28 IV-1
const upd28 = () => {
const F = +document.getElementById('p28-F-r').value;
const Scm = +document.getElementById('p28-S-r').value;
const S = Scm * 1e-4; // м²
document.getElementById('p28-F').textContent = F;
document.getElementById('p28-S').textContent = Scm;
const p = F / S;
document.getElementById('p28-p').textContent = p.toLocaleString('ru-RU', { maximumFractionDigits: 0 });
document.getElementById('p28-pkpa').textContent = (p / 1000).toFixed(2);
let cmp;
if(p < 1000) cmp = 'Очень малое — как давление гирь на резиновый коврик.';
else if(p < 10000) cmp = 'Похоже на лыжника на снегу.';
else if(p < 100000) cmp = 'Близко к давлению человека на полу.';
else if(p < 1e6) cmp = 'Балерина на пуанте, копыто лошади.';
else cmp = 'Огромное — как у гвоздя под молотком (≈ ГПа).';
document.getElementById('p28-cmp').textContent = cmp;
};
['p28-F-r','p28-S-r'].forEach(id => document.getElementById(id).addEventListener('input', upd28));
upd28();
// §28 IV-2 sims
const scenarios = {
boots: { S: 0.03, nm:'Ботинки на 2 ноги', cmp:'≈ давление человека (700 Н на 300 см²)' },
skis: { S: 0.25, nm:'Лыжи', cmp:'в ~8 раз меньше — не проваливается в снег' },
stilet: { S: 0.0001, nm:'Каблук-шпилька', cmp:'~ в 300 раз больше — повреждает паркет' }
};
function draw28(sc){
const W = 360, H = 140, baseY = 110;
let s = '';
s += '<rect x="0" y="' + baseY + '" width="' + W + '" height="30" fill="#94a3b8"/>';
for(let i = 0; i < 18; i++) s += '<line x1="' + (i*22+5) + '" y1="' + baseY + '" x2="' + (i*22+15) + '" y2="' + (baseY+8) + '" stroke="#374151" stroke-width="0.8"/>';
// Человек (упрощённо)
s += '<circle cx="180" cy="40" r="14" fill="#fbbf24" stroke="#0f172a" stroke-width="1.5"/>'; // голова
s += '<rect x="170" y="55" width="20" height="35" fill="#dc2626"/>';
// Опора (разная)
if(sc === 'boots'){
s += '<rect x="165" y="100" width="30" height="10" fill="#374151"/>';
s += '<text x="180" y="135" text-anchor="middle" font-size="10" fill="#0f172a" font-family="Inter,sans-serif">2 ботинка, S ≈ 300 см²</text>';
} else if(sc === 'skis'){
s += '<rect x="100" y="100" width="160" height="10" fill="#92400e" stroke="#0f172a" stroke-width="1"/>';
s += '<text x="180" y="135" text-anchor="middle" font-size="10" fill="#0f172a" font-family="Inter,sans-serif">2 лыжи, S ≈ 2500 см²</text>';
} else {
s += '<polygon points="178,100 182,100 180,108" fill="#374151"/>';
s += '<text x="180" y="135" text-anchor="middle" font-size="10" fill="#0f172a" font-family="Inter,sans-serif">2 пуанта, S ≈ 1 см²</text>';
}
// Сила
s += '<line x1="220" y1="50" x2="220" y2="98" stroke="#dc2626" stroke-width="2.5"/>';
s += '<polygon points="215,90 225,90 220,100" fill="#dc2626"/>';
s += '<text x="228" y="78" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#dc2626">F = 700 Н</text>';
document.getElementById('p28-sc-svg').innerHTML = s;
const d = scenarios[sc];
const p = 700 / d.S;
document.getElementById('p28-sc-info').innerHTML = '<b>' + d.nm + '</b>: $S = ' + d.S + '$ м², $p = F/S = ' + Math.round(p).toLocaleString('ru-RU') + '$ Па $\\approx ' + (p/1000).toFixed(1) + '$ кПа<br><span style="font-size:.84rem;color:#64748b">' + d.cmp + '</span>';
renderMath(document.getElementById('p28-sc-info'));
}
body.querySelectorAll('.p28-sc').forEach(btn => btn.addEventListener('click', () => {
body.querySelectorAll('.p28-sc').forEach(b => { b.style.background = '#fff'; b.style.color = ACCENT; });
btn.style.background = ACCENT; btn.style.color = '#fff';
draw28(btn.dataset.s);
}));
draw28('boots');
wireDnd('p28-dnd', [
{ id:'a1', cat:'low' },{ id:'a2', cat:'low' },{ id:'a3', cat:'mid' },
{ id:'a4', cat:'mid' },{ id:'a5', cat:'high' },{ id:'a6', cat:'high' }
]);
wireQuiz('p28-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p28'); });
wireReadBtn('p28');
renderMath(body);
}
/* ========================================================== */
/* §29 — Давление газа */
/* ========================================================== */
function add_p29(){
const body = document.getElementById('p29-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Откуда давление у газа', '§ 29.1',
'Молекулы газа постоянно <b>бьются о стенки</b> сосуда. Каждый удар — крошечная сила. '
+ 'Сумма всех ударов делится на площадь стенки — получается <b>давление газа</b>.<br><br>'
+ 'У газа нет собственной формы и фиксированного объёма, поэтому давление возникает <b>равномерно во все стороны</b>.');
h += makeCard('rule', 'Что увеличивает p газа', '§ 29.2',
'Давление газа растёт, если:'
+ '<ul style="padding-left:20px;margin:5px 0">'
+ '<li><b>Увеличить $T$</b> — молекулы быстрее, удары сильнее.</li>'
+ '<li><b>Уменьшить $V$</b> — то же число молекул на меньшей площади.</li>'
+ '<li><b>Добавить молекул</b> (накачать) — больше ударов в секунду.</li>'
+ '</ul>');
h += makeCard('example', 'Шарик и шина', '§ 29.3',
'<b>Воздушный шарик</b>: накачиваем (добавляем молекулы) → $p$ растёт → шарик расширяется, '
+ 'пока упругость резины не уравновесит давление.<br><br>'
+ '<b>Шина машины</b>: летом нагревается на солнце → $T$ растёт → $p$ растёт. '
+ 'Поэтому летом давление в шинах выше, чем зимой.');
/* IV-1 СИМ */
h += wgWrap('p29-iv1', 'СИМ', 'Молекулы газа в сосуде', 'Меняй число молекул и скорость — увидь, как меняется частота ударов.',
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Число молекул: <b id="p29-N" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">30</b><input type="range" id="p29-N-r" min="5" max="80" step="1" value="30" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Температура $T$, отн. ед.: <b id="p29-T" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">2</b><input type="range" id="p29-T-r" min="1" max="5" step="0.5" value="2" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '</div>'
+ '<svg id="p29-svg" viewBox="0 0 360 200" width="100%" style="max-width:500px;display:block;margin:0 auto;background:#fffbeb;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p29-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;text-align:center"></div>');
/* IV-2 КВИЗ */
h += wgWrap('p29-iv2', 'КВИЗ', 'Давление газа', '',
'<div id="p29-q-host">'
+ quizQuestion('p29-q', 0, 'Что создаёт давление газа на стенки сосуда?', ['Сила тяжести','Удары молекул о стенки','Поверхностное натяжение','Магнитное поле'], 1)
+ quizQuestion('p29-q', 1, 'Если нагреть газ в закрытом сосуде, давление…', ['Не изменится','Уменьшится','Увеличится','Станет нулевым'], 2)
+ quizQuestion('p29-q', 2, 'Если сжать газ (уменьшить $V$) при той же температуре, $p$…', ['Уменьшится','Увеличится','Не изменится','Зависит от массы'], 1)
+ quizQuestion('p29-q', 3, 'В какую сторону газ давит на стенки сосуда?', ['Только вниз','Только вверх','Равномерно во все стороны','Только в одну сторону'], 2)
+ '</div>');
/* IV-3 DnD */
h += wgWrap('p29-iv3', 'DnD', 'p газа: больше или меньше?', '',
dndPool('p29-dnd', [
{ id:'a1', cat:'up', html:'Накачали колесо насосом' },
{ id:'a2', cat:'up', html:'Шар на солнце летом' },
{ id:'a3', cat:'up', html:'Сжали шприц поршнем' },
{ id:'a4', cat:'down', html:'Газ остыл' },
{ id:'a5', cat:'down', html:'Выпустили часть воздуха' },
{ id:'a6', cat:'down', html:'Расширили сосуд' }
], [
{ cat:'up', label:'p растёт' },
{ cat:'down', label:'p падает' }
]));
/* IV-4 ТРН */
h += wgWrap('p29-iv4', 'ТРН', 'Тренажёр §29', '',
'<div id="p29-tr-host">'
+ quizQuestion('p29-tr', 0, 'Газ в закрытом цилиндре охладили. С давлением:', ['Растёт','Падает','Не меняется','Становится 0'], 1)
+ quizQuestion('p29-tr', 1, 'Где давление газа выше: в надутом мяче или в спущенном?', ['В спущенном','В надутом','Одинаково','Зависит от веса'], 1)
+ quizQuestion('p29-tr', 2, 'В баллоне с гелием давление $p$. Если вытащить половину гелия (молекул в 2 раза меньше) при той же $T$ и $V$, $p$ станет…', ['В 2 раза больше','В 2 раза меньше','Тем же','Нулевым'], 1)
+ quizQuestion('p29-tr', 3, 'Что произойдёт с шариком в очень холодильнике?', ['Лопнет','Сожмётся (давление упадёт, форма уменьшится)','Не изменится','Улетит'], 1)
+ '</div>');
h += readButton('p29');
body.innerHTML = h;
// §29 IV-1 sim
const p29 = { parts: [], raf: 0 };
function init29(){
const N = +document.getElementById('p29-N-r').value;
const T = +document.getElementById('p29-T-r').value;
p29.parts = [];
for(let i = 0; i < N; i++){
const ang = Math.random() * Math.PI * 2;
const sp = (0.8 + Math.random() * 0.4) * T;
p29.parts.push({
x: 20 + Math.random() * 320,
y: 20 + Math.random() * 160,
vx: Math.cos(ang) * sp,
vy: Math.sin(ang) * sp
});
}
}
function step29(){
let hits = 0;
p29.parts.forEach(p => {
p.x += p.vx; p.y += p.vy;
if(p.x < 6){ p.x = 6; p.vx = -p.vx; hits++; }
if(p.x > 354){ p.x = 354; p.vx = -p.vx; hits++; }
if(p.y < 6){ p.y = 6; p.vy = -p.vy; hits++; }
if(p.y > 194){ p.y = 194; p.vy = -p.vy; hits++; }
});
return hits;
}
let frame29 = 0, hitSum = 0;
function render29(){
const svg = document.getElementById('p29-svg');
if(!svg){ cancelAnimationFrame(p29.raf); return; }
const hits = step29();
hitSum += hits;
frame29++;
let s = '';
s += '<rect x="3" y="3" width="354" height="194" fill="none" stroke="' + ACCENT_D + '" stroke-width="2"/>';
p29.parts.forEach(p => {
const sp = Math.hypot(p.vx, p.vy);
const col = sp > 2 ? '#dc2626' : (sp > 1.2 ? '#d97706' : '#0284c7');
s += '<circle cx="' + p.x.toFixed(1) + '" cy="' + p.y.toFixed(1) + '" r="3.5" fill="' + col + '"/>';
});
svg.innerHTML = s;
if(frame29 % 30 === 0){
const avg = (hitSum / 30).toFixed(0);
document.getElementById('p29-info').innerHTML = 'Молекул: <b>' + p29.parts.length + '</b> &middot; ударов о стенки за такт: <b>' + avg + '</b> &middot; Давление $p$ <b>тем выше</b>, чем больше число молекул × их скорость.';
renderMath(document.getElementById('p29-info'));
hitSum = 0;
}
p29.raf = requestAnimationFrame(render29);
}
['p29-N-r','p29-T-r'].forEach(id => document.getElementById(id).addEventListener('input', () => {
document.getElementById('p29-N').textContent = document.getElementById('p29-N-r').value;
document.getElementById('p29-T').textContent = document.getElementById('p29-T-r').value;
init29();
}));
init29();
p29.raf = requestAnimationFrame(render29);
wireDnd('p29-dnd', [
{ id:'a1', cat:'up' },{ id:'a2', cat:'up' },{ id:'a3', cat:'up' },
{ id:'a4', cat:'down' },{ id:'a5', cat:'down' },{ id:'a6', cat:'down' }
]);
wireQuiz('p29-q-host', () => { if(window.addXp) window.addXp(10, 'q-p29'); });
wireQuiz('p29-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p29'); });
wireReadBtn('p29');
renderMath(body);
}
/* ========================================================== */
/* §30 — Закон Паскаля. Гидравлический пресс */
/* ========================================================== */
function add_p30(){
const body = document.getElementById('p30-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Закон Паскаля', '§ 30.1',
'Давление, производимое на жидкость или газ, передаётся <b>без изменения</b> в каждую точку '
+ 'этой жидкости или газа и <b>во все стороны одинаково</b>.<br><br>'
+ 'Это открыл Блез Паскаль в XVII веке. Поэтому если надуть воздушный шарик и сжать его в одном месте — '
+ 'он раздуется в другом, передавая давление равномерно.');
h += makeCard('rule', 'Гидравлический пресс', '§ 30.2',
'Соединим два цилиндра жидкостью. На малый поршень давит сила $F_1$ — возникает давление $p = F_1/S_1$. '
+ 'Это давление передаётся по жидкости к большому поршню площадью $S_2$:<br>'
+ '$$F_2 = p \\cdot S_2 = F_1 \\cdot \\dfrac{S_2}{S_1}$$<br>'
+ '<b>Если $S_2 \\gg S_1$</b>, то $F_2 \\gg F_1$ — гидравлика <b>выигрывает в силе</b>. '
+ 'Платой служит то, что большой поршень движется во столько же раз медленнее.');
h += makeCard('example', 'Где применяют', '§ 30.3',
'<ul style="padding-left:20px;margin:5px 0">'
+ '<li><b>Гидравлический пресс</b> — гнёт металл, прессует тюки.</li>'
+ '<li><b>Гидравлический подъёмник</b> в автосервисе.</li>'
+ '<li><b>Тормоза</b> легкового авто — нажатие на педаль передаётся жидкости.</li>'
+ '<li><b>Экскаватор, ковш бульдозера</b> — цилиндры с маслом.</li>'
+ '</ul>');
/* IV-1 ГЛАВНЫЙ ВИЗУАЛ — гидравлический пресс */
h += wgWrap('p30-iv1', 'СИМ', 'Гидравлический пресс — главный визуал', 'Меняй площади и силу на малом поршне — увидь силу на большом.',
'<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:7px 11px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">$S_1$, см²: <b id="p30-S1" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">2</b><input type="range" id="p30-S1-r" min="1" max="50" step="1" value="2" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:7px 11px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">$S_2$, см²: <b id="p30-S2" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">200</b><input type="range" id="p30-S2-r" min="10" max="500" step="5" value="200" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:7px 11px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">$F_1$, Н: <b id="p30-F1" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">50</b><input type="range" id="p30-F1-r" min="1" max="500" step="1" value="50" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '</div>'
+ '<svg id="p30-svg" viewBox="0 0 320 200" width="100%" style="max-width:500px;display:block;margin:0 auto;background:#fffbeb;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p30-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.94rem;line-height:1.65"></div>');
/* IV-2 КАЛЬК */
h += wgWrap('p30-iv2', 'КАЛЬК', 'F₂ через закон Паскаля', '',
'<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">$F_1$, Н: <b id="p30c-F1" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">100</b><input type="range" id="p30c-F1-r" min="1" max="1000" step="1" value="100" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">$S_1$: <b id="p30c-S1" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">5</b><input type="range" id="p30c-S1-r" min="1" max="100" step="1" value="5" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">$S_2$: <b id="p30c-S2" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">500</b><input type="range" id="p30c-S2-r" min="10" max="2000" step="10" value="500" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '</div>'
+ '<div style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.94rem;line-height:1.7">'
+ '$p = F_1/S_1 = $ <b id="p30c-p" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">20</b> Н/см² &middot; $F_2 = pS_2 = F_1 \\cdot S_2/S_1 = $ <b id="p30c-F2" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">10000</b> Н'
+ '<div id="p30c-gain" style="font-size:.84rem;color:#475569;margin-top:5px">Выигрыш в силе: <b style="color:#10b981">в 100 раз</b></div>'
+ '</div>');
/* IV-3 DnD */
h += wgWrap('p30-iv3', 'DnD', 'Применения закона Паскаля', '',
dndPool('p30-dnd', [
{ id:'a1', cat:'hyd', html:'Гидравлический пресс' },
{ id:'a2', cat:'hyd', html:'Автомобильный подъёмник' },
{ id:'a3', cat:'hyd', html:'Тормоза машины' },
{ id:'a4', cat:'not', html:'Звонок в дверь' },
{ id:'a5', cat:'not', html:'Лампа накаливания' },
{ id:'a6', cat:'hyd', html:'Ковш бульдозера' }
], [
{ cat:'hyd', label:'Использует закон Паскаля' },
{ cat:'not', label:'Не относится' }
]));
/* IV-4 ТРН */
h += wgWrap('p30-iv4', 'ТРН', 'Тренажёр §30', '',
'<div id="p30-tr-host">'
+ quizQuestion('p30-tr', 0, '$F_1 = 50$ Н, $S_1 = 5$ см², $S_2 = 50$ см². $F_2$?', ['100 Н','250 Н','500 Н','5000 Н'], 2, '$F_2 = 50 \\cdot 50/5 = 500$ Н.')
+ quizQuestion('p30-tr', 1, 'Если $S_2/S_1 = 100$, во сколько раз увеличится сила?', ['В 10','В 100','В 1000','Не изменится'], 1)
+ quizQuestion('p30-tr', 2, 'Что является «платой» за выигрыш в силе у гидравлики?', ['Расход воды','Большой поршень движется медленнее','Жидкость греется','Ничего'], 1)
+ quizQuestion('p30-tr', 3, 'Жидкости и газы передают давление…', ['Только вниз','Только вверх','Равномерно во все стороны','По-разному в разных точках'], 2)
+ '</div>');
h += readButton('p30');
body.innerHTML = h;
function draw30(){
const S1 = +document.getElementById('p30-S1-r').value;
const S2 = +document.getElementById('p30-S2-r').value;
const F1 = +document.getElementById('p30-F1-r').value;
document.getElementById('p30-S1').textContent = S1;
document.getElementById('p30-S2').textContent = S2;
document.getElementById('p30-F1').textContent = F1;
const F2 = F1 * S2 / S1;
// Render via PHYS.hydraulicPress if available
if(window.PHYS && window.PHYS.hydraulicPress){
const svgInner = window.PHYS.hydraulicPress(40, 30, S1, S2, F1, '#60a5fa');
document.getElementById('p30-svg').innerHTML = svgInner;
}
document.getElementById('p30-info').innerHTML = '$F_1 = ' + F1 + '$ Н, $S_1 = ' + S1 + '$ см², $S_2 = ' + S2 + '$ см² &nbsp;→&nbsp; $F_2 = F_1 \\cdot S_2/S_1 = $ <b>' + F2.toFixed(0) + '</b> Н <span style="color:#10b981;font-weight:700">(в ' + (S2/S1).toFixed(1) + ' раз больше)</span>';
renderMath(document.getElementById('p30-info'));
}
['p30-S1-r','p30-S2-r','p30-F1-r'].forEach(id => document.getElementById(id).addEventListener('input', draw30));
draw30();
const upd30c = () => {
const F1 = +document.getElementById('p30c-F1-r').value;
const S1 = +document.getElementById('p30c-S1-r').value;
const S2 = +document.getElementById('p30c-S2-r').value;
document.getElementById('p30c-F1').textContent = F1;
document.getElementById('p30c-S1').textContent = S1;
document.getElementById('p30c-S2').textContent = S2;
const p = F1 / S1;
const F2 = p * S2;
document.getElementById('p30c-p').textContent = p.toFixed(1);
document.getElementById('p30c-F2').textContent = F2.toFixed(0);
document.getElementById('p30c-gain').innerHTML = 'Выигрыш в силе: <b style="color:#10b981">в ' + (S2/S1).toFixed(1) + ' раз</b>';
};
['p30c-F1-r','p30c-S1-r','p30c-S2-r'].forEach(id => document.getElementById(id).addEventListener('input', upd30c));
upd30c();
wireDnd('p30-dnd', [
{ id:'a1', cat:'hyd' },{ id:'a2', cat:'hyd' },{ id:'a3', cat:'hyd' },
{ id:'a4', cat:'not' },{ id:'a5', cat:'not' },{ id:'a6', cat:'hyd' }
]);
wireQuiz('p30-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p30'); });
wireReadBtn('p30');
renderMath(body);
}
/* ========================================================== */
/* §31 — Давление жидкости (гидростатическое) */
/* ========================================================== */
function add_p31(){
const body = document.getElementById('p31-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Жидкость давит весом', '§ 31.1',
'Жидкость, имеющая массу, давит на дно сосуда и на боковые стенки. '
+ 'Это давление возникает <b>не от тела</b>, как у твёрдых, а от <b>собственного веса жидкости</b>.<br><br>'
+ 'Формула гидростатического давления на глубине $h$:<br>'
+ '$$p = \\rho g h$$<br>'
+ 'где $\\rho$ — плотность жидкости (кг/м³), $g \\approx 9{,}8$ Н/кг, $h$ — глубина (м).');
h += makeCard('rule', 'Гидростатический парадокс', '§ 31.2',
'<b>Удивительный факт:</b> давление на дно <b>не зависит</b> от формы сосуда и от количества жидкости. '
+ 'Если налить $h$ воды в узкую трубку или в широкий бассейн — давление на дно <b>одинаково</b>.<br><br>'
+ 'Зависит только от: плотности жидкости и глубины. Это <b>гидростатический парадокс</b> Паскаля.');
h += makeCard('example', 'Давление на глубине', '§ 31.3',
'<table style="width:100%;border-collapse:collapse;font-size:.92rem">'
+ '<tr style="background:' + ACCENT_SOFT + '"><th style="padding:6px 10px;text-align:left;border-bottom:2px solid ' + ACCENT + '">Глубина</th><th style="padding:6px 10px;text-align:right;border-bottom:2px solid ' + ACCENT + '">p (вода)</th></tr>'
+ [['$1$ м','9,8 кПа'],['$10$ м','98 кПа ≈ 1 атм'],['$100$ м','≈ 10 атм'],['$1000$ м','≈ 100 атм (батискаф)'],['Дно Марианской впадины ($\\approx 11$ км)','≈ 1100 атм']].map(r =>
'<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">' + r[0] + '</td><td style="padding:5px 10px;text-align:right;border-bottom:1px solid ' + ACCENT_SOFT + ';font-family:JetBrains Mono,monospace;font-weight:700">' + r[1] + '</td></tr>').join('')
+ '</table>');
/* IV-1 КАЛЬК */
h += wgWrap('p31-iv1', 'КАЛЬК', 'Калькулятор $p = \\rho g h$', 'Меняй плотность и глубину.',
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Жидкость:<select id="p31-rho" style="width:100%;margin-top:6px;padding:6px;border-radius:6px;border:1px solid ' + ACCENT_SOFT + ';font-family:inherit"><option value="1000" selected>Вода (1000 кг/м³)</option><option value="800">Бензин (800)</option><option value="1030">Морская вода (1030)</option><option value="13600">Ртуть (13600)</option><option value="900">Спирт (900)</option></select></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Глубина $h$, м: <b id="p31-h" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">3</b><input type="range" id="p31-h-r" min="0.1" max="100" step="0.1" value="3" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '</div>'
+ '<div style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.94rem;line-height:1.65">'
+ '$p = \\rho g h = $ <b id="p31-p" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">29 400</b> Па $= $ <b id="p31-pkpa" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">29.4</b> кПа $\\approx $ <b id="p31-patm" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">0.29</b> атм'
+ '</div>');
/* IV-2 СИМ: гидростатический парадокс — 3 сосуда */
h += wgWrap('p31-iv2', 'СИМ', 'Гидростатический парадокс: 3 сосуда', 'Один уровень воды — одинаковое давление на дно. Форма не важна!',
'<svg id="p31-svg" viewBox="0 0 360 200" width="100%" style="max-width:500px;display:block;margin:0 auto;background:#fffbeb;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div style="margin-top:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Уровень воды, см: <b id="p31s-h" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">10</b><input type="range" id="p31s-h-r" min="2" max="15" step="1" value="10" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<div id="p31s-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;text-align:center"></div>');
/* IV-3 DnD */
h += wgWrap('p31-iv3', 'DnD', 'От чего зависит p жидкости?', '',
dndPool('p31-dnd', [
{ id:'a1', cat:'yes', html:'Глубина $h$' },
{ id:'a2', cat:'yes', html:'Плотность жидкости $\\rho$' },
{ id:'a3', cat:'yes', html:'Ускорение $g$' },
{ id:'a4', cat:'no', html:'Форма сосуда' },
{ id:'a5', cat:'no', html:'Количество жидкости в сосуде' },
{ id:'a6', cat:'no', html:'Площадь дна' }
], [
{ cat:'yes', label:'p ЗАВИСИТ' },
{ cat:'no', label:'p НЕ зависит' }
]));
/* IV-4 ТРН */
h += wgWrap('p31-iv4', 'ТРН', 'Тренажёр §31', '',
'<div id="p31-tr-host">'
+ quizQuestion('p31-tr', 0, 'Давление воды на дне бассейна глубиной $5$ м ($g = 10$, $\\rho = 1000$)?', ['5 кПа','50 кПа','500 кПа','5000 кПа'], 1, '$p = 1000 \\cdot 10 \\cdot 5 = 50\\,000$ Па $= 50$ кПа.')
+ quizQuestion('p31-tr', 1, 'Жидкость глубиной $h = 2$ м, $\\rho = 800$ кг/м³ (бензин). $p$ (g=10)?', ['8 кПа','16 кПа','80 кПа','160 кПа'], 1, '$p = 800 \\cdot 10 \\cdot 2 = 16\\,000$ Па.')
+ quizQuestion('p31-tr', 2, 'В двух разных сосудах вода на одной глубине $h = 1$ м. Где $p$ больше?', ['В большом','В малом','Одинаковое','Зависит от формы'], 2)
+ quizQuestion('p31-tr', 3, 'В каком случае давление на дно больше: $1$ м воды или $1$ м ртути ($\\rho_{рт} = 13600$)?', ['Воды','Ртути','Одинаково','Воды в 13,6 раз'], 1)
+ quizQuestion('p31-tr', 4, 'Дайвер на $h = 30$ м в море ($\\rho = 1030$). Гидростат. давление?', ['3 атм','5 атм','3,1 атм','30 атм'], 2, '$p = 1030 \\cdot 9{,}8 \\cdot 30 \\approx 303\\,000$ Па $\\approx 3$ атм.')
+ '</div>');
h += readButton('p31');
body.innerHTML = h;
// §31 IV-1
const upd31 = () => {
const rho = +document.getElementById('p31-rho').value;
const hVal = +document.getElementById('p31-h-r').value;
document.getElementById('p31-h').textContent = hVal;
const p = rho * 9.8 * hVal;
document.getElementById('p31-p').textContent = p.toLocaleString('ru-RU', { maximumFractionDigits: 0 });
document.getElementById('p31-pkpa').textContent = (p / 1000).toFixed(2);
document.getElementById('p31-patm').textContent = (p / 101325).toFixed(3);
};
document.getElementById('p31-rho').addEventListener('change', upd31);
document.getElementById('p31-h-r').addEventListener('input', upd31);
upd31();
// §31 IV-2 — paradox
function draw31s(){
const hCm = +document.getElementById('p31s-h-r').value;
document.getElementById('p31s-h').textContent = hCm;
const W = 360, H = 200, baseY = 170, pxPerCm = 9;
const liqColor = '#60a5fa';
let s = '';
// Дно
s += '<rect x="20" y="' + baseY + '" width="320" height="10" fill="#475569"/>';
function vessel(x, w, kind){
const wallH = 130;
const topY = baseY - wallH;
let g = '';
if(kind === 'cyl'){
g += '<line x1="' + x + '" y1="' + topY + '" x2="' + x + '" y2="' + baseY + '" stroke="#0f172a" stroke-width="2"/>';
g += '<line x1="' + (x+w) + '" y1="' + topY + '" x2="' + (x+w) + '" y2="' + baseY + '" stroke="#0f172a" stroke-width="2"/>';
// Жидкость
const fillH = hCm * pxPerCm;
g += '<rect x="' + (x+1) + '" y="' + (baseY - fillH) + '" width="' + (w-2) + '" height="' + fillH + '" fill="' + liqColor + '" opacity="0.7"/>';
} else if(kind === 'wide'){
// Конус расширяющийся вверх
g += '<line x1="' + (x+5) + '" y1="' + topY + '" x2="' + x + '" y2="' + baseY + '" stroke="#0f172a" stroke-width="2"/>';
g += '<line x1="' + (x+w-5) + '" y1="' + topY + '" x2="' + (x+w) + '" y2="' + baseY + '" stroke="#0f172a" stroke-width="2"/>';
const fillH = hCm * pxPerCm;
g += '<polygon points="' + (x+1) + ',' + baseY + ' ' + (x+w-1) + ',' + baseY + ' ' + (x+w-1-fillH*0.05) + ',' + (baseY-fillH) + ' ' + (x+1+fillH*0.05) + ',' + (baseY-fillH) + '" fill="' + liqColor + '" opacity="0.7"/>';
} else { // narrow — сужающийся
g += '<line x1="' + x + '" y1="' + topY + '" x2="' + (x+10) + '" y2="' + baseY + '" stroke="#0f172a" stroke-width="2"/>';
g += '<line x1="' + (x+w) + '" y1="' + topY + '" x2="' + (x+w-10) + '" y2="' + baseY + '" stroke="#0f172a" stroke-width="2"/>';
const fillH = hCm * pxPerCm;
g += '<polygon points="' + (x+10) + ',' + baseY + ' ' + (x+w-10) + ',' + baseY + ' ' + (x+w-10-fillH*0.05) + ',' + (baseY-fillH) + ' ' + (x+10+fillH*0.05) + ',' + (baseY-fillH) + '" fill="' + liqColor + '" opacity="0.7"/>';
}
return g;
}
s += vessel(40, 60, 'cyl');
s += vessel(150, 60, 'wide');
s += vessel(260, 60, 'narrow');
// Линия уровня
const lvlY = baseY - hCm * pxPerCm;
s += '<line x1="20" y1="' + lvlY + '" x2="340" y2="' + lvlY + '" stroke="#dc2626" stroke-width="1.5" stroke-dasharray="4 3"/>';
s += '<text x="20" y="' + (lvlY-3) + '" font-family="Inter,sans-serif" font-size="10" font-weight="700" fill="#dc2626">уровень = ' + hCm + ' см</text>';
document.getElementById('p31-svg').innerHTML = s;
const p = 1000 * 9.8 * (hCm / 100);
document.getElementById('p31s-info').innerHTML = 'На дне всех трёх сосудов: <b>$p = \\rho g h = ' + Math.round(p).toLocaleString('ru-RU') + '$ Па</b>. Форма не важна!';
renderMath(document.getElementById('p31s-info'));
}
document.getElementById('p31s-h-r').addEventListener('input', draw31s);
draw31s();
wireDnd('p31-dnd', [
{ id:'a1', cat:'yes' },{ id:'a2', cat:'yes' },{ id:'a3', cat:'yes' },
{ id:'a4', cat:'no' },{ id:'a5', cat:'no' },{ id:'a6', cat:'no' }
]);
wireQuiz('p31-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p31'); });
wireReadBtn('p31');
renderMath(body);
}
/* ========================================================== */
/* §32 — Сообщающиеся сосуды */
/* ========================================================== */
function add_p32(){
const body = document.getElementById('p32-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Что это такое', '§ 32.1',
'<b>Сообщающиеся сосуды</b> — это два или несколько сосудов, соединённых внизу так, что жидкость может переходить между ними.<br><br>'
+ '<b>Главный закон:</b> в сообщающихся сосудах <b>однородная</b> жидкость устанавливается на <b>одном уровне</b> — независимо от формы сосудов.');
h += makeCard('rule', 'Почему именно так', '§ 32.2',
'На одной глубине давление одно и то же ($p = \\rho g h$). Если уровни жидкости разные, то и давления у дна разные, '
+ 'и жидкость будет перетекать в сторону <b>меньшего</b> давления — пока уровни не сравняются.<br><br>'
+ 'Для <b>разнородных</b> жидкостей: высоты в коленах <b>обратно пропорциональны плотностям</b>: '
+ '$\\rho_1 h_1 = \\rho_2 h_2$.');
h += makeCard('example', 'Применения', '§ 32.3',
'<ul style="padding-left:20px;margin:5px 0">'
+ '<li><b>Водопровод</b> в высотных домах — давление от водонапорной башни.</li>'
+ '<li><b>Шлюзы</b> для пропуска судов.</li>'
+ '<li><b>Чайник с носиком</b>: чай в чайнике и в носике на одном уровне.</li>'
+ '<li><b>Кофейник, лейка</b>.</li>'
+ '<li><b>Артезианские колодцы</b>: вода поднимается естественным образом.</li>'
+ '</ul>');
/* IV-1 СИМ: сообщающиеся сосуды */
h += wgWrap('p32-iv1', 'СИМ', 'Однородная жидкость → один уровень', 'Меняй уровень — оба сосуда уравниваются.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Уровень воды, px: <b id="p32-l" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">100</b><input type="range" id="p32-l-r" min="40" max="160" step="2" value="100" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
+ '<button class="p32-shape" data-a="cylinder" data-b="cylinder" type="button" style="background:' + ACCENT + ';color:#fff;border:none;padding:7px 14px;border-radius:9px;cursor:pointer;font-weight:700;font-family:inherit;font-size:.84rem">Два цилиндра</button>'
+ '<button class="p32-shape" data-a="cylinder" data-b="wide" type="button" style="background:#fff;color:' + ACCENT + ';border:2px solid ' + ACCENT + ';padding:7px 14px;border-radius:9px;cursor:pointer;font-weight:700;font-family:inherit;font-size:.84rem">Цилиндр + широкий</button>'
+ '<button class="p32-shape" data-a="narrow" data-b="wide" type="button" style="background:#fff;color:' + ACCENT + ';border:2px solid ' + ACCENT + ';padding:7px 14px;border-radius:9px;cursor:pointer;font-weight:700;font-family:inherit;font-size:.84rem">Узкий + широкий</button>'
+ '</div>'
+ '<svg id="p32-svg" viewBox="0 0 320 200" width="100%" style="max-width:500px;display:block;margin:0 auto;background:#fffbeb;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p32-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;text-align:center">Уровень одинаков, потому что давления на дне равны.</div>');
/* IV-2 КВИЗ */
h += wgWrap('p32-iv2', 'КВИЗ', 'Сообщающиеся сосуды', '',
'<div id="p32-q-host">'
+ quizQuestion('p32-q', 0, 'В двух соединённых сосудах одна и та же вода. Что верно?', ['Уровни могут быть разными','Уровни всегда одинаковы','Зависит от объёмов','Зависит от формы'], 1)
+ quizQuestion('p32-q', 1, 'Чайник: уровень чая в носике и корпусе…', ['В носике выше','В корпусе выше','На одном уровне','Зависит от наклона'], 2)
+ quizQuestion('p32-q', 2, 'Если жидкости разные (вода и масло), уровни…', ['Одинаковые','Зависят от плотностей (обратно пропорц.)','Зависят от массы','Жидкость смешается'], 1)
+ '</div>');
/* IV-3 DnD */
h += wgWrap('p32-iv3', 'DnD', 'Что использует сообщающиеся сосуды?', '',
dndPool('p32-dnd', [
{ id:'a1', cat:'yes', html:'Шлюз для судов' },
{ id:'a2', cat:'yes', html:'Лейка для воды' },
{ id:'a3', cat:'yes', html:'Водомерное стекло котла' },
{ id:'a4', cat:'no', html:'Микроволновка' },
{ id:'a5', cat:'no', html:'Электронные весы' },
{ id:'a6', cat:'yes', html:'Артезианский колодец' }
], [
{ cat:'yes', label:'Применение принципа' },
{ cat:'no', label:'Не относится' }
]));
/* IV-4 ТРН */
h += wgWrap('p32-iv4', 'ТРН', 'Тренажёр §32', '',
'<div id="p32-tr-host">'
+ quizQuestion('p32-tr', 0, 'В сообщающиеся сосуды налита однородная вода. Если в одном уровень $h$, то во втором…', ['$h/2$','$h$','$2h$','Любой'], 1)
+ quizQuestion('p32-tr', 1, 'Если узкий сосуд тоньше широкого в 5 раз, а вода поднимается в широком на $10$ см, то в узком…', ['10 см','50 см','5 см','100 см'], 0, 'Уровни одной жидкости равны независимо от площади.')
+ quizQuestion('p32-tr', 2, 'В U-трубке с двух сторон ртуть. Налили воду — она «выдавила» ртуть. В каком колене ртуть выше?', ['Где налита вода','В противоположном','Одинаково','Ртуть выльется'], 1)
+ quizQuestion('p32-tr', 3, 'Принцип сообщающихся сосудов работает потому, что…', ['Жидкость лёгкая','Давление зависит только от $h$ и $\\rho$','Жидкость холодная','Стенки гладкие'], 1)
+ '</div>');
h += readButton('p32');
body.innerHTML = h;
// §32 IV-1
let curShape = { a:'cylinder', b:'cylinder' };
function draw32(){
const lvlY = 220 - +document.getElementById('p32-l-r').value; // px (220 — низ + base)
// На самом деле проще задать levelY напрямую от верха svg
const Lpx = +document.getElementById('p32-l-r').value;
document.getElementById('p32-l').textContent = Lpx;
if(window.PHYS && window.PHYS.connectedVessels){
const levelY = 200 - Lpx; // viewBox 200H, уровень от низа
const svgInner = window.PHYS.connectedVessels(50, 30, curShape.a, curShape.b, levelY, '#60a5fa');
document.getElementById('p32-svg').innerHTML = svgInner;
}
}
body.querySelectorAll('.p32-shape').forEach(btn => btn.addEventListener('click', () => {
body.querySelectorAll('.p32-shape').forEach(b => { b.style.background = '#fff'; b.style.color = ACCENT; b.style.border = '2px solid ' + ACCENT; });
btn.style.background = ACCENT; btn.style.color = '#fff'; btn.style.border = 'none';
curShape = { a: btn.dataset.a, b: btn.dataset.b };
draw32();
}));
document.getElementById('p32-l-r').addEventListener('input', draw32);
draw32();
wireDnd('p32-dnd', [
{ id:'a1', cat:'yes' },{ id:'a2', cat:'yes' },{ id:'a3', cat:'yes' },
{ id:'a4', cat:'no' },{ id:'a5', cat:'no' },{ id:'a6', cat:'yes' }
]);
wireQuiz('p32-q-host', () => { if(window.addXp) window.addXp(10, 'q-p32'); });
wireQuiz('p32-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p32'); });
wireReadBtn('p32');
renderMath(body);
}
/* ========================================================== */
/* §33 — Газы и их вес */
/* ========================================================== */
function add_p33(){
const body = document.getElementById('p33-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'У воздуха есть вес', '§ 33.1',
'Любой газ состоит из молекул, у молекул есть масса — значит, и сам газ имеет <b>массу</b> и <b>вес</b>.<br><br>'
+ 'Плотность воздуха у поверхности Земли: $\\rho_{возд} \\approx 1{,}29$ кг/м³.');
h += makeCard('rule', 'Сколько весит воздух', '§ 33.2',
'Масса газа в сосуде: $m = \\rho V$.<br>'
+ 'Вес: $P = m g$.<br><br>'
+ 'Воздух в комнате $5 \\times 4 \\times 3$ м$^3 = 60$ м³ имеет массу $m \\approx 1{,}29 \\cdot 60 = 77$ кг — '
+ 'столько весит взрослый человек!');
h += makeCard('example', 'Как доказать вес воздуха', '§ 33.3',
'<b>Опыт:</b> взвесить стеклянный шар на чувствительных весах, затем выкачать из него воздух насосом '
+ 'и взвесить снова. Шар без воздуха окажется <b>легче</b> на массу удалённого воздуха.');
/* IV-1 КАЛЬК: масса воздуха в комнате */
h += wgWrap('p33-iv1', 'КАЛЬК', 'Сколько весит воздух в комнате?', '',
'<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Длина $a$, м: <b id="p33-a" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">5</b><input type="range" id="p33-a-r" min="2" max="20" step="0.5" value="5" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Ширина $b$, м: <b id="p33-b" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">4</b><input type="range" id="p33-b-r" min="2" max="20" step="0.5" value="4" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Высота $c$, м: <b id="p33-c" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">3</b><input type="range" id="p33-c-r" min="2" max="10" step="0.5" value="3" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '</div>'
+ '<div style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.94rem;line-height:1.7">'
+ '$V = abc = $ <b id="p33-V" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">60</b> м³ &middot; $m = \\rho V = $ <b id="p33-m" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">77</b> кг &middot; $P = mg = $ <b id="p33-P" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">756</b> Н'
+ '<div id="p33-cmp" style="font-size:.84rem;color:#475569;margin-top:4px"></div>'
+ '</div>');
/* IV-2 КВИЗ */
h += wgWrap('p33-iv2', 'КВИЗ', 'Вес газов', '',
'<div id="p33-q-host">'
+ quizQuestion('p33-q', 0, 'Воздух имеет массу?', ['Нет, газ невесом','Да, как и любое вещество','Только при низкой T','Только под давлением'], 1)
+ quizQuestion('p33-q', 1, 'Плотность воздуха у Земли примерно равна:', ['0,001 кг/м³','1,29 кг/м³','100 кг/м³','1000 кг/м³'], 1)
+ quizQuestion('p33-q', 2, 'Воздух в комнате 50 м³ весит примерно:', ['65 г','650 г','65 кг','650 кг'], 2)
+ '</div>');
/* IV-3 DnD */
h += wgWrap('p33-iv3', 'DnD', 'Тяжелее или легче воздуха?', '',
dndPool('p33-dnd', [
{ id:'a1', cat:'lighter', html:'Гелий (He, 0,18 кг/м³)' },
{ id:'a2', cat:'lighter', html:'Водород (H₂, 0,09 кг/м³)' },
{ id:'a3', cat:'lighter', html:'Метан (CH₄, 0,72 кг/м³)' },
{ id:'a4', cat:'heavier', html:'Углекислый газ (CO₂, 1,98)' },
{ id:'a5', cat:'heavier', html:'Хлор (Cl₂, 3,21)' },
{ id:'a6', cat:'heavier', html:'Радон (Rn, 9,73)' }
], [
{ cat:'lighter', label:'Легче воздуха ($\\rho < 1{,}29$)' },
{ cat:'heavier', label:'Тяжелее воздуха ($\\rho > 1{,}29$)' }
]));
/* IV-4 ТРН */
h += wgWrap('p33-iv4', 'ТРН', 'Тренажёр §33', '',
'<div id="p33-tr-host">'
+ quizQuestion('p33-tr', 0, 'Воздух в комнате $V = 100$ м³ ($\\rho = 1{,}29$). Масса в кг?', ['12,9','129','1290','1,29'], 1, '$m = 1{,}29 \\cdot 100 = 129$ кг.')
+ quizQuestion('p33-tr', 1, 'Гелий легче воздуха в ~7 раз. Шарик с гелием…', ['Тяжелее','Не отличается','Легче — может летать','Падает быстрее'], 2)
+ quizQuestion('p33-tr', 2, 'Углекислый газ скапливается…', ['У потолка','У пола','Равномерно','Не скапливается'], 1, 'Он тяжелее воздуха — оседает вниз.')
+ quizQuestion('p33-tr', 3, '$m$ воздуха в баллоне $0{,}001$ м³ ($\\rho = 1{,}29$)?', ['0,00129 кг','0,0129 кг','1,29 г','Все верны 1 и 3'], 3, '$m = 1{,}29 \\cdot 0{,}001 = 0{,}00129$ кг $= 1{,}29$ г.')
+ '</div>');
h += readButton('p33');
body.innerHTML = h;
const upd33 = () => {
const a = +document.getElementById('p33-a-r').value;
const b = +document.getElementById('p33-b-r').value;
const c = +document.getElementById('p33-c-r').value;
document.getElementById('p33-a').textContent = a;
document.getElementById('p33-b').textContent = b;
document.getElementById('p33-c').textContent = c;
const V = a * b * c;
const m = V * 1.29;
const P = m * 9.8;
document.getElementById('p33-V').textContent = V.toFixed(1);
document.getElementById('p33-m').textContent = m.toFixed(1);
document.getElementById('p33-P').textContent = P.toFixed(0);
let cmp;
if(m < 30) cmp = 'Меньше школьника.';
else if(m < 80) cmp = 'Примерно вес взрослого человека.';
else if(m < 200) cmp = 'Как пара человек.';
else if(m < 1000) cmp = 'Как пианино или мотоцикл.';
else cmp = 'Тяжелее тонны — как автомобиль!';
document.getElementById('p33-cmp').textContent = cmp;
};
['p33-a-r','p33-b-r','p33-c-r'].forEach(id => document.getElementById(id).addEventListener('input', upd33));
upd33();
wireDnd('p33-dnd', [
{ id:'a1', cat:'lighter' },{ id:'a2', cat:'lighter' },{ id:'a3', cat:'lighter' },
{ id:'a4', cat:'heavier' },{ id:'a5', cat:'heavier' },{ id:'a6', cat:'heavier' }
]);
wireQuiz('p33-q-host', () => { if(window.addXp) window.addXp(10, 'q-p33'); });
wireQuiz('p33-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p33'); });
wireReadBtn('p33');
renderMath(body);
}
/* ========================================================== */
/* §34 — Атмосферное давление */
/* ========================================================== */
function add_p34(){
const body = document.getElementById('p34-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Атмосфера давит на нас', '§ 34.1',
'Земля окружена слоем воздуха — <b>атмосферой</b>. Этот воздух имеет вес и давит на всё, что находится на поверхности Земли.<br><br>'
+ '<b>Нормальное атмосферное давление</b>: $p_0 = 101\\,325$ Па $= 760$ мм рт. ст. $\\approx 1$ атм.');
h += makeCard('rule', 'Опыт Торричелли (1643)', '§ 34.2',
'Эванжелиста Торричелли перевернул трубку, наполненную ртутью, в чашку с ртутью. '
+ 'Ртуть в трубке опустилась до высоты $\\approx 760$ мм над уровнем чашки. '
+ 'Это значит, что атмосфера снаружи давила на чашку с такой же силой, как столб ртути высотой $760$ мм.<br><br>'
+ 'Так была открыта единица «миллиметр ртутного столба» (мм рт. ст.).');
h += makeCard('example', 'С высотой давление падает', '§ 34.3',
'На каждые $\\approx 12$ м подъёма атмосферное давление уменьшается на $1$ мм рт. ст. (на малых высотах).<br><br>'
+ 'Поэтому на вершине Эльбруса ($5642$ м) давление $\\approx 400$ мм рт. ст. — почти в 2 раза меньше уровня моря. '
+ 'Космонавтам в открытом космосе нужны скафандры — давление за бортом $\\approx 0$.');
/* IV-1 СИМ: ртутный барометр Торричелли */
h += wgWrap('p34-iv1', 'СИМ', 'Барометр Торричелли', 'Меняй атмосферное давление — увидь высоту столба ртути.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Давление, мм рт. ст.: <b id="p34-mm" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">760</b><input type="range" id="p34-mm-r" min="400" max="800" step="5" value="760" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<div style="display:grid;grid-template-columns:160px 1fr;gap:14px;align-items:center">'
+ '<svg id="p34-svg" viewBox="0 0 160 380" width="100%" style="max-width:180px;display:block"></svg>'
+ '<div id="p34-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.94rem;line-height:1.7"></div>'
+ '</div>');
/* IV-2 КАЛЬК: высота → давление */
h += wgWrap('p34-iv2', 'КАЛЬК', 'Давление на высоте', 'На каждые ~12 м давление падает на 1 мм рт. ст.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Высота над уровнем моря, м: <b id="p34c-H" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">0</b><input type="range" id="p34c-H-r" min="0" max="5000" step="50" value="0" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<div style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.94rem;line-height:1.65">'
+ '$\\Delta p = H/12 = $ <b id="p34c-dp" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">0</b> мм рт. ст. &middot; $p \\approx $ <b id="p34c-p" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">760</b> мм рт. ст. $\\approx $ <b id="p34c-pkpa" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">101.3</b> кПа'
+ '<div id="p34c-place" style="font-size:.84rem;color:#475569;margin-top:5px"></div>'
+ '</div>');
/* IV-3 DnD */
h += wgWrap('p34-iv3', 'DnD', 'Где давление какое?', '',
dndPool('p34-dnd', [
{ id:'a1', cat:'norm', html:'Уровень моря (≈760 мм)' },
{ id:'a2', cat:'low', html:'Эверест 8 848 м (≈250 мм)' },
{ id:'a3', cat:'high', html:'Шахта 500 м (≈800 мм)' },
{ id:'a4', cat:'low', html:'Самолёт 10 км (≈190 мм)' },
{ id:'a5', cat:'norm', html:'Город Минск (≈750 мм)' },
{ id:'a6', cat:'high', html:'Мёртвое море 430 м (≈800 мм)' }
], [
{ cat:'high', label:'Выше нормы (ниже уровня моря)' },
{ cat:'norm', label:'Около нормы (~760)' },
{ cat:'low', label:'Ниже нормы (горы / небо)' }
]));
/* IV-4 ТРН */
h += wgWrap('p34-iv4', 'ТРН', 'Тренажёр §34', '',
'<div id="p34-tr-host">'
+ quizQuestion('p34-tr', 0, 'Нормальное атм. давление в мм рт. ст.?', ['100','500','760','1000'], 2)
+ quizQuestion('p34-tr', 1, 'Что произойдёт с давлением, если подняться на 360 м вверх?', ['Не изменится','Упадёт на ~30 мм','Упадёт на ~3 мм','Возрастёт'], 1, '$\\Delta p = 360/12 = 30$ мм рт. ст.')
+ quizQuestion('p34-tr', 2, 'Кто открыл атм. давление?', ['Архимед','Торричелли','Галилей','Паскаль'], 1)
+ quizQuestion('p34-tr', 3, 'Высота Эвереста ~9 км. Атм. давление там примерно:', ['0 мм','100 мм','250 мм','760 мм'], 2)
+ quizQuestion('p34-tr', 4, '$p = 750$ мм рт. ст. в кПа? (1 мм ≈ 133 Па)', ['7,5','75','100','750'], 2, '$750 \\cdot 133 \\approx 100\\,000$ Па $= 100$ кПа.')
+ '</div>');
h += readButton('p34');
body.innerHTML = h;
// §34 IV-1 — use PHYS.mercuryBarometer
function draw34(){
const mm = +document.getElementById('p34-mm-r').value;
document.getElementById('p34-mm').textContent = mm;
if(window.PHYS && window.PHYS.mercuryBarometer){
const inner = window.PHYS.mercuryBarometer(80, 30, mm);
document.getElementById('p34-svg').innerHTML = inner;
}
const pa = mm * 133.322;
let descr;
if(mm > 770) descr = '<b>Выше нормы</b> — антициклон, ясная погода (или вы в шахте/долине).';
else if(mm > 745) descr = '<b>Норма</b> — обычное давление у поверхности Земли.';
else if(mm > 600) descr = '<b>Ниже нормы</b> — горы, циклон, плохая погода.';
else descr = '<b>Очень низкое</b> — высокогорье или большая высота.';
document.getElementById('p34-info').innerHTML = '<b>' + mm + '</b> мм рт. ст. $= $ <b>' + Math.round(pa).toLocaleString('ru-RU') + '</b> Па $\\approx $ <b>' + (pa/1000).toFixed(1) + '</b> кПа<br><br>' + descr;
renderMath(document.getElementById('p34-info'));
}
document.getElementById('p34-mm-r').addEventListener('input', draw34);
draw34();
// §34 IV-2
const upd34c = () => {
const H = +document.getElementById('p34c-H-r').value;
document.getElementById('p34c-H').textContent = H;
const dp = H / 12;
const p = Math.max(0, 760 - dp);
const pa = p * 133.322;
document.getElementById('p34c-dp').textContent = dp.toFixed(1);
document.getElementById('p34c-p').textContent = p.toFixed(0);
document.getElementById('p34c-pkpa').textContent = (pa/1000).toFixed(1);
let place;
if(H < 100) place = 'Уровень моря — норма.';
else if(H < 500) place = 'Холмистая местность.';
else if(H < 2000) place = 'Среднегорье (Кавказ, Альпы предгорья).';
else if(H < 4000) place = 'Высокогорье. Может быть «горная болезнь».';
else place = 'Очень высоко — Эверест и выше. Нужен кислород.';
document.getElementById('p34c-place').textContent = place;
};
document.getElementById('p34c-H-r').addEventListener('input', upd34c);
upd34c();
wireDnd('p34-dnd', [
{ id:'a1', cat:'norm' },{ id:'a2', cat:'low' },{ id:'a3', cat:'high' },
{ id:'a4', cat:'low' },{ id:'a5', cat:'norm' },{ id:'a6', cat:'high' }
]);
wireQuiz('p34-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p34'); });
wireReadBtn('p34');
renderMath(body);
}
/* ========================================================== */
/* §35 — Барометры и манометры (ГЛАВНЫЙ ВИЗУАЛ ГЛАВЫ 4) */
/* ========================================================== */
function add_p35(){
const body = document.getElementById('p35-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Три прибора для давления', '§ 35.1',
'<ul style="padding-left:20px;margin:6px 0">'
+ '<li><b>Ртутный барометр Торричелли</b> — измеряет атм. давление через высоту ртутного столба.</li>'
+ '<li><b>Анероид</b> (греч. «без жидкости») — пружинный, стрелочный. Не разобьётся, удобен.</li>'
+ '<li><b>Жидкостный U-манометр</b> — измеряет давление газа относительно атмосферного, через разность уровней.</li>'
+ '</ul>');
h += makeCard('rule', 'Где какой прибор', '§ 35.2',
'<b>Барометры</b> (Торричелли, анероид) — измеряют <b>атмосферное</b> давление воздуха.<br>'
+ '<b>Манометр</b> — измеряет давление <b>газа в сосуде</b> или жидкости. '
+ 'Например, в шине, в баллоне с пропаном, в трубе с водой.<br>'
+ '<b>Кардиограф/тонометр</b> — давление в кровеносных сосудах.');
h += makeCard('example', 'Манометр на баллоне', '§ 35.3',
'В баллоне с газом давление много выше атмосферного. Манометр показывает <b>разность</b>: '
+ 'давление в баллоне минус $p_0$. Если шкала показывает $200$ кПа — фактическое давление в баллоне $200 + 100 = 300$ кПа.');
/* IV-1 ГЛАВНЫЙ ВИЗУАЛ — все 3 прибора */
h += wgWrap('p35-iv1', 'СИМ', 'Три прибора рядом — главный визуал', 'Одно и то же давление, три способа показать.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Атм. давление, мм рт. ст.: <b id="p35-mm" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">760</b><input type="range" id="p35-mm-r" min="720" max="800" step="2" value="760" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px">'
+ '<div style="text-align:center"><div style="font-weight:700;font-size:.84rem;color:' + ACCENT_D + ';margin-bottom:6px">Торричелли</div><svg id="p35-merc" viewBox="0 0 140 340" width="100%" style="max-width:140px"></svg></div>'
+ '<div style="text-align:center"><div style="font-weight:700;font-size:.84rem;color:' + ACCENT_D + ';margin-bottom:6px">Анероид</div><svg id="p35-aner" viewBox="0 0 180 200" width="100%" style="max-width:180px"></svg></div>'
+ '<div style="text-align:center"><div style="font-weight:700;font-size:.84rem;color:' + ACCENT_D + ';margin-bottom:6px">U-манометр (газ vs $p_0$)</div><svg id="p35-uman" viewBox="0 0 120 160" width="100%" style="max-width:120px"></svg></div>'
+ '</div>'
+ '<div id="p35-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:10px;font-size:.92rem;text-align:center"></div>');
/* IV-2 КВИЗ */
h += wgWrap('p35-iv2', 'КВИЗ', 'Какой прибор для чего', '',
'<div id="p35-q-host">'
+ quizQuestion('p35-q', 0, 'Чем измеряют атм. давление?', ['Манометр','Барометр','Гигрометр','Термометр'], 1)
+ quizQuestion('p35-q', 1, 'Чем измеряют давление газа в шине?', ['Барометр','Манометр','Динамометр','Спидометр'], 1)
+ quizQuestion('p35-q', 2, 'Что меряет анероид?', ['Температура','Атм. давление','Скорость','Влажность'], 1)
+ quizQuestion('p35-q', 3, 'Что значит «анероид»?', ['Безжидкостный','Сложный','Точный','Электронный'], 0)
+ '</div>');
/* IV-3 DnD */
h += wgWrap('p35-iv3', 'DnD', 'Какой прибор для какой задачи?', '',
dndPool('p35-dnd', [
{ id:'a1', cat:'baro', html:'Атм. давление в школьном кабинете физики' },
{ id:'a2', cat:'baro', html:'Давление перед сменой погоды' },
{ id:'a3', cat:'mano', html:'Давление в шине автомобиля' },
{ id:'a4', cat:'mano', html:'Давление в газовом баллоне' },
{ id:'a5', cat:'mano', html:'Давление в водопроводе' },
{ id:'a6', cat:'baro', html:'Давление на вершине горы' }
], [
{ cat:'baro', label:'Барометр' },
{ cat:'mano', label:'Манометр' }
]));
/* IV-4 ТРН */
h += wgWrap('p35-iv4', 'ТРН', 'Тренажёр §35', '',
'<div id="p35-tr-host">'
+ quizQuestion('p35-tr', 0, '$1$ мм рт. ст. примерно равен:', ['13,3 Па','133 Па','1330 Па','13 300 Па'], 1)
+ quizQuestion('p35-tr', 1, '$200$ мм рт. ст. в Па:', ['2 660','26 600','266 000','2 660 000'], 1, '$200 \\cdot 133 \\approx 26\\,600$ Па.')
+ quizQuestion('p35-tr', 2, 'Манометр показал $\\Delta p = 150$ кПа. Полное давление в баллоне (при $p_0 = 100$ кПа):', ['50 кПа','100 кПа','150 кПа','250 кПа'], 3)
+ quizQuestion('p35-tr', 3, 'Высота ртутного столба $= 750$ мм. Что измеряем?', ['Атм. давление','Влажность','Температуру','Скорость ветра'], 0)
+ '</div>');
h += readButton('p35');
body.innerHTML = h;
function draw35(){
const mm = +document.getElementById('p35-mm-r').value;
document.getElementById('p35-mm').textContent = mm;
const pa = mm * 133.322;
if(window.PHYS){
if(window.PHYS.mercuryBarometer) document.getElementById('p35-merc').innerHTML = window.PHYS.mercuryBarometer(60, 30, mm);
if(window.PHYS.aneroidBarometer) document.getElementById('p35-aner').innerHTML = window.PHYS.aneroidBarometer(90, 90, 70, pa);
// Для U-манометра показываем разницу давлений (предположим, газ под давлением 800 мм)
if(window.PHYS.uManometer){
// deltaH в px, положительное — газ давит, правая часть ниже
const gasPMm = mm + 30; // газ всегда выше атмосферного для иллюстрации
const deltaH = (gasPMm - mm) * 1.5; // px
document.getElementById('p35-uman').innerHTML = window.PHYS.uManometer(30, 20, 60, 130, deltaH, '#0891b2');
}
}
document.getElementById('p35-info').innerHTML = 'Атм. давление: <b>' + mm + '</b> мм рт. ст. $= $ <b>' + Math.round(pa).toLocaleString('ru-RU') + '</b> Па. Все три прибора показывают одно и то же — по-разному.';
renderMath(document.getElementById('p35-info'));
}
document.getElementById('p35-mm-r').addEventListener('input', draw35);
draw35();
wireDnd('p35-dnd', [
{ id:'a1', cat:'baro' },{ id:'a2', cat:'baro' },{ id:'a3', cat:'mano' },
{ id:'a4', cat:'mano' },{ id:'a5', cat:'mano' },{ id:'a6', cat:'baro' }
]);
wireQuiz('p35-q-host', () => { if(window.addXp) window.addXp(10, 'q-p35'); });
wireQuiz('p35-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p35'); });
wireReadBtn('p35');
renderMath(body);
}
/* ========================================================== */
/* Финал главы 4 — 7 боссов + ачивка «Властелин давления» */
/* ========================================================== */
function add_final4(){
const body = document.getElementById('final4-body');
if(!body) return;
let h = '';
h += '<div style="background:linear-gradient(135deg,' + ACCENT_SOFT + ',#fff7ed);border:1.5px solid ' + ACCENT + ';border-radius:14px;padding:16px;margin-bottom:14px;text-align:center">'
+ '<div style="font-family:Unbounded,sans-serif;font-weight:800;font-size:1.12rem;color:' + ACCENT_D + '">Финал главы 4: победи 7 боссов</div>'
+ '<div style="font-size:.88rem;color:#475569;margin-top:5px">Реши все 7 задач — получишь ачивку «Властелин давления» и +50 XP.</div>'
+ '<div style="height:10px;background:#fff;border-radius:6px;overflow:hidden;margin-top:12px;border:1px solid ' + ACCENT_SOFT + '"><div id="ch4-fin-fill" style="height:100%;background:linear-gradient(90deg,' + ACCENT + ',' + ACCENT_D + ');width:0%;transition:width .4s"></div></div>'
+ '<div id="ch4-fin-lab" style="font-size:.84rem;color:#475569;margin-top:6px">Побеждено: 0 / 7</div>'
+ '</div>';
const bosses = [
{ n:1, tag:'§28', title:'Давление кирпича',
q:'Кирпич весом $F = 30$ Н стоит на грани площадью $S = 60$ см². Найди $p$ в Па.',
hint:'$S = 60 \\cdot 10^{-4} = 0{,}006$ м². $p = F/S = 30/0{,}006 = 5000$ Па.',
ans:5000, tol:50, step:'10' },
{ n:2, tag:'§30', title:'Гидравлический пресс',
q:'Малый поршень $S_1 = 5$ см², большой $S_2 = 500$ см². На малый давит $F_1 = 80$ Н. Найди $F_2$ в Н.',
hint:'$F_2 = F_1 \\cdot S_2/S_1 = 80 \\cdot 500/5 = 8000$ Н.',
ans:8000, tol:50, step:'10' },
{ n:3, tag:'§31', title:'Дайвер на дне моря',
q:'Глубина $h = 20$ м, $\\rho_{море} = 1030$ кг/м³, $g = 10$. Гидростат. давление в кПа?',
hint:'$p = 1030 \\cdot 10 \\cdot 20 = 206\\,000$ Па $= 206$ кПа.',
ans:206, tol:3, step:'1' },
{ n:4, tag:'§32', title:'Сообщающиеся сосуды',
q:'В двух соединённых сосудах одна и та же вода. В одном уровень $h = 18$ см. В другом сосуде, в 3 раза шире, какой уровень будет в см?',
hint:'Уровни однородной жидкости одинаковы независимо от ширины. $h = 18$ см.',
ans:18, tol:0.5, step:'0.1' },
{ n:5, tag:'§34', title:'Давление на горе',
q:'У моря $p_0 = 760$ мм рт. ст. Поднялись на $H = 480$ м. Давление стало:',
hint:'$\\Delta p = H/12 = 40$ мм. $p = 760 - 40 = 720$ мм рт. ст.',
ans:720, tol:3, step:'1' },
{ n:6, tag:'§35', title:'Барометр в Па',
q:'Барометр-анероид показал $p = 740$ мм рт. ст. Сколько это Па? (округли до сотен)',
hint:'$p = 740 \\cdot 133 \\approx 98\\,420$ Па $\\approx 98\\,400$ Па.',
ans:98400, tol:300, step:'100' },
{ n:7, tag:'синтез', title:'Властелин давления',
q:'Дайвер на $h = 30$ м в пресной воде ($\\rho = 1000$). Над водой $p_0 = 100$ кПа. Найди полное давление на дайвера в кПа.',
hint:'$p_{гидр} = 1000 \\cdot 10 \\cdot 30 = 300\\,000$ Па $= 300$ кПа. Полное: $p = p_0 + p_{гидр} = 100 + 300 = 400$ кПа.',
ans:400, tol:5, step:'1' }
];
const STATE_KEY = 'physics7_ch4_final_bosses';
let solved = {};
try{ solved = JSON.parse(localStorage.getItem(STATE_KEY) || '{}') || {}; }catch(e){}
bosses.forEach(b => {
const isSolved = !!solved[b.n];
h += '<div data-boss="' + b.n + '" style="background:#fff;border:2px solid ' + (isSolved ? '#10b981' : ACCENT_SOFT) + ';border-radius:12px;padding:14px 16px;margin-bottom:12px;box-shadow:' + (isSolved ? '0 0 0 3px rgba(16,185,129,.16)' : '0 2px 8px rgba(0,0,0,.05)') + '">'
+ '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap">'
+ '<span style="background:' + ACCENT + ';color:#fff;padding:3px 10px;border-radius:99px;font-size:.7rem;font-weight:800;letter-spacing:.04em">' + b.tag + '</span>'
+ '<span style="font-family:Unbounded,sans-serif;font-weight:800;font-size:.96rem;color:#0f172a">Босс ' + b.n + '. ' + b.title + '</span>'
+ '</div>'
+ '<div style="padding:10px 12px;background:' + ACCENT_SOFT + ';border-radius:8px;margin-bottom:10px;font-size:.94rem;line-height:1.55">' + b.q + '</div>'
+ '<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">'
+ '<input type="number" step="' + b.step + '" class="boss-inp" data-n="' + b.n + '" placeholder="число" style="padding:8px 12px;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:8px;width:140px;text-align:center;font-family:JetBrains Mono,monospace;font-size:.95rem"' + (isSolved ? ' value="' + b.ans + '" disabled' : '') + '>'
+ '<button class="boss-go" data-n="' + b.n + '" type="button" style="background:linear-gradient(135deg,' + ACCENT + ',' + ACCENT_D + ');color:#fff;border:none;padding:8px 16px;border-radius:9px;font-weight:700;font-size:.88rem;cursor:pointer;font-family:inherit"' + (isSolved ? ' disabled' : '') + '>Атаковать</button>'
+ '<button class="boss-hint" data-n="' + b.n + '" type="button" style="background:#fff;color:#475569;border:1.5px solid ' + ACCENT_SOFT + ';padding:8px 14px;border-radius:9px;font-weight:600;font-size:.86rem;cursor:pointer;font-family:inherit">Подсказка</button>'
+ '</div>'
+ '<div class="boss-hint-txt" data-n="' + b.n + '" style="margin-top:8px;padding:9px 13px;background:#fef3c7;border-left:3px solid #f59e0b;border-radius:6px;font-size:.86rem;line-height:1.5;display:none">' + b.hint + '</div>'
+ '<div class="boss-fb" data-n="' + b.n + '" style="margin-top:8px;padding:9px 13px;border-radius:8px;font-weight:600;font-size:.88rem;line-height:1.45;' + (isSolved ? 'background:#d1fae5;color:#065f46;border-left:4px solid #10b981' : 'display:none') + '">' + (isSolved ? '&#10003; Босс повержен! +20 XP.' : '') + '</div>'
+ '</div>';
});
h += '<div id="ch4-mastered" style="margin-top:14px;padding:14px 18px;border-radius:12px;background:linear-gradient(135deg,#fef3c7,#fde68a);border:1.5px solid #f59e0b;display:none;align-items:center;gap:12px"><svg style="width:32px;height:32px;stroke:#92400e;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round" viewBox="0 0 24 24"><polygon points="12,2 15,9 22,9.3 17,14 18.5,21 12,17 5.5,21 7,14 2,9.3 9,9"/></svg><div style="flex:1"><div style="font-weight:800;color:#92400e;font-family:Unbounded,sans-serif">Ачивка «Властелин давления» получена!</div><div style="font-size:.86rem;color:#78350f;margin-top:2px">+50 XP &middot; Глава 4 полностью пройдена.</div></div></div>';
body.innerHTML = h;
renderMath(body);
function updateBar(){
const cnt = bosses.filter(b => solved[b.n]).length;
document.getElementById('ch4-fin-fill').style.width = (cnt * 100 / bosses.length) + '%';
document.getElementById('ch4-fin-lab').textContent = 'Побеждено: ' + cnt + ' / ' + bosses.length;
if(cnt === bosses.length){
document.getElementById('ch4-mastered').style.display = 'flex';
const ACH_KEY = 'physics7_ch4_master';
if(localStorage.getItem(ACH_KEY) !== '1'){
localStorage.setItem(ACH_KEY, '1');
if(window.addXp) window.addXp(50, 'ach-ch4-master');
if(window.achievement) window.achievement('ch_done', 'Властелин давления');
}
}
}
updateBar();
body.querySelectorAll('.boss-hint').forEach(btn => btn.addEventListener('click', () => {
const n = btn.dataset.n;
const txt = body.querySelector('.boss-hint-txt[data-n="' + n + '"]');
if(txt) txt.style.display = txt.style.display === 'none' ? 'block' : 'none';
}));
body.querySelectorAll('.boss-go').forEach(btn => btn.addEventListener('click', () => {
const n = +btn.dataset.n;
const b = bosses.find(x => x.n === n);
const inp = body.querySelector('.boss-inp[data-n="' + n + '"]');
const fb = body.querySelector('.boss-fb[data-n="' + n + '"]');
const card = body.querySelector('[data-boss="' + n + '"]');
const v = parseFloat((inp.value || '').replace(',', '.'));
if(isNaN(v)){
fb.style.display = 'block';
fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.textContent = 'Введи число.';
return;
}
if(Math.abs(v - b.ans) < b.tol){
fb.style.display = 'block';
fb.style.background = '#d1fae5'; fb.style.color = '#065f46'; fb.style.borderLeft = '4px solid #10b981';
fb.innerHTML = '&#10003; Босс повержен! +20 XP.';
card.style.border = '2px solid #10b981';
card.style.boxShadow = '0 0 0 3px rgba(16,185,129,.16)';
btn.disabled = true; inp.disabled = true;
if(!solved[n]){
solved[n] = true;
try{ localStorage.setItem(STATE_KEY, JSON.stringify(solved)); }catch(e){}
if(window.addXp) window.addXp(20, 'boss-ch4-' + n);
updateBar();
}
} else {
fb.style.display = 'block';
fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.textContent = 'Не то. Перепроверь решение.';
}
}));
body.querySelectorAll('.boss-inp').forEach(inp => inp.addEventListener('keydown', e => {
if(e.key === 'Enter'){ e.preventDefault(); body.querySelector('.boss-go[data-n="' + inp.dataset.n + '"]').click(); }
}));
}
window.PHYS7_CH4_WIDGETS = {
p28: add_p28,
p29: add_p29,
p30: add_p30,
p31: add_p31,
p32: add_p32,
p33: add_p33,
p34: add_p34,
p35: add_p35,
final4: add_final4
};
})();