ed97b6d90b
Полная глава 2 «Строение вещества» в одном файле (1195 строк, 7 экспортов). §8 Дискретное строение: - 3 карточки (молекулы и атомы / шкала размеров от 1 м до ядра / доказательства) - IV-1 СИМ: визуальная шкала размеров (8 объектов с цветными барами) - IV-2 СИМ: конструктор молекул H₂O/CO₂/O₂/N₂/CH4/NaCl с SVG-схемами и описаниями - IV-3 DnD: 8 объектов по 3 корзинам (атом/молекула/тело) - IV-4 ТРН: 5 вопросов §9 Тепловое движение. Диффузия: - 3 карточки (хаотическое движение / диффузия и её скорость / примеры) - IV-1 СИМ: анимированная диффузия 60 частиц (20 чернил + 40 воды), slider T → ускорение броуновского движения, кнопка «Сброс», requestAnimationFrame - IV-2 КВИЗ: 3 вопроса о диффузии и броун. движении - IV-3 DnD: 6 примеров → 3 скорости (быстро газ / средне жидк / медленно тверд) - IV-4 ТРН: 5 вопросов §10 Взаимодействие частиц: - 3 карточки (отталкивание/равновесие/притяжение / зачем знать / опыт со свинцом) - IV-1 СИМ: интерактивный график F(r) (Леннард-Джонс-подобная кривая), slider положения → автоматическое определение «отталкивание / равновесие / притяжение / силы малы» - IV-2 КВИЗ: 4 вопроса - IV-3 DnD: 6 ситуаций по 4 корзинам - IV-4 ТРН: 4 вопроса §11 Три состояния — ГЛАВНЫЙ ВИЗУАЛ ГЛАВЫ 2: - 3 карточки (таблица состояний / поведение молекул / вода во всех 3 состояниях) - IV-1 СИМ: переключатель solid/liquid/gas с 3 разными режимами анимации 50 частиц: solid — крист. решётка 10×5 + дрожание; liquid — отскоки + гравитация к дну + плоский уровень; gas — свободное хаотическое движение по всему объёму - IV-2 КВИЗ: 4 вопроса о свойствах - IV-3 DnD: 9 веществ → 3 состояния - IV-4 ТРН: 5 вопросов §12 Тепловое расширение: - 3 карточки (почему / где важно / аномалия воды) - IV-1 СИМ: стержень со slider ΔT (0..200°C), цвет по температуре (HSL 240→0), пунктир базовой длины, индикатор Δl - IV-2 СИМ: биметаллическая пластина с slider ΔT (-50..100°C), изгиб ±30° - IV-3 DnD: 6 веществ → 3 уровня расширения - IV-4 ТРН: 5 вопросов §13 Температура. Термометры: - 3 карточки (T и тепловое движение / шкала Цельсия / 4 вида термометров) - IV-1 СИМ: виртуальный термометр SVG (-50..150 °C), столбик меняет цвет по температуре, шкала с делениями, указатель-стрелка, контекстная подсказка (мороз/комфорт/жарко/кипяток...) + конвертер в Кельвины - IV-2 КАЛЬК: slider t°C → T(K) = t + 273.15, упоминание абс. нуля - IV-3 DnD: 6 температур → 3 диапазона - IV-4 ТРН: 5 вопросов (включая °C↔K) ФИНАЛ ГЛАВЫ 2 (5 боссов + ачивка «Знаток вещества» +50 XP): 1. Молекула vs волос: во сколько раз меньше (10⁶) 2. Диффузия в горячей воде (/T_2$ через Кельвины) 3. Сжатие газа в шприце (20/50 = 40%) 4. Удлинение рельса при ΔT=60°C (18 мм) 5. 27 °C → 300.2 K Все интерактивы wireDnd/wireQuiz/слайдеры/симы привязаны. parse-check, smoke-test (7 экспортов) пройдены.
1196 lines
88 KiB
JavaScript
1196 lines
88 KiB
JavaScript
// Физика 7 · Глава 2 «Строение вещества» · виджеты §§8–13 + финал (Wave 1+2+3).
|
||
// Экспорт: window.PHYS7_CH2_WIDGETS = { p8, p9, p10, p11, p12, p13, final2 }.
|
||
// Палитра главы — violet (#7c3aed).
|
||
|
||
(function(){
|
||
'use strict';
|
||
|
||
const ACCENT = '#7c3aed';
|
||
const ACCENT_D = '#5b21b6';
|
||
const ACCENT_SOFT = '#ede9fe';
|
||
|
||
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:'#dc2626', 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>'
|
||
+ 'Я прочитал § <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_ch2_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 = {};
|
||
let 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(124,58,237,.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 inner = box.querySelector('.drop-items');
|
||
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 = '';
|
||
});
|
||
inner.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 = '✓ Идеально! Все ' + 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 = '✗ Правильно: ' + 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:#faf5ff">' + 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,'"') + '">' + 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 = '✓ Верно!' + (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 = '✗ Неверно. Правильно: «' + opts[correct].textContent + '».' + (explain ? ' ' + explain : '');
|
||
done.add(qDiv);
|
||
}
|
||
}));
|
||
});
|
||
}
|
||
|
||
/* ========================================================== */
|
||
/* §8 — Дискретное строение вещества */
|
||
/* ========================================================== */
|
||
function add_p8(){
|
||
const body = document.getElementById('p8-body');
|
||
if(!body) return;
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Из чего состоит вещество', '§ 8.1',
|
||
'Все вещества состоят из <b>мельчайших частиц</b> — <b>молекул</b> и <b>атомов</b>. '
|
||
+ 'Они так малы, что не видны даже в обычный микроскоп. Между частицами есть <b>промежутки</b>. '
|
||
+ 'Молекула — это наименьшая частица вещества, сохраняющая его химические свойства. '
|
||
+ 'Молекулы состоят из <b>атомов</b>.');
|
||
|
||
h += makeCard('rule', 'Размеры частиц', '§ 8.2',
|
||
'Типичный диаметр молекулы — около $10^{-10}$ м. Сравни:'
|
||
+ '<table style="width:100%;border-collapse:collapse;margin-top:6px;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 + '">Размер</th></tr>'
|
||
+ [['Зерно мака','1 мм $= 10^{-3}$ м'],['Толщина волоса','$\\approx 10^{-4}$ м'],['Бактерия','$\\approx 10^{-6}$ м'],['Молекула','$\\approx 10^{-10}$ м'],['Атом','$\\approx 10^{-10}$ м'],['Ядро атома','$\\approx 10^{-15}$ м']].map(([nm, sz]) =>
|
||
'<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">' + nm + '</td><td style="padding:5px 10px;text-align:right;border-bottom:1px solid ' + ACCENT_SOFT + ';font-family:JetBrains Mono,monospace">' + sz + '</td></tr>').join('')
|
||
+ '</table>');
|
||
|
||
h += makeCard('example', 'Доказательства дискретности', '§ 8.3',
|
||
'<ol style="padding-left:20px;margin:6px 0;line-height:1.7">'
|
||
+ '<li><b>Сжимаемость газов</b> — при сдавливании поршнем объём уменьшается → есть пустоты между молекулами.</li>'
|
||
+ '<li><b>Растворение сахара в воде</b> — молекулы сахара заполняют промежутки между молекулами воды; уровень почти не поднимается.</li>'
|
||
+ '<li><b>Расширение тел при нагреве</b> — увеличиваются промежутки между частицами.</li>'
|
||
+ '</ol>');
|
||
|
||
/* IV-1: визуал-масштабы */
|
||
h += wgWrap('p8-iv1', 'СИМ', 'Шкала размеров', 'От огромного к крошечному (логарифмическая шкала).',
|
||
'<div style="display:flex;flex-direction:column;gap:6px">'
|
||
+ [['1 м','Человек','#0284c7',1],['0,01 м','Монета','#10b981',0.85],['0,001 м','Зерно мака','#d97706',0.7],['10⁻⁴ м','Волос (толщина)','#dc2626',0.55],['10⁻⁶ м','Бактерия','#7c3aed',0.4],['10⁻⁸ м','Вирус','#0891b2',0.25],['10⁻¹⁰ м','Молекула','#92400e',0.12],['10⁻¹⁵ м','Ядро атома','#374151',0.05]].map(([sz, nm, col, w]) =>
|
||
'<div style="display:flex;align-items:center;gap:10px;background:#faf5ff;border-radius:8px;padding:6px 10px">'
|
||
+ '<div style="font-family:JetBrains Mono,monospace;font-weight:700;color:' + col + ';min-width:64px;font-size:.86rem">' + sz + '</div>'
|
||
+ '<div style="flex:1;height:18px;background:#fff;border:1px solid ' + ACCENT_SOFT + ';border-radius:4px;overflow:hidden"><div style="height:100%;width:' + (w*100) + '%;background:linear-gradient(90deg,' + col + ',' + col + '88)"></div></div>'
|
||
+ '<div style="font-size:.86rem;color:#475569;min-width:120px">' + nm + '</div>'
|
||
+ '</div>').join('')
|
||
+ '</div>');
|
||
|
||
/* IV-2: конструктор молекулы */
|
||
h += wgWrap('p8-iv2', 'СИМ', 'Конструктор молекулы', 'Выбери — увидь схему молекулы из атомов.',
|
||
'<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">'
|
||
+ ['H2O','CO2','O2','N2','CH4','NaCl'].map(m =>
|
||
'<button class="p8-mol" data-m="' + m + '" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:8px;padding:7px 14px;cursor:pointer;font-family:JetBrains Mono,monospace;font-weight:700;font-size:.9rem">' + m + '</button>').join('')
|
||
+ '</div>'
|
||
+ '<svg id="p8-mol-svg" viewBox="0 0 320 130" width="100%" style="max-width:400px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||
+ '<div id="p8-mol-desc" style="text-align:center;font-size:.88rem;color:#475569;margin-top:8px"></div>');
|
||
|
||
/* IV-3: DnD */
|
||
h += wgWrap('p8-iv3', 'DnD', 'Атом / молекула / тело', 'Распредели понятия по корзинам.',
|
||
dndPool('p8-dnd', [
|
||
{ id:'a1', cat:'atom', html:'Атом водорода H' },
|
||
{ id:'a2', cat:'atom', html:'Атом кислорода O' },
|
||
{ id:'a3', cat:'mol', html:'Молекула воды H₂O' },
|
||
{ id:'a4', cat:'mol', html:'Молекула CO₂' },
|
||
{ id:'a5', cat:'body', html:'Капля воды' },
|
||
{ id:'a6', cat:'body', html:'Резиновый мяч' },
|
||
{ id:'a7', cat:'atom', html:'Атом железа Fe' },
|
||
{ id:'a8', cat:'mol', html:'Молекула O₂' }
|
||
], [
|
||
{ cat:'atom', label:'Атом' },
|
||
{ cat:'mol', label:'Молекула' },
|
||
{ cat:'body', label:'Тело' }
|
||
]));
|
||
|
||
/* IV-4: тренажёр */
|
||
h += wgWrap('p8-iv4', 'ТРН', 'Тренажёр §8', '5 вопросов на закрепление.',
|
||
'<div id="p8-tr-host">'
|
||
+ quizQuestion('p8-tr', 0, 'Каков примерный диаметр молекулы воды?', ['$10^{-3}$ м','$10^{-6}$ м','$10^{-10}$ м','$10^{-15}$ м'], 2, 'Молекулы — порядка $10^{-10}$ м (десятая часть нанометра).')
|
||
+ quizQuestion('p8-tr', 1, 'Что меньше: молекула или ядро атома?', ['Молекула','Ядро атома','Они одинаковые','Зависит от вещества'], 1, 'Ядро в $\\sim 10^5$ раз меньше атома.')
|
||
+ quizQuestion('p8-tr', 2, 'Почему газы легко сжимаются?', ['Молекулы мягкие','Между молекулами большие промежутки','Газ не имеет молекул','Молекулы скользят'], 1)
|
||
+ quizQuestion('p8-tr', 3, 'Молекула — это…', ['Видимая частица','Наименьшая частица, сохраняющая свойства вещества','Атом','Кристалл'], 1)
|
||
+ quizQuestion('p8-tr', 4, 'Из чего состоят молекулы?', ['Из электронов','Из протонов','Из атомов','Из ядер'], 2)
|
||
+ '</div>');
|
||
|
||
h += readButton('p8');
|
||
body.innerHTML = h;
|
||
|
||
// Wire molecule constructor
|
||
const molData = {
|
||
'H2O': { atoms:[{x:160,y:65,r:18,c:'#dc2626',l:'O'},{x:120,y:90,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:200,y:90,r:11,c:'#fff',l:'H',stroke:'#94a3b8'}], bonds:[[0,1],[0,2]], desc:'H₂O (вода): 1 атом кислорода + 2 атома водорода под углом 104,5°.' },
|
||
'CO2': { atoms:[{x:160,y:65,r:14,c:'#0f172a',l:'C'},{x:100,y:65,r:18,c:'#dc2626',l:'O'},{x:220,y:65,r:18,c:'#dc2626',l:'O'}], bonds:[[0,1],[0,2]], desc:'CO₂ (углекислый газ): углерод между двумя кислородами, молекула линейная.' },
|
||
'O2': { atoms:[{x:120,y:65,r:18,c:'#dc2626',l:'O'},{x:200,y:65,r:18,c:'#dc2626',l:'O'}], bonds:[[0,1]], desc:'O₂ (кислород): два атома кислорода. Этим воздухом мы дышим.' },
|
||
'N2': { atoms:[{x:120,y:65,r:18,c:'#0891b2',l:'N'},{x:200,y:65,r:18,c:'#0891b2',l:'N'}], bonds:[[0,1]], desc:'N₂ (азот): два атома азота. 78 % воздуха — это N₂.' },
|
||
'CH4': { atoms:[{x:160,y:65,r:14,c:'#0f172a',l:'C'},{x:160,y:30,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:160,y:100,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:110,y:65,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:210,y:65,r:11,c:'#fff',l:'H',stroke:'#94a3b8'}], bonds:[[0,1],[0,2],[0,3],[0,4]], desc:'CH₄ (метан): углерод в центре, 4 водорода по углам тетраэдра. Природный газ.' },
|
||
'NaCl':{ atoms:[{x:130,y:65,r:18,c:'#7c3aed',l:'Na'},{x:200,y:65,r:18,c:'#10b981',l:'Cl'}], bonds:[[0,1]], desc:'NaCl (поваренная соль): натрий + хлор. В твёрдом виде образует кубическую решётку.' }
|
||
};
|
||
function drawMol(m){
|
||
const d = molData[m];
|
||
let s = '';
|
||
d.bonds.forEach(([i,j]) => {
|
||
s += '<line x1="' + d.atoms[i].x + '" y1="' + d.atoms[i].y + '" x2="' + d.atoms[j].x + '" y2="' + d.atoms[j].y + '" stroke="#475569" stroke-width="3"/>';
|
||
});
|
||
d.atoms.forEach(a => {
|
||
s += '<circle cx="' + a.x + '" cy="' + a.y + '" r="' + a.r + '" fill="' + a.c + '" stroke="' + (a.stroke || a.c) + '" stroke-width="1.5"/>';
|
||
s += '<text x="' + a.x + '" y="' + (a.y + 4) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="' + (a.c === '#fff' ? '#0f172a' : '#fff') + '">' + a.l + '</text>';
|
||
});
|
||
document.getElementById('p8-mol-svg').innerHTML = s;
|
||
document.getElementById('p8-mol-desc').textContent = d.desc;
|
||
}
|
||
body.querySelectorAll('.p8-mol').forEach(btn => btn.addEventListener('click', () => {
|
||
body.querySelectorAll('.p8-mol').forEach(b => { b.style.background = '#fff'; b.style.color = '#0f172a'; });
|
||
btn.style.background = ACCENT; btn.style.color = '#fff';
|
||
drawMol(btn.dataset.m);
|
||
}));
|
||
drawMol('H2O');
|
||
body.querySelector('.p8-mol[data-m="H2O"]').style.background = ACCENT;
|
||
body.querySelector('.p8-mol[data-m="H2O"]').style.color = '#fff';
|
||
|
||
wireDnd('p8-dnd', [
|
||
{ id:'a1', cat:'atom' },{ id:'a2', cat:'atom' },{ id:'a3', cat:'mol' },{ id:'a4', cat:'mol' },
|
||
{ id:'a5', cat:'body' },{ id:'a6', cat:'body' },{ id:'a7', cat:'atom' },{ id:'a8', cat:'mol' }
|
||
]);
|
||
wireQuiz('p8-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p8'); });
|
||
wireReadBtn('p8');
|
||
renderMath(body);
|
||
}
|
||
|
||
/* ========================================================== */
|
||
/* §9 — Тепловое движение частиц. Диффузия */
|
||
/* ========================================================== */
|
||
function add_p9(){
|
||
const body = document.getElementById('p9-body');
|
||
if(!body) return;
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Молекулы вечно движутся', '§ 9.1',
|
||
'Молекулы любого тела находятся в <b>непрерывном беспорядочном (хаотическом) движении</b>. '
|
||
+ 'Это движение называется <b>тепловым</b>: чем выше температура, тем быстрее движутся частицы.<br><br>'
|
||
+ 'Доказательство — <b>броуновское движение</b>: мельчайшие частицы в воде (пыльца, тушь) непрерывно дёргаются под ударами молекул.');
|
||
|
||
h += makeCard('rule', 'Диффузия', '§ 9.2',
|
||
'<b>Диффузия</b> — это самопроизвольное взаимное проникновение молекул одного вещества между молекулами другого.<br><br>'
|
||
+ 'Скорость диффузии зависит от:'
|
||
+ '<ul style="padding-left:20px;margin:5px 0">'
|
||
+ '<li><b>температуры:</b> выше $T$ → быстрее диффузия;</li>'
|
||
+ '<li><b>состояния вещества:</b> в газах ⪢ в жидкостях ⪢ в твёрдых телах.</li>'
|
||
+ '</ul>');
|
||
|
||
h += makeCard('example', 'Где мы видим диффузию', '§ 9.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+ '<li><b>Запах</b> духов или пищи распространяется по комнате — диффузия в воздухе.</li>'
|
||
+ '<li><b>Чай</b> завариваеётся быстрее в горячей воде — молекулы чая активно перемешиваются.</li>'
|
||
+ '<li><b>Засолка</b> огурцов идёт долго — диффузия в жидкости медленнее, чем в газе.</li>'
|
||
+ '<li><b>Сварка</b> металлов на самом деле — диффузия атомов в твёрдом теле, очень медленная.</li>'
|
||
+ '</ul>');
|
||
|
||
/* IV-1: симуляция диффузии (свой простой газ) */
|
||
h += wgWrap('p9-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 + '">Температура $t$, °C: <b id="p9-T" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">20</b><input type="range" id="p9-T-r" min="0" max="90" step="1" value="20" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
|
||
+ '<div style="display:flex;gap:6px;align-items:center;justify-content:flex-end;padding-top:6px"><button id="p9-reset" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';padding:8px 14px;border-radius:9px;cursor:pointer;font-family:inherit;font-weight:600">Сброс</button></div>'
|
||
+ '</div>'
|
||
+ '<svg id="p9-sim" viewBox="0 0 360 160" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#cffafe;border-radius:9px;border:1px solid #67e8f9"></svg>'
|
||
+ '<div style="text-align:center;font-size:.86rem;color:#64748b;margin-top:6px">Синие молекулы — вода, тёмные — чернила. Видно, как чем теплее, тем быстрее они перемешиваются.</div>');
|
||
|
||
/* IV-2: квиз */
|
||
h += wgWrap('p9-iv2', 'КВИЗ', 'Про диффузию', 'Выбери верное.',
|
||
'<div id="p9-q-host">'
|
||
+ quizQuestion('p9-q', 0, 'В каком веществе диффузия идёт быстрее всего?', ['В твёрдом','В жидком','В газообразном','Одинаково'], 2, 'В газах молекулы движутся быстрее и расстояния между ними больше.')
|
||
+ quizQuestion('p9-q', 1, 'Как ускорить заваривание чая?', ['Понизить температуру','Налить холодной воды','Налить горячей воды','Не размешивать'], 2)
|
||
+ quizQuestion('p9-q', 2, 'Что доказывает броуновское движение?', ['Что молекулы покоятся','Что молекулы движутся','Что молекулы видны','Что молекул нет'], 1)
|
||
+ '</div>');
|
||
|
||
/* IV-3: DnD скорости */
|
||
h += wgWrap('p9-iv3', 'DnD', 'Где диффузия быстрее?', 'Распредели 6 ситуаций.',
|
||
dndPool('p9-dnd', [
|
||
{ id:'a1', cat:'fast', html:'Дым из костра в воздухе' },
|
||
{ id:'a2', cat:'fast', html:'Запах духов в комнате' },
|
||
{ id:'a3', cat:'med', html:'Сахар в горячем чае' },
|
||
{ id:'a4', cat:'med', html:'Раствор соли в воде' },
|
||
{ id:'a5', cat:'slow', html:'Сварка металлов' },
|
||
{ id:'a6', cat:'slow', html:'Свинцовая пломба со временем «врастает» в дерево' }
|
||
], [
|
||
{ cat:'fast', label:'Быстро (газ)' },
|
||
{ cat:'med', label:'Средне (жидкость)' },
|
||
{ cat:'slow', label:'Медленно (твёрдое)' }
|
||
]));
|
||
|
||
/* IV-4: тренажёр */
|
||
h += wgWrap('p9-iv4', 'ТРН', 'Тренажёр §9', '5 вопросов.',
|
||
'<div id="p9-tr-host">'
|
||
+ quizQuestion('p9-tr', 0, 'Тепловое движение — это…', ['Падение тел','Движение колеса','Хаотическое движение молекул','Движение звуковой волны'], 2)
|
||
+ quizQuestion('p9-tr', 1, 'При нагревании средняя скорость молекул…', ['Не меняется','Увеличивается','Уменьшается','Становится нулевой'], 1)
|
||
+ quizQuestion('p9-tr', 2, 'В каком случае диффузия пройдёт быстрее: в холодной или горячей воде?', ['В холодной','В горячей','Одинаково','Не зависит'], 1)
|
||
+ quizQuestion('p9-tr', 3, 'Через сколько примерно времени запах из открытого флакона духов распространится по комнате?', ['Доли секунды','За минуту-две','За сутки','За месяц'], 1, 'Диффузия в газе — относительно быстрая, но мгновенной не бывает.')
|
||
+ quizQuestion('p9-tr', 4, 'Броуновское движение — это движение…', ['Молекул','Атомов','Мельчайших видимых частиц под ударами молекул','Звуковых волн'], 2)
|
||
+ '</div>');
|
||
|
||
h += readButton('p9');
|
||
body.innerHTML = h;
|
||
|
||
// Diffusion sim
|
||
const sim = (function(){
|
||
const W = 360, H = 160;
|
||
const N = 60;
|
||
const parts = [];
|
||
function init(){
|
||
parts.length = 0;
|
||
for(let i = 0; i < N; i++){
|
||
const isInk = i < 20;
|
||
parts.push({
|
||
x: isInk ? (40 + Math.random() * 60) : (Math.random() * W),
|
||
y: isInk ? (40 + Math.random() * 60) : (Math.random() * H),
|
||
vx: 0, vy: 0,
|
||
ink: isInk
|
||
});
|
||
}
|
||
}
|
||
function step(T){
|
||
const speed = 0.4 + T / 30; // px/frame
|
||
parts.forEach(p => {
|
||
p.vx += (Math.random() - 0.5) * speed * 0.6;
|
||
p.vy += (Math.random() - 0.5) * speed * 0.6;
|
||
p.vx *= 0.92; p.vy *= 0.92;
|
||
p.x += p.vx; p.y += p.vy;
|
||
if(p.x < 2){ p.x = 2; p.vx = -p.vx; }
|
||
if(p.x > W-2){ p.x = W-2; p.vx = -p.vx; }
|
||
if(p.y < 2){ p.y = 2; p.vy = -p.vy; }
|
||
if(p.y > H-2){ p.y = H-2; p.vy = -p.vy; }
|
||
});
|
||
}
|
||
function render(){
|
||
const svg = document.getElementById('p9-sim');
|
||
if(!svg) return false;
|
||
let s = '';
|
||
parts.forEach(p => {
|
||
const c = p.ink ? '#0f172a' : '#3b82f6';
|
||
s += '<circle cx="' + p.x.toFixed(1) + '" cy="' + p.y.toFixed(1) + '" r="' + (p.ink ? 3 : 2) + '" fill="' + c + '" opacity="' + (p.ink ? 0.9 : 0.55) + '"/>';
|
||
});
|
||
svg.innerHTML = s;
|
||
return true;
|
||
}
|
||
return { init, step, render };
|
||
})();
|
||
let raf = 0;
|
||
function loop(){
|
||
const T = +document.getElementById('p9-T-r').value;
|
||
sim.step(T);
|
||
if(!sim.render()){ cancelAnimationFrame(raf); return; }
|
||
raf = requestAnimationFrame(loop);
|
||
}
|
||
sim.init();
|
||
raf = requestAnimationFrame(loop);
|
||
document.getElementById('p9-T-r').addEventListener('input', () => {
|
||
document.getElementById('p9-T').textContent = document.getElementById('p9-T-r').value;
|
||
});
|
||
document.getElementById('p9-reset').addEventListener('click', () => { sim.init(); });
|
||
|
||
wireDnd('p9-dnd', [
|
||
{ id:'a1', cat:'fast' },{ id:'a2', cat:'fast' },{ id:'a3', cat:'med' },{ id:'a4', cat:'med' },
|
||
{ id:'a5', cat:'slow' },{ id:'a6', cat:'slow' }
|
||
]);
|
||
wireQuiz('p9-q-host', () => { if(window.addXp) window.addXp(10, 'q-p9'); });
|
||
wireQuiz('p9-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p9'); });
|
||
wireReadBtn('p9');
|
||
renderMath(body);
|
||
}
|
||
|
||
/* ========================================================== */
|
||
/* §10 — Взаимодействие частиц вещества */
|
||
/* ========================================================== */
|
||
function add_p10(){
|
||
const body = document.getElementById('p10-body');
|
||
if(!body) return;
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Два вида сил между частицами', '§ 10.1',
|
||
'Между молекулами одновременно действуют <b>силы притяжения</b> и <b>силы отталкивания</b>. '
|
||
+ 'Их интенсивность зависит от расстояния:'
|
||
+ '<ul style="padding-left:20px;margin:6px 0">'
|
||
+ '<li>на <b>малом</b> расстоянии (молекулы «прижаты») — преобладает <b>отталкивание</b>;</li>'
|
||
+ '<li>на <b>равновесном</b> расстоянии $r_0$ — силы уравновешиваются;</li>'
|
||
+ '<li>на <b>большом</b> расстоянии — преобладает <b>притяжение</b>;</li>'
|
||
+ '<li>на <b>очень большом</b> — силы пренебрежимо малы.</li>'
|
||
+ '</ul>');
|
||
|
||
h += makeCard('rule', 'Зачем нужно знать про эти силы', '§ 10.2',
|
||
'Силы между молекулами объясняют:'
|
||
+ '<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>');
|
||
|
||
h += makeCard('example', 'Опыт с свинцовыми цилиндрами', '§ 10.3',
|
||
'Если две тщательно отшлифованные свинцовые поверхности сжать вместе, '
|
||
+ 'они <b>«слипнутся»</b> — их можно даже подвесить на крючок, и они не разойдутся. '
|
||
+ 'Причина — притяжение молекул на малом расстоянии. '
|
||
+ 'Через грязный или окисленный слой это не работает: молекулы не подходят достаточно близко.');
|
||
|
||
/* IV-1: график F(r) */
|
||
h += wgWrap('p10-iv1', 'СИМ', 'График сил F(r) — притяжение и отталкивание', 'Двигай молекулу — увидь, какая сила преобладает.',
|
||
'<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 + '">Расстояние $r/r_0$: <b id="p10-r" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">1.00</b><input type="range" id="p10-r-r" min="60" max="250" step="2" value="100" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
|
||
+ '<svg id="p10-svg" viewBox="0 0 380 200" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||
+ '<div id="p10-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.94rem;text-align:center"></div>');
|
||
|
||
/* IV-2: квиз */
|
||
h += wgWrap('p10-iv2', 'КВИЗ', 'Силы взаимодействия', 'Выбери верное.',
|
||
'<div id="p10-q-host">'
|
||
+ quizQuestion('p10-q', 0, 'На равновесном расстоянии $r_0$ молекулы…', ['Только притягиваются','Только отталкиваются','Притяжение и отталкивание равны','Не взаимодействуют'], 2)
|
||
+ quizQuestion('p10-q', 1, 'Почему трудно сжать жидкость?', ['Молекул мало','Молекулы уже близко — мешает отталкивание','Жидкость не имеет молекул','Притяжение слишком сильно'], 1)
|
||
+ quizQuestion('p10-q', 2, 'Почему пружина возвращается в исходную форму?', ['Из-за гравитации','Из-за сил между молекулами','Сама по себе','Из-за воздуха'], 1)
|
||
+ quizQuestion('p10-q', 3, 'На очень большом расстоянии межмолекулярные силы…', ['Очень большие','Пренебрежимо малы','Отталкивают','Колеблются'], 1)
|
||
+ '</div>');
|
||
|
||
/* IV-3: DnD */
|
||
h += wgWrap('p10-iv3', 'DnD', 'Преобладает что?', 'Сопоставь расстояние и преобладающую силу.',
|
||
dndPool('p10-dnd', [
|
||
{ id:'a1', cat:'rep', html:'Молекулы прижаты вплотную' },
|
||
{ id:'a2', cat:'rep', html:'Жидкость сжимают поршнем' },
|
||
{ id:'a3', cat:'eq', html:'$r = r_0$ (равновесие)' },
|
||
{ id:'a4', cat:'attr', html:'Растягивание стального троса' },
|
||
{ id:'a5', cat:'attr', html:'Молекулы немного раздвинуты' },
|
||
{ id:'a6', cat:'zero', html:'$r \\gg r_0$ (далеко)' }
|
||
], [
|
||
{ cat:'rep', label:'Отталкивание' },
|
||
{ cat:'eq', label:'Равновесие' },
|
||
{ cat:'attr', label:'Притяжение' },
|
||
{ cat:'zero', label:'Силы малы' }
|
||
]));
|
||
|
||
/* IV-4: тренажёр */
|
||
h += wgWrap('p10-iv4', 'ТРН', 'Тренажёр §10', '4 вопроса.',
|
||
'<div id="p10-tr-host">'
|
||
+ quizQuestion('p10-tr', 0, 'Между молекулами действуют…', ['Только притяжение','Только отталкивание','И притяжение, и отталкивание','Никаких сил'], 2)
|
||
+ quizQuestion('p10-tr', 1, 'Если молекулы оказались ближе $r_0$, то результирующая сила…', ['Отталкивает','Притягивает','Равна нулю','Не определена'], 0)
|
||
+ quizQuestion('p10-tr', 2, 'Опыт со свинцовыми цилиндрами показывает…', ['Что вещество твёрдое','Что молекулы притягиваются на близком расстоянии','Что свинец тяжёлый','Что молекулы движутся'], 1)
|
||
+ quizQuestion('p10-tr', 3, 'Силы упругости имеют ту же природу, что и…', ['Сила трения','Гравитация','Силы между молекулами','Электромагнитные волны'], 2)
|
||
+ '</div>');
|
||
|
||
h += readButton('p10');
|
||
body.innerHTML = h;
|
||
|
||
function drawF(){
|
||
const rRel = +document.getElementById('p10-r-r').value / 100; // r/r0 from 0.6 to 2.5
|
||
document.getElementById('p10-r').textContent = rRel.toFixed(2);
|
||
const W = 380, H = 200, pad = 30;
|
||
// Чертим оси r (x) и F (y)
|
||
// F(r) модельная: F = a/r^13 - b/r^7 (Lennard-Jones-like), минимум в r=1.
|
||
function F(r){ return 12/Math.pow(r,13) - 12/Math.pow(r,7); }
|
||
let s = '';
|
||
// Оси
|
||
s += '<line x1="' + pad + '" y1="' + (H/2) + '" x2="' + (W-pad+10) + '" y2="' + (H/2) + '" stroke="#0f172a" stroke-width="1.5"/>';
|
||
s += '<line x1="' + pad + '" y1="20" x2="' + pad + '" y2="' + (H-20) + '" stroke="#0f172a" stroke-width="1.5"/>';
|
||
s += '<text x="' + (W-pad+8) + '" y="' + (H/2 + 12) + '" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">r</text>';
|
||
s += '<text x="' + (pad+4) + '" y="20" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">F</text>';
|
||
// r=r0
|
||
const r0X = pad + (W - 2*pad) * (1 - 0.6) / (2.5 - 0.6);
|
||
s += '<line x1="' + r0X.toFixed(1) + '" y1="20" x2="' + r0X.toFixed(1) + '" y2="' + (H-20) + '" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3 2"/>';
|
||
s += '<text x="' + r0X.toFixed(1) + '" y="' + (H-6) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" fill="#64748b">r₀</text>';
|
||
// Кривая F(r)
|
||
let path = '';
|
||
for(let i = 0; i <= 60; i++){
|
||
const r = 0.6 + (2.5 - 0.6) * i / 60;
|
||
const f = F(r);
|
||
const fClamped = Math.max(-2, Math.min(4, f));
|
||
const x = pad + (W - 2*pad) * (r - 0.6) / (2.5 - 0.6);
|
||
const y = H/2 - fClamped * 18;
|
||
path += (i === 0 ? 'M' : 'L') + x.toFixed(1) + ' ' + y.toFixed(1) + ' ';
|
||
}
|
||
s += '<path d="' + path + '" fill="none" stroke="' + ACCENT + '" stroke-width="2.5"/>';
|
||
// Текущая точка
|
||
const curX = pad + (W - 2*pad) * (rRel - 0.6) / (2.5 - 0.6);
|
||
const curF = Math.max(-2, Math.min(4, F(rRel)));
|
||
const curY = H/2 - curF * 18;
|
||
s += '<circle cx="' + curX.toFixed(1) + '" cy="' + curY.toFixed(1) + '" r="6" fill="#dc2626" stroke="#fff" stroke-width="2"/>';
|
||
s += '<line x1="' + curX.toFixed(1) + '" y1="' + (H/2) + '" x2="' + curX.toFixed(1) + '" y2="' + curY.toFixed(1) + '" stroke="#dc2626" stroke-width="1.5" stroke-dasharray="2 2"/>';
|
||
// Подписи областей
|
||
s += '<text x="' + (pad + 30) + '" y="40" font-family="Inter,sans-serif" font-size="10" fill="#dc2626" font-weight="700">отталкивание</text>';
|
||
s += '<text x="' + (W - pad - 60) + '" y="' + (H - 40) + '" font-family="Inter,sans-serif" font-size="10" fill="#10b981" font-weight="700">притяжение</text>';
|
||
|
||
document.getElementById('p10-svg').innerHTML = s;
|
||
|
||
// Info
|
||
const fVal = F(rRel);
|
||
let label;
|
||
if(rRel < 0.95) label = '<b style="color:#dc2626">Отталкивание</b> (молекулы слишком близко).';
|
||
else if(rRel < 1.05) label = '<b style="color:#0c4a6e">Равновесие</b>: силы уравновешены, $F \\approx 0$.';
|
||
else if(rRel < 1.6) label = '<b style="color:#10b981">Притяжение</b> (молекулы стремятся вернуться).';
|
||
else label = '<b style="color:#64748b">Силы малы</b>: молекулы почти не взаимодействуют.';
|
||
document.getElementById('p10-info').innerHTML = '$r/r_0 = ' + rRel.toFixed(2) + '$ · ' + label;
|
||
renderMath(document.getElementById('p10-info'));
|
||
}
|
||
document.getElementById('p10-r-r').addEventListener('input', drawF);
|
||
drawF();
|
||
|
||
wireDnd('p10-dnd', [
|
||
{ id:'a1', cat:'rep' },{ id:'a2', cat:'rep' },{ id:'a3', cat:'eq' },
|
||
{ id:'a4', cat:'attr' },{ id:'a5', cat:'attr' },{ id:'a6', cat:'zero' }
|
||
]);
|
||
wireQuiz('p10-q-host', () => { if(window.addXp) window.addXp(10, 'q-p10'); });
|
||
wireQuiz('p10-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p10'); });
|
||
wireReadBtn('p10');
|
||
renderMath(body);
|
||
}
|
||
|
||
/* ========================================================== */
|
||
/* §11 — Газообразное, жидкое, твёрдое состояния */
|
||
/* ГЛАВНЫЙ ВИЗУАЛ ГЛАВЫ 2: переключатель состояний с анимацией */
|
||
/* ========================================================== */
|
||
function add_p11(){
|
||
const body = document.getElementById('p11-body');
|
||
if(!body) return;
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Три состояния — три поведения частиц', '§ 11.1',
|
||
'<b>Одно и то же вещество</b> может находиться в трёх состояниях. Различие — в том, '
|
||
+ 'как расположены и движутся его молекулы:'
|
||
+ '<table style="width:100%;border-collapse:collapse;margin-top:8px;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:left;border-bottom:2px solid ' + ACCENT + '">Форма</th><th style="padding:6px 10px;text-align:left;border-bottom:2px solid ' + ACCENT + '">Объём</th></tr>'
|
||
+ '<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '"><b>Твёрдое</b></td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">сохраняет</td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">сохраняет</td></tr>'
|
||
+ '<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '"><b>Жидкое</b></td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">принимает форму сосуда</td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">сохраняет</td></tr>'
|
||
+ '<tr><td style="padding:5px 10px"><b>Газообразное</b></td><td style="padding:5px 10px">заполняет весь сосуд</td><td style="padding:5px 10px">не сохраняет</td></tr>'
|
||
+ '</table>');
|
||
|
||
h += makeCard('rule', 'Чем отличается поведение молекул', '§ 11.2',
|
||
'<ul style="padding-left:20px;margin:6px 0;line-height:1.7">'
|
||
+ '<li><b>Твёрдое</b>: молекулы в узлах кристаллической решётки; колеблются около положений равновесия. Притяжение сильное.</li>'
|
||
+ '<li><b>Жидкое</b>: молекулы упакованы плотно, но <i>«перескакивают»</i> с места на место. Промежутки малы — несжимаема, но течёт.</li>'
|
||
+ '<li><b>Газообразное</b>: молекулы летают почти свободно на больших расстояниях. Силы притяжения слабые. Газ занимает <b>весь</b> предоставленный объём.</li>'
|
||
+ '</ul>');
|
||
|
||
h += makeCard('example', 'Вода — все три состояния', '§ 11.3',
|
||
'Удивительно: одна и та же $\\text{H}_2\\text{O}$ существует во всех трёх состояниях:'
|
||
+ '<ul style="padding-left:20px;margin:6px 0">'
|
||
+ '<li><b>Лёд</b> (твёрдое) — при $t < 0$ °C. Сохраняет форму, можно расколоть.</li>'
|
||
+ '<li><b>Вода</b> (жидкое) — от $0$ до $100$ °C. Принимает форму сосуда.</li>'
|
||
+ '<li><b>Пар</b> (газообразное) — при $t > 100$ °C. Заполняет всё пространство.</li>'
|
||
+ '</ul>'
|
||
+ 'Сами молекулы при переходе <b>не меняются</b> — меняется лишь характер их движения и расположения.');
|
||
|
||
/* IV-1: ГЛАВНЫЙ ВИЗУАЛ — переключатель 3 состояний с симуляцией МКТ */
|
||
h += wgWrap('p11-iv1', 'СИМ', 'Молекулы в трёх состояниях', 'Переключай состояние — смотри, как меняется поведение частиц.',
|
||
'<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
|
||
+ ['solid','liquid','gas'].map((st, i) => {
|
||
const labels = ['Твёрдое', 'Жидкое', 'Газ'];
|
||
const colors = ['#4f46e5', '#0891b2', '#94a3b8'];
|
||
return '<button class="p11-st" data-st="' + st + '" type="button" style="background:#fff;border:2px solid ' + colors[i] + ';color:' + colors[i] + ';padding:8px 18px;border-radius:9px;cursor:pointer;font-weight:700;font-size:.9rem;font-family:inherit">' + labels[i] + '</button>';
|
||
}).join('')
|
||
+ '</div>'
|
||
+ '<svg id="p11-sim" viewBox="0 0 360 180" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||
+ '<div id="p11-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;line-height:1.55"></div>');
|
||
|
||
/* IV-2: квиз */
|
||
h += wgWrap('p11-iv2', 'КВИЗ', 'Свойства состояний', '',
|
||
'<div id="p11-q-host">'
|
||
+ quizQuestion('p11-q', 0, 'Какое состояние сохраняет и форму, и объём?', ['Твёрдое','Жидкое','Газообразное','Все три'], 0)
|
||
+ quizQuestion('p11-q', 1, 'Газ занимает…', ['Только дно сосуда','Половину сосуда','Весь сосуд','Часть, равную массе'], 2)
|
||
+ quizQuestion('p11-q', 2, 'Жидкость принимает форму…', ['Любую','Сосуда','Кубическую','Шарообразную'], 1)
|
||
+ quizQuestion('p11-q', 3, 'В каком состоянии молекулы движутся быстрее всего?', ['В твёрдом','В жидком','В газообразном','Одинаково'], 2)
|
||
+ '</div>');
|
||
|
||
/* IV-3: DnD */
|
||
h += wgWrap('p11-iv3', 'DnD', 'Что в каком состоянии?', 'Распредели 9 примеров.',
|
||
dndPool('p11-dnd', [
|
||
{ id:'a1', cat:'sol', html:'Камень' },
|
||
{ id:'a2', cat:'sol', html:'Лёд' },
|
||
{ id:'a3', cat:'sol', html:'Железо' },
|
||
{ id:'a4', cat:'liq', html:'Молоко' },
|
||
{ id:'a5', cat:'liq', html:'Бензин' },
|
||
{ id:'a6', cat:'liq', html:'Расплавленный воск' },
|
||
{ id:'a7', cat:'gas', html:'Воздух' },
|
||
{ id:'a8', cat:'gas', html:'Водяной пар' },
|
||
{ id:'a9', cat:'gas', html:'Углекислый газ' }
|
||
], [
|
||
{ cat:'sol', label:'Твёрдое' },
|
||
{ cat:'liq', label:'Жидкое' },
|
||
{ cat:'gas', label:'Газообразное' }
|
||
]));
|
||
|
||
/* IV-4: тренажёр */
|
||
h += wgWrap('p11-iv4', 'ТРН', 'Тренажёр §11', '5 вопросов.',
|
||
'<div id="p11-tr-host">'
|
||
+ quizQuestion('p11-tr', 0, 'Можно ли сжать газ в 2 раза в плотно закрытом шприце?', ['Нет','Да, легко','Только при высокой температуре','Только при очень низкой'], 1)
|
||
+ quizQuestion('p11-tr', 1, 'Жидкость практически не сжимается, потому что…', ['Молекул мало','Молекулы уже плотно упакованы','Жидкости лёгкие','Молекулы неподвижны'], 1)
|
||
+ quizQuestion('p11-tr', 2, 'В каком состоянии вещества молекулы располагаются в строгом порядке (кристалл)?', ['Твёрдое','Жидкое','Газообразное','Ни в каком'], 0)
|
||
+ quizQuestion('p11-tr', 3, 'При переходе из льда в воду молекулы $\\text{H}_2\\text{O}$…', ['Распадаются','Превращаются в другие','Остаются теми же, меняется лишь их движение','Исчезают'], 2)
|
||
+ quizQuestion('p11-tr', 4, '$0{,}5$ л воды налили в банку $1$ л. Какой объём займёт вода?', ['0,5 л','1 л','0,75 л','Зависит от формы'], 0, 'Жидкость сохраняет свой объём — только форму она меняет.')
|
||
+ '</div>');
|
||
|
||
h += readButton('p11');
|
||
body.innerHTML = h;
|
||
|
||
// Wire 3-state simulator
|
||
const st11 = (function(){
|
||
const W = 360, H = 180, N = 50;
|
||
let state = 'solid';
|
||
const parts = [];
|
||
for(let i = 0; i < N; i++) parts.push({ x:0, y:0, vx:0, vy:0, hx:0, hy:0 });
|
||
function reset(){
|
||
if(state === 'solid'){
|
||
// Кристаллическая решётка 10×5
|
||
for(let i = 0; i < N; i++){
|
||
const r = Math.floor(i/10), c = i % 10;
|
||
parts[i].hx = 40 + c * 28;
|
||
parts[i].hy = 40 + r * 28;
|
||
parts[i].x = parts[i].hx; parts[i].y = parts[i].hy;
|
||
parts[i].vx = 0; parts[i].vy = 0;
|
||
}
|
||
} else if(state === 'liquid'){
|
||
// Жидкость — занимает нижнюю половину
|
||
for(let i = 0; i < N; i++){
|
||
parts[i].x = 20 + Math.random() * (W - 40);
|
||
parts[i].y = H/2 + Math.random() * (H/2 - 10);
|
||
parts[i].vx = (Math.random() - 0.5) * 1;
|
||
parts[i].vy = (Math.random() - 0.5) * 1;
|
||
}
|
||
} else { // gas
|
||
for(let i = 0; i < N; i++){
|
||
parts[i].x = 10 + Math.random() * (W - 20);
|
||
parts[i].y = 10 + Math.random() * (H - 20);
|
||
const ang = Math.random() * Math.PI * 2;
|
||
parts[i].vx = Math.cos(ang) * 2.5;
|
||
parts[i].vy = Math.sin(ang) * 2.5;
|
||
}
|
||
}
|
||
}
|
||
function step(){
|
||
if(state === 'solid'){
|
||
for(let i = 0; i < N; i++){
|
||
parts[i].x = parts[i].hx + (Math.random() - 0.5) * 3;
|
||
parts[i].y = parts[i].hy + (Math.random() - 0.5) * 3;
|
||
}
|
||
} else if(state === 'liquid'){
|
||
for(let i = 0; i < N; i++){
|
||
parts[i].vx += (Math.random() - 0.5) * 0.3;
|
||
parts[i].vy += (Math.random() - 0.5) * 0.3;
|
||
parts[i].vx *= 0.93; parts[i].vy *= 0.93;
|
||
parts[i].x += parts[i].vx; parts[i].y += parts[i].vy;
|
||
// Притяжение к дну (как жидкость)
|
||
parts[i].vy += 0.1;
|
||
if(parts[i].x < 6){ parts[i].x = 6; parts[i].vx = -parts[i].vx; }
|
||
if(parts[i].x > W-6){ parts[i].x = W-6; parts[i].vx = -parts[i].vx; }
|
||
if(parts[i].y < H/2 + 6){ parts[i].y = H/2 + 6; parts[i].vy = Math.abs(parts[i].vy)*0.5; }
|
||
if(parts[i].y > H-6){ parts[i].y = H-6; parts[i].vy = -Math.abs(parts[i].vy)*0.7; }
|
||
}
|
||
} else {
|
||
for(let i = 0; i < N; i++){
|
||
parts[i].x += parts[i].vx; parts[i].y += parts[i].vy;
|
||
if(parts[i].x < 6){ parts[i].x = 6; parts[i].vx = -parts[i].vx; }
|
||
if(parts[i].x > W-6){ parts[i].x = W-6; parts[i].vx = -parts[i].vx; }
|
||
if(parts[i].y < 6){ parts[i].y = 6; parts[i].vy = -parts[i].vy; }
|
||
if(parts[i].y > H-6){ parts[i].y = H-6; parts[i].vy = -parts[i].vy; }
|
||
}
|
||
}
|
||
}
|
||
function render(){
|
||
const svg = document.getElementById('p11-sim');
|
||
if(!svg) return false;
|
||
let s = '';
|
||
// Контур сосуда
|
||
s += '<rect x="2" y="2" width="' + (W-4) + '" height="' + (H-4) + '" fill="none" stroke="' + ACCENT_D + '" stroke-width="1.5" stroke-dasharray="4 3" rx="6"/>';
|
||
// Уровень жидкости — линия
|
||
if(state === 'liquid'){
|
||
s += '<line x1="3" y1="' + (H/2) + '" x2="' + (W-3) + '" y2="' + (H/2) + '" stroke="#0891b2" stroke-width="1.5"/>';
|
||
}
|
||
const col = state === 'solid' ? '#4f46e5' : (state === 'liquid' ? '#0891b2' : '#64748b');
|
||
parts.forEach(p => {
|
||
s += '<circle cx="' + p.x.toFixed(1) + '" cy="' + p.y.toFixed(1) + '" r="4" fill="' + col + '" stroke="#0f172a" stroke-width="0.6" opacity="0.9"/>';
|
||
});
|
||
svg.innerHTML = s;
|
||
return true;
|
||
}
|
||
return {
|
||
setState(st){ state = st; reset(); updateInfo(); },
|
||
step, render, getState(){ return state; }
|
||
};
|
||
})();
|
||
function updateInfo(){
|
||
const st = st11.getState();
|
||
const descs = {
|
||
solid: '<b style="color:#4f46e5">Твёрдое:</b> молекулы в узлах решётки, только колеблются. Форма и объём сохраняются.',
|
||
liquid: '<b style="color:#0891b2">Жидкость:</b> молекулы плотно упакованы и «перескакивают». Объём сохраняется, форма — нет.',
|
||
gas: '<b style="color:#64748b">Газ:</b> молекулы летают свободно. Ни форма, ни объём не сохраняются — газ занимает весь сосуд.'
|
||
};
|
||
document.getElementById('p11-info').innerHTML = descs[st];
|
||
}
|
||
body.querySelectorAll('.p11-st').forEach(btn => btn.addEventListener('click', () => {
|
||
body.querySelectorAll('.p11-st').forEach(b => { b.style.background = '#fff'; b.style.color = b.style.borderColor; });
|
||
btn.style.background = btn.style.borderColor; btn.style.color = '#fff';
|
||
st11.setState(btn.dataset.st);
|
||
}));
|
||
st11.setState('solid');
|
||
body.querySelector('.p11-st[data-st="solid"]').style.background = '#4f46e5';
|
||
body.querySelector('.p11-st[data-st="solid"]').style.color = '#fff';
|
||
let raf11 = 0;
|
||
function loop11(){
|
||
st11.step();
|
||
if(!st11.render()){ cancelAnimationFrame(raf11); return; }
|
||
raf11 = requestAnimationFrame(loop11);
|
||
}
|
||
raf11 = requestAnimationFrame(loop11);
|
||
|
||
wireDnd('p11-dnd', [
|
||
{ id:'a1', cat:'sol' },{ id:'a2', cat:'sol' },{ id:'a3', cat:'sol' },
|
||
{ id:'a4', cat:'liq' },{ id:'a5', cat:'liq' },{ id:'a6', cat:'liq' },
|
||
{ id:'a7', cat:'gas' },{ id:'a8', cat:'gas' },{ id:'a9', cat:'gas' }
|
||
]);
|
||
wireQuiz('p11-q-host', () => { if(window.addXp) window.addXp(10, 'q-p11'); });
|
||
wireQuiz('p11-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p11'); });
|
||
wireReadBtn('p11');
|
||
renderMath(body);
|
||
}
|
||
|
||
/* ========================================================== */
|
||
/* §12 — Тепловое расширение */
|
||
/* ========================================================== */
|
||
function add_p12(){
|
||
const body = document.getElementById('p12-body');
|
||
if(!body) return;
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Почему тела расширяются при нагреве', '§ 12.1',
|
||
'При нагревании молекулы движутся быстрее и амплитуда их колебаний возрастает. '
|
||
+ 'Среднее расстояние между молекулами <b>увеличивается</b> — тело расширяется. '
|
||
+ 'При охлаждении наоборот: тело сжимается.<br><br>'
|
||
+ 'Тепловое расширение есть у <b>всех</b> веществ — твёрдых, жидких и газообразных. '
|
||
+ 'Сильнее всех расширяются газы, меньше всех — твёрдые тела.');
|
||
|
||
h += makeCard('rule', 'Где это важно учитывать', '§ 12.2',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+ '<li><b>Рельсы</b> укладывают с зазорами — летом сталь удлиняется.</li>'
|
||
+ '<li><b>Мосты</b> опирают через катки или прокладки — иначе бы трескались.</li>'
|
||
+ '<li><b>Провода ЛЭП</b> летом провисают сильнее, чем зимой.</li>'
|
||
+ '<li><b>Биметаллическая пластина</b> — два металла спаяны вместе, гнётся от температуры. Используется в утюгах и термостатах.</li>'
|
||
+ '</ul>');
|
||
|
||
h += makeCard('example', 'Аномалия воды', '§ 12.3',
|
||
'Большинство веществ при нагревании расширяются. Но у воды есть <b>исключение</b>: '
|
||
+ 'при $t$ от $0$ до $+4$ °C она <b>сжимается</b>, а только начиная с $+4$ °C — расширяется. '
|
||
+ 'Поэтому самая плотная вода — при $+4$ °C; она опускается на дно водоёма. '
|
||
+ 'Это <b>спасает</b> жизнь в озёрах зимой: лёд плавает сверху, а под ним вода с $+4$ °C, где могут жить рыбы.');
|
||
|
||
/* IV-1: расширение стержня + биметалла */
|
||
h += wgWrap('p12-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 + '">Нагрев $\\Delta T$, °C: <b id="p12-T" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">50</b><input type="range" id="p12-T-r" min="0" max="200" step="5" value="50" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
|
||
+ '<svg id="p12-svg" viewBox="0 0 380 140" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||
+ '<div id="p12-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.9rem;text-align:center"></div>');
|
||
|
||
/* IV-2: биметалл */
|
||
h += wgWrap('p12-iv2', 'СИМ', 'Биметаллическая пластина', 'Два металла расширяются по-разному — пластина гнётся.',
|
||
'<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 + '">Нагрев $\\Delta T$, °C: <b id="p12b-T" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">60</b><input type="range" id="p12b-T-r" min="-50" max="100" step="5" value="60" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
|
||
+ '<svg id="p12b-svg" viewBox="0 0 280 200" width="100%" style="max-width:400px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
|
||
+ '<div style="text-align:center;font-size:.84rem;color:#64748b;margin-top:6px">Жёлтый слой — латунь (сильнее расширяется), серый — сталь. Принцип термостата.</div>');
|
||
|
||
/* IV-3: DnD */
|
||
h += wgWrap('p12-iv3', 'DnD', 'Кто сильнее расширяется?', 'Расставь по убыванию теплового расширения.',
|
||
dndPool('p12-dnd', [
|
||
{ id:'a1', cat:'gas', html:'Воздух в шарике' },
|
||
{ id:'a2', cat:'gas', html:'Гелий в баллоне' },
|
||
{ id:'a3', cat:'liq', html:'Спирт в термометре' },
|
||
{ id:'a4', cat:'liq', html:'Ртуть в термометре' },
|
||
{ id:'a5', cat:'sol', html:'Железный рельс' },
|
||
{ id:'a6', cat:'sol', html:'Кварцевое стекло' }
|
||
], [
|
||
{ cat:'gas', label:'Сильно (газ)' },
|
||
{ cat:'liq', label:'Средне (жидкость)' },
|
||
{ cat:'sol', label:'Слабо (твёрдое)' }
|
||
]));
|
||
|
||
/* IV-4: тренажёр */
|
||
h += wgWrap('p12-iv4', 'ТРН', 'Тренажёр §12', '5 вопросов.',
|
||
'<div id="p12-tr-host">'
|
||
+ quizQuestion('p12-tr', 0, 'Почему между рельсами оставляют зазоры?', ['Для экономии металла','Чтобы рельсы могли расширяться летом','Для прохода животных','Не оставляют, это миф'], 1)
|
||
+ quizQuestion('p12-tr', 1, 'При охлаждении тело…', ['Расширяется','Сжимается','Не меняется','Может то и другое'], 1)
|
||
+ quizQuestion('p12-tr', 2, 'У какой воды максимальная плотность?', ['При 0 °C','При +4 °C','При +100 °C','Не зависит от t'], 1, 'Это уникальная аномалия воды — спасает водоёмы зимой.')
|
||
+ quizQuestion('p12-tr', 3, 'Биметаллическая пластина при нагревании…', ['Не изменяется','Гнётся в одну сторону','Гнётся в случайную сторону','Распадается'], 1, 'Один металл расширяется сильнее, и пластина изгибается.')
|
||
+ quizQuestion('p12-tr', 4, 'Что сильнее расширяется при $\\Delta T = 50$ °C?', ['Стальной стержень','Воздушный шарик','Кварц','Лёд'], 1, 'Газы расширяются в сотни раз сильнее твёрдых тел.')
|
||
+ '</div>');
|
||
|
||
h += readButton('p12');
|
||
body.innerHTML = h;
|
||
|
||
// §12 IV-1
|
||
function drawRod(){
|
||
const dT = +document.getElementById('p12-T-r').value;
|
||
document.getElementById('p12-T').textContent = dT;
|
||
const W = 380, baseLen = 200, alpha = 12e-6; // сталь
|
||
const dl = baseLen * alpha * dT * 200; // визуально усилено
|
||
const len = baseLen + dl;
|
||
const y = 60, h = 22;
|
||
const x = 30;
|
||
// Цвет = функция температуры (0..200 → синий → красный)
|
||
const hue = 240 - 240 * Math.min(1, dT / 200);
|
||
const col = 'hsl(' + hue + ',70%,55%)';
|
||
let s = '';
|
||
// Базовая длина — пунктир
|
||
s += '<rect x="' + x + '" y="' + (y-3) + '" width="' + baseLen + '" height="' + (h+6) + '" fill="none" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3 2" rx="3"/>';
|
||
// Реальный стержень
|
||
s += '<rect x="' + x + '" y="' + y + '" width="' + len.toFixed(1) + '" height="' + h + '" fill="' + col + '" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
|
||
// Подписи
|
||
s += '<text x="' + (x + baseLen/2) + '" y="' + (y - 8) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" fill="#64748b">базовая длина (при 0 °C)</text>';
|
||
if(Math.abs(dl) > 1){
|
||
s += '<line x1="' + (x + baseLen) + '" y1="' + (y + h + 8) + '" x2="' + (x + len) + '" y2="' + (y + h + 8) + '" stroke="#dc2626" stroke-width="2"/>';
|
||
s += '<text x="' + (x + baseLen + dl/2) + '" y="' + (y + h + 24) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#dc2626">Δl = ' + dl.toFixed(1) + ' px</text>';
|
||
}
|
||
document.getElementById('p12-svg').innerHTML = s;
|
||
const realDl = (baseLen * alpha * dT * 100).toFixed(3); // реалистично в мм для l0=1 м
|
||
document.getElementById('p12-info').innerHTML = 'Сталь, $l_0 = 1$ м, нагрев на $\\Delta T = ' + dT + '$ °C: реально удлинится примерно на $' + (alpha * 1000 * dT).toFixed(3) + '$ мм (масштаб усилен).';
|
||
renderMath(document.getElementById('p12-info'));
|
||
}
|
||
document.getElementById('p12-T-r').addEventListener('input', drawRod);
|
||
drawRod();
|
||
|
||
// §12 IV-2 биметалл
|
||
function drawBimet(){
|
||
const dT = +document.getElementById('p12b-T-r').value;
|
||
document.getElementById('p12b-T').textContent = dT;
|
||
const ang = Math.max(-30, Math.min(30, -dT * 0.3));
|
||
const cx = 140, cy = 50;
|
||
let s = '';
|
||
// Опора
|
||
s += '<rect x="' + (cx - 30) + '" y="' + (cy - 8) + '" width="60" height="8" fill="#475569" stroke="#0f172a" stroke-width="1"/>';
|
||
// Пластина с поворотом
|
||
s += '<g transform="translate(' + cx + ',' + cy + ') rotate(' + ang + ')">';
|
||
s += '<rect x="0" y="0" width="120" height="10" fill="#fbbf24" stroke="#92400e" stroke-width="1"/>';
|
||
s += '<rect x="0" y="10" width="120" height="10" fill="#94a3b8" stroke="#374151" stroke-width="1"/>';
|
||
s += '<text x="60" y="38" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" font-weight="600" fill="#374151">Δt = ' + dT + ' °C</text>';
|
||
s += '</g>';
|
||
// Подписи цветов
|
||
s += '<rect x="10" y="180" width="14" height="6" fill="#fbbf24"/>';
|
||
s += '<text x="28" y="187" font-family="Inter,sans-serif" font-size="9" fill="#374151">латунь (сильнее расширяется)</text>';
|
||
s += '<rect x="10" y="190" width="14" height="6" fill="#94a3b8"/>';
|
||
s += '<text x="28" y="197" font-family="Inter,sans-serif" font-size="9" fill="#374151">сталь</text>';
|
||
document.getElementById('p12b-svg').innerHTML = s;
|
||
}
|
||
document.getElementById('p12b-T-r').addEventListener('input', drawBimet);
|
||
drawBimet();
|
||
|
||
wireDnd('p12-dnd', [
|
||
{ id:'a1', cat:'gas' },{ id:'a2', cat:'gas' },{ id:'a3', cat:'liq' },
|
||
{ id:'a4', cat:'liq' },{ id:'a5', cat:'sol' },{ id:'a6', cat:'sol' }
|
||
]);
|
||
wireQuiz('p12-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p12'); });
|
||
wireReadBtn('p12');
|
||
renderMath(body);
|
||
}
|
||
|
||
/* ========================================================== */
|
||
/* §13 — Температура. Термометры */
|
||
/* ========================================================== */
|
||
function add_p13(){
|
||
const body = document.getElementById('p13-body');
|
||
if(!body) return;
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Что такое температура', '§ 13.1',
|
||
'<b>Температура</b> — физическая величина, которая характеризует степень нагретости тела. '
|
||
+ 'Чем быстрее в среднем движутся молекулы — тем выше температура.<br><br>'
|
||
+ 'Обозначается $t$ (или $T$), измеряется в <b>градусах Цельсия</b> ($°C$). '
|
||
+ 'В физике также используют <b>Кельвины</b> ($K$); связь: $T = t + 273{,}15$.');
|
||
|
||
h += makeCard('rule', 'Шкала Цельсия', '§ 13.2',
|
||
'Шкала строится по двум опорным точкам:'
|
||
+ '<ul style="padding-left:20px;margin:6px 0">'
|
||
+ '<li><b>$0$ °C</b> — температура таяния льда (при нормальном давлении);</li>'
|
||
+ '<li><b>$100$ °C</b> — температура кипения чистой воды (при нормальном давлении).</li>'
|
||
+ '</ul>'
|
||
+ 'Промежуток разбит на $100$ равных частей — отсюда «градус Цельсия».');
|
||
|
||
h += makeCard('example', 'Виды термометров', '§ 13.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+ '<li><b>Жидкостный</b> (спирт, ртуть) — расширение жидкости в капилляре. От $-40$ до $+50$ °C — бытовой; до $+300$ °C — ртутный лабораторный.</li>'
|
||
+ '<li><b>Биметаллический</b> — стрелка двигается за счёт изгиба пластины. На печках, духовках.</li>'
|
||
+ '<li><b>Электронный</b> — термопара или термистор + дисплей. От $-200$ до $+1000$ °C.</li>'
|
||
+ '<li><b>Инфракрасный (пирометр)</b> — измеряет тепловое излучение без контакта. До тысяч °C.</li>'
|
||
+ '</ul>');
|
||
|
||
/* IV-1: виртуальный термометр */
|
||
h += wgWrap('p13-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 + '">Температура $t$, °C: <b id="p13-t" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">22</b><input type="range" id="p13-t-r" min="-50" max="150" step="1" value="22" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
|
||
+ '<div style="display:grid;grid-template-columns:140px 1fr;gap:14px;align-items:center">'
|
||
+ '<svg id="p13-svg" viewBox="0 0 100 220" width="100%" style="max-width:140px"></svg>'
|
||
+ '<div id="p13-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.92rem;line-height:1.65"></div>'
|
||
+ '</div>');
|
||
|
||
/* IV-2: конвертер °C ↔ K */
|
||
h += wgWrap('p13-iv2', 'КАЛЬК', 'Конвертер °C ↔ K', 'Кельвин и Цельсий — две шкалы для одной температуры.',
|
||
'<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 + '">$t$, °C: <b id="p13c-c" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">25</b><input type="range" id="p13c-c-r" min="-273" max="500" step="1" value="25" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
|
||
+ '<div style="background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + ';font-size:.86rem;color:#475569">'
|
||
+ '$T = t + 273{,}15 = $ <b id="p13c-k" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">298,15</b> K'
|
||
+ '<div style="font-size:.78rem;color:#64748b;margin-top:4px">Абсолютный нуль: $T = 0$ K $= -273{,}15$ °C — теоретический предел холода.</div>'
|
||
+ '</div>'
|
||
+ '</div>');
|
||
|
||
/* IV-3: DnD температуры */
|
||
h += wgWrap('p13-iv3', 'DnD', 'Соотнеси температуру и объект', '',
|
||
dndPool('p13-dnd', [
|
||
{ id:'a1', cat:'cold', html:'$-180$ °C' },
|
||
{ id:'a2', cat:'cold', html:'$-15$ °C' },
|
||
{ id:'a3', cat:'room', html:'$+20$ °C' },
|
||
{ id:'a4', cat:'room', html:'$+37$ °C' },
|
||
{ id:'a5', cat:'hot', html:'$+100$ °C' },
|
||
{ id:'a6', cat:'hot', html:'$+1500$ °C' }
|
||
], [
|
||
{ cat:'cold', label:'Холод (морозильник / жидкий азот)' },
|
||
{ cat:'room', label:'Норма (комната / тело человека)' },
|
||
{ cat:'hot', label:'Горячо (кипяток / расплав металла)' }
|
||
]));
|
||
|
||
/* IV-4: тренажёр */
|
||
h += wgWrap('p13-iv4', 'ТРН', 'Тренажёр §13', '5 вопросов.',
|
||
'<div id="p13-tr-host">'
|
||
+ quizQuestion('p13-tr', 0, 'Температура $t = 0$ °C соответствует…', ['Таянию льда','Кипению воды','Замерзанию ртути','Абсолютному нулю'], 0)
|
||
+ quizQuestion('p13-tr', 1, 'Сколько Кельвинов в $0$ °C?', ['0','100','273,15','373,15'], 2, '$T = 0 + 273{,}15 = 273{,}15$ K.')
|
||
+ quizQuestion('p13-tr', 2, 'В каком термометре используется расширение жидкости?', ['Биметаллическом','Электронном','Жидкостном (спиртовом/ртутном)','Инфракрасном'], 2)
|
||
+ quizQuestion('p13-tr', 3, 'Тело человека: $36{,}6$ °C $= ?$ K', ['36,6','273,15','309,75','310'], 2, '$T = 36{,}6 + 273{,}15 \\approx 309{,}75$ K.')
|
||
+ quizQuestion('p13-tr', 4, 'Может ли быть температура $-300$ °C?', ['Да','Нет, ниже -273,15 °C ничего не бывает','Только в космосе','Только в опытах'], 1)
|
||
+ '</div>');
|
||
|
||
h += readButton('p13');
|
||
body.innerHTML = h;
|
||
|
||
// §13 IV-1 thermometer
|
||
function drawTherm(){
|
||
const t = +document.getElementById('p13-t-r').value;
|
||
document.getElementById('p13-t').textContent = t;
|
||
const W = 100, H = 220;
|
||
const xC = 50, tubeTop = 20, tubeBot = 180, tubeW = 14;
|
||
const minT = -50, maxT = 150;
|
||
const frac = Math.max(0, Math.min(1, (t - minT) / (maxT - minT)));
|
||
const colTop = tubeBot - (tubeBot - tubeTop) * frac;
|
||
// Резервуар
|
||
const bulbR = 18;
|
||
const bulbY = 196;
|
||
let s = '';
|
||
s += '<rect x="' + (xC - tubeW/2 - 2) + '" y="' + tubeTop + '" width="' + (tubeW + 4) + '" height="' + (tubeBot - tubeTop + 6) + '" fill="#fff" stroke="#0f172a" stroke-width="1.5" rx="' + tubeW/2 + '"/>';
|
||
s += '<circle cx="' + xC + '" cy="' + bulbY + '" r="' + bulbR + '" fill="#fff" stroke="#0f172a" stroke-width="1.5"/>';
|
||
// Столбик
|
||
const hue = 240 - 240 * frac;
|
||
const col = 'hsl(' + hue + ',75%,50%)';
|
||
s += '<rect x="' + (xC - tubeW/2 + 2) + '" y="' + colTop + '" width="' + (tubeW - 4) + '" height="' + (tubeBot - colTop + 8) + '" fill="' + col + '"/>';
|
||
s += '<circle cx="' + xC + '" cy="' + bulbY + '" r="' + (bulbR - 4) + '" fill="' + col + '"/>';
|
||
// Шкала
|
||
for(let T = minT; T <= maxT; T += 10){
|
||
const y = tubeBot - (tubeBot - tubeTop) * (T - minT) / (maxT - minT);
|
||
const isBig = T % 50 === 0 || T === 0 || T === 100;
|
||
s += '<line x1="' + (xC + tubeW/2 + 4) + '" y1="' + y + '" x2="' + (xC + tubeW/2 + (isBig ? 12 : 8)) + '" y2="' + y + '" stroke="#0f172a" stroke-width="' + (isBig ? 1.5 : 1) + '"/>';
|
||
if(isBig) s += '<text x="' + (xC + tubeW/2 + 15) + '" y="' + (y + 3) + '" font-family="Inter,sans-serif" font-size="9" font-weight="600" fill="#0f172a">' + T + '</text>';
|
||
}
|
||
// Указатель текущей
|
||
const tY = tubeBot - (tubeBot - tubeTop) * (t - minT) / (maxT - minT);
|
||
s += '<polygon points="' + (xC - tubeW/2 - 14) + ',' + (tY - 5) + ' ' + (xC - tubeW/2 - 4) + ',' + tY + ' ' + (xC - tubeW/2 - 14) + ',' + (tY + 5) + '" fill="#dc2626"/>';
|
||
s += '<text x="3" y="14" font-family="Inter,sans-serif" font-size="10" font-weight="700" fill="#92400e">°C</text>';
|
||
document.getElementById('p13-svg').innerHTML = s;
|
||
// Info
|
||
let label;
|
||
if(t < -50) label = 'Очень холодно (вряд ли встретишь в природе на Земле).';
|
||
else if(t < -30) label = '<b>Сильный мороз</b> — Север, Сибирь зимой.';
|
||
else if(t < 0) label = '<b>Минусовая температура</b> — вода замерзает.';
|
||
else if(t < 10) label = '<b>Прохладно</b> — поздняя осень.';
|
||
else if(t < 25) label = '<b>Комфортно</b> — обычная комнатная температура.';
|
||
else if(t < 37) label = '<b>Тепло</b> — летний день.';
|
||
else if(t < 60) label = '<b>Жарко</b> — около температуры тела или горячая вода из крана.';
|
||
else if(t < 100) label = '<b>Очень горячо</b> — нельзя касаться, можно обжечься.';
|
||
else if(t < 120) label = '<b>Кипяток / пар</b> — кипящая вода.';
|
||
else label = '<b>Очень горячо</b> — выше точки кипения воды.';
|
||
document.getElementById('p13-info').innerHTML = label + '<br><span style="font-size:.84rem;color:#64748b">$T = t + 273{,}15 = ' + (t + 273.15).toFixed(2) + '$ K</span>';
|
||
renderMath(document.getElementById('p13-info'));
|
||
}
|
||
document.getElementById('p13-t-r').addEventListener('input', drawTherm);
|
||
drawTherm();
|
||
|
||
// §13 IV-2 converter
|
||
document.getElementById('p13c-c-r').addEventListener('input', () => {
|
||
const c = +document.getElementById('p13c-c-r').value;
|
||
document.getElementById('p13c-c').textContent = c;
|
||
document.getElementById('p13c-k').textContent = (c + 273.15).toFixed(2);
|
||
});
|
||
|
||
wireDnd('p13-dnd', [
|
||
{ id:'a1', cat:'cold' },{ id:'a2', cat:'cold' },{ id:'a3', cat:'room' },
|
||
{ id:'a4', cat:'room' },{ id:'a5', cat:'hot' },{ id:'a6', cat:'hot' }
|
||
]);
|
||
wireQuiz('p13-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p13'); });
|
||
wireReadBtn('p13');
|
||
renderMath(body);
|
||
}
|
||
|
||
/* ========================================================== */
|
||
/* Финал главы 2 — 5 боссов + ачивка «Знаток вещества» */
|
||
/* ========================================================== */
|
||
function add_final2(){
|
||
const body = document.getElementById('final2-body');
|
||
if(!body) return;
|
||
let h = '';
|
||
|
||
h += '<div style="background:linear-gradient(135deg,' + ACCENT_SOFT + ',#fdf4ff);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 + '">Финал главы 2: победи 5 боссов</div>'
|
||
+ '<div style="font-size:.88rem;color:#475569;margin-top:5px">Реши все 5 задач — получишь ачивку «Знаток вещества» и +50 XP.</div>'
|
||
+ '<div style="height:10px;background:#fff;border-radius:6px;overflow:hidden;margin-top:12px;border:1px solid ' + ACCENT_SOFT + '"><div id="ch2-fin-fill" style="height:100%;background:linear-gradient(90deg,' + ACCENT + ',' + ACCENT_D + ');width:0%;transition:width .4s"></div></div>'
|
||
+ '<div id="ch2-fin-lab" style="font-size:.84rem;color:#475569;margin-top:6px">Побеждено: 0 / 5</div>'
|
||
+ '</div>';
|
||
|
||
const bosses = [
|
||
{ n:1, tag:'§8', title:'Размер молекулы',
|
||
q:'Во сколько раз молекула воды ($\\sim 10^{-10}$ м) меньше толщины волоса ($\\sim 10^{-4}$ м)?',
|
||
hint:'$10^{-4} / 10^{-10} = 10^6$ — в миллион раз.',
|
||
ans:1000000, tol:50000, step:'1' },
|
||
{ n:2, tag:'§9', title:'Диффузия и температура',
|
||
q:'Стакан кипятка ($+95$ °C) и стакан воды из-под крана ($+10$ °C). В обоих растворяют одинаковую щепотку соли. Через сколько минут вода в первом будет соленее по всему объёму, если во втором — за $30$ мин? Считать, что скорость диффузии примерно $\\sim T$ (в Кельвинах). Ответ — приблизительно в минутах (округли до целого).',
|
||
hint:'$T_1 = 95+273 = 368$ K, $T_2 = 10+273 = 283$ K. Отношение $283/368 \\approx 0{,}77$. Время в горячей: $30 \\cdot 0{,}77 \\approx 23$ мин.',
|
||
ans:23, tol:2, step:'1' },
|
||
{ n:3, tag:'§11', title:'Газ в шприце',
|
||
q:'В шприце $V_1 = 50$ см³ воздуха. Поршнем сжали так, что объём стал $V_2 = 20$ см³. Какую часть от первоначального объёма занял газ (в процентах, округли до целого)?',
|
||
hint:'$V_2/V_1 \\cdot 100\\% = 20/50 \\cdot 100\\% = 40\\,\\%$.',
|
||
ans:40, tol:1, step:'1' },
|
||
{ n:4, tag:'§12', title:'Тепловое расширение рельса',
|
||
q:'Стальной рельс длиной $l_0 = 25$ м летом нагревается с зимних $-20$ °C до летних $+40$ °C ($\\Delta T = 60$ °C). Коэффициент линейного расширения стали $\\alpha = 12 \\cdot 10^{-6}$ 1/°C. На сколько мм он удлинится?',
|
||
hint:'$\\Delta l = l_0 \\alpha \\Delta T = 25 \\cdot 12 \\cdot 10^{-6} \\cdot 60 = 1{,}8 \\cdot 10^{-2}$ м $= 18$ мм.',
|
||
ans:18, tol:1, step:'0.1' },
|
||
{ n:5, tag:'§13', title:'Знаток вещества (термометр)',
|
||
q:'Термометр показывает $t = 27$ °C. Сколько это Кельвинов? Округли до десятых.',
|
||
hint:'$T = t + 273{,}15 = 27 + 273{,}15 = 300{,}2$ K (при округлении до десятых).',
|
||
ans:300.2, tol:0.2, step:'0.1' }
|
||
];
|
||
|
||
const STATE_KEY = 'physics7_ch2_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 ? '✓ Босс повержен! +20 XP.' : '') + '</div>'
|
||
+ '</div>';
|
||
});
|
||
|
||
h += '<div id="ch2-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 · Глава 2 полностью пройдена.</div></div></div>';
|
||
|
||
body.innerHTML = h;
|
||
renderMath(body);
|
||
|
||
function updateBar(){
|
||
const cnt = bosses.filter(b => solved[b.n]).length;
|
||
document.getElementById('ch2-fin-fill').style.width = (cnt * 100 / bosses.length) + '%';
|
||
document.getElementById('ch2-fin-lab').textContent = 'Побеждено: ' + cnt + ' / ' + bosses.length;
|
||
if(cnt === bosses.length){
|
||
document.getElementById('ch2-mastered').style.display = 'flex';
|
||
const ACH_KEY = 'physics7_ch2_master';
|
||
if(localStorage.getItem(ACH_KEY) !== '1'){
|
||
localStorage.setItem(ACH_KEY, '1');
|
||
if(window.addXp) window.addXp(50, 'ach-ch2-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 = '✓ Босс повержен! +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-ch2-' + 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_CH2_WIDGETS = {
|
||
p8: add_p8,
|
||
p9: add_p9,
|
||
p10: add_p10,
|
||
p11: add_p11,
|
||
p12: add_p12,
|
||
p13: add_p13,
|
||
final2: add_final2
|
||
};
|
||
|
||
})();
|