feat(p8 ch1): IV-5 расчётные задачи для §1-5, §8, §10 (тепловые явления)
В Физике 8 ch1 §6, §7, §9, §11 уже имели IV-4 'Тренажёр N расчётных задач'. У §1-5, §8, §10 IV-4 был только MCQ — числовых задач не было. inject_p8_ch1_tasks.cjs добавляет IV-5 виджет после IV-4 в build_pN: - §1 Внутр. энергия: 5 задач (T-конверсия, U vs масса/высота) - §2 Способы изменения U: 5 (Q=ΔU+A, кин. энергия молота → тепло) - §3 Теплопроводность: 5 (тепловой поток P=Q/t, зависимости от d, S, λ) - §4 Конвекция: 5 (плотности тёплого/холодного, нагрев радиатором) - §5 Излучение: 5 (солнечный поток, Стефан-Больцман упрощённо) - §8 Плавление: 5 (Q=λm) - §10 Испарение: 5 (Q=rm, испарение пота, лужи) Всего 35 новых задач с автопроверкой числового ответа (±tol), подсказкой-решением (KaTeX) и +20 XP при прохождении всей серии. Используется существующий design system (.wg, .tinp, .feedback, .score-display) — уже подключён через phys-textbook-widgets.css.
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
// Inject IV-5 «Расчётные задачи» widget into build_pN of physics_8_ch1.html
|
||||
// for paragraphs where IV-4 is только MCQ (§1, §2, §3, §4, §5, §8, §10).
|
||||
// §6, §7, §9, §11 already have numeric task trainers.
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DST = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'physics_8_ch1.html');
|
||||
let h = fs.readFileSync(DST, 'utf8');
|
||||
|
||||
// === Numeric tasks per paragraph (§1..§11 thermal) ===
|
||||
// Каждая задача: q (вопрос с KaTeX в $..$), ans (число), tol (допуск), why (пошаговое решение)
|
||||
const TASKS = {
|
||||
|
||||
p1: [ // Внутренняя энергия
|
||||
{ q: 'Переведите температуру $t = 27\\,^\\circ$C в кельвины. ($T = t + 273$)', ans: 300, tol: 1, why: '$T = 27 + 273 = 300$ К.' },
|
||||
{ q: 'Температура воды $T = 373$ К. Чему равно $t$ в градусах Цельсия?', ans: 100, tol: 1, why: '$t = T - 273 = 373 - 273 = 100\\,^\\circ$C — кипение воды.' },
|
||||
{ q: 'У стакана воды массой $m_1 = 0{,}5$ кг и у бочки воды массой $m_2 = 50$ кг одинаковая температура. У кого внутренняя энергия больше во сколько раз?', ans: 100, tol: 1, why: '$U \\propto m$ при одинаковой $T$. $U_2/U_1 = m_2/m_1 = 50/0{,}5 = 100$.' },
|
||||
{ q: 'Тело нагрели на $\\Delta T = 30$ К. На сколько градусов Цельсия изменилась его температура?', ans: 30, tol: 0.5, why: 'Шкалы Кельвина и Цельсия отличаются только сдвигом — разность температур одинакова.' },
|
||||
{ q: 'При какой температуре по шкале Цельсия средняя кинетическая энергия молекул равна нулю (абсолютный ноль)?', ans: -273, tol: 1, why: 'Абсолютный ноль $T = 0$ К соответствует $t = 0 - 273 = -273\\,^\\circ$C.' },
|
||||
],
|
||||
|
||||
p2: [ // Способы изменения U
|
||||
{ q: 'Газу передали $Q = 200$ Дж теплоты, и он совершил работу $A = 60$ Дж. На сколько увеличилась его внутренняя энергия? ($\\Delta U = Q - A$)', ans: 140, tol: 2, why: '$\\Delta U = Q - A = 200 - 60 = 140$ Дж (первое начало термодинамики).' },
|
||||
{ q: 'Над газом совершили работу $A_{внеш} = 150$ Дж, газ отдал $Q = 50$ Дж тепла. На сколько изменилась $U$?', ans: 100, tol: 2, why: '$\\Delta U = A_{внеш} - Q_{отд} = 150 - 50 = 100$ Дж.' },
|
||||
{ q: 'Газ адиабатно (без теплообмена, $Q = 0$) расширился, совершив $A = 80$ Дж. Найдите $|\\Delta U|$.', ans: 80, tol: 2, why: 'При $Q = 0$: $\\Delta U = -A = -80$ Дж. Модуль изменения $|\\Delta U| = 80$ Дж.' },
|
||||
{ q: 'Молотом массой $0{,}5$ кг, движущимся со скоростью $v = 4$ м/с, ударили по гвоздю. Вся кинетическая энергия перешла в тепло. На сколько Джоулей увеличилась $U$ гвоздя?', ans: 4, tol: 0.1, why: '$E_к = \\dfrac{mv^2}{2} = \\dfrac{0{,}5 \\cdot 16}{2} = 4$ Дж $= \\Delta U$.' },
|
||||
{ q: 'Газу сообщили $Q = 500$ Дж, при этом $\\Delta U = 350$ Дж. Какую работу совершил газ?', ans: 150, tol: 3, why: '$A = Q - \\Delta U = 500 - 350 = 150$ Дж.' },
|
||||
],
|
||||
|
||||
p3: [ // Теплопроводность
|
||||
{ q: 'Через стенку площадью $S = 2$ м² с разностью температур $\\Delta T = 20$ К за $t = 100$ с прошло $Q = 200$ Дж. Найдите тепловой поток (Вт): $P = Q/t$.', ans: 2, tol: 0.05, why: '$P = Q/t = 200 / 100 = 2$ Вт.' },
|
||||
{ q: 'Тепловой поток через стенку $P = 50$ Вт. Сколько джоулей теплоты пройдёт через неё за $t = 1$ час?', ans: 180000, tol: 1000, why: '$Q = P \\cdot t = 50 \\cdot 3600 = 180\\,000$ Дж.' },
|
||||
{ q: 'У какого материала теплопроводность больше при прочих равных: у $\\lambda_1 = 400$ Вт/(м·К) (медь) или $\\lambda_2 = 0{,}5$ Вт/(м·К) (вода)? Введите $\\lambda_1/\\lambda_2$.', ans: 800, tol: 5, why: '$\\lambda_1 / \\lambda_2 = 400 / 0{,}5 = 800$ — металлы намного лучше проводят тепло.' },
|
||||
{ q: 'Стенка толщиной $d_1 = 0{,}1$ м заменена на стенку толщиной $d_2 = 0{,}05$ м из того же материала. Во сколько раз вырастет тепловой поток?', ans: 2, tol: 0.05, why: 'Поток $P \\propto 1/d$, поэтому $P_2/P_1 = d_1/d_2 = 0{,}1/0{,}05 = 2$.' },
|
||||
{ q: 'Площадь стенки увеличили в 3 раза. Во сколько раз вырастет тепловой поток (при той же толщине и $\\Delta T$)?', ans: 3, tol: 0.05, why: 'Поток $P \\propto S$, поэтому увеличивается в 3 раза.' },
|
||||
],
|
||||
|
||||
p4: [ // Конвекция
|
||||
{ q: 'Плотность тёплого воздуха в $\\rho_1 = 1{,}1$ кг/м³, холодного $\\rho_2 = 1{,}3$ кг/м³. На сколько % холодный плотнее? $((\\rho_2 - \\rho_1)/\\rho_1) \\cdot 100$.', ans: 18, tol: 1, why: '$(1{,}3 - 1{,}1)/1{,}1 \\cdot 100 \\approx 18\\,\\%$.' },
|
||||
{ q: 'Радиатор отдаёт мощность $P = 1500$ Вт, нагревая воздух массой $m = 50$ кг за $t = 60$ с. На сколько $\\Delta T$ нагрелся воздух? ($c_{возд} = 1000$ Дж/(кг·К))', ans: 1.8, tol: 0.1, why: '$\\Delta T = Q/(cm) = (P\\cdot t)/(cm) = (1500 \\cdot 60)/(1000 \\cdot 50) = 1{,}8$ К.' },
|
||||
{ q: 'Вода нагревается снизу. Где будет тёплая вода: $a)$ снизу, $b)$ сверху? Введите 2, если сверху, 1, если снизу.', ans: 2, tol: 0.1, why: 'Тёплая вода легче — поднимается вверх. Это и есть конвекция.' },
|
||||
{ q: 'Холодильник остужает $m = 2$ кг воздуха с $T_1 = 25$ до $T_2 = 5\\,^\\circ$C. Какое тепло (в кДж) он унёс? ($c = 1000$)', ans: 40, tol: 1, why: '$Q = cm\\Delta T = 1000 \\cdot 2 \\cdot 20 = 40\\,000$ Дж $= 40$ кДж.' },
|
||||
{ q: 'Ветер охлаждает кожу. Если без ветра тело отдаёт $P_0 = 50$ Вт, а с ветром $P = 200$ Вт, во сколько раз быстрее идёт теплоотдача?', ans: 4, tol: 0.1, why: '$P/P_0 = 200/50 = 4$ раза.' },
|
||||
],
|
||||
|
||||
p5: [ // Излучение
|
||||
{ q: 'Солнце нагревает квадратный метр земной поверхности с мощностью $P = 1000$ Вт. Сколько теплоты получит $S = 5$ м² за $t = 60$ с?', ans: 300000, tol: 5000, why: '$Q = P \\cdot S \\cdot t = 1000 \\cdot 5 \\cdot 60 = 300\\,000$ Дж = $300$ кДж.' },
|
||||
{ q: 'Черное тело излучает в 2 раза эффективнее белого. Если белое тело отдаёт $P_1 = 100$ Вт, сколько отдаст чёрное при той же $T$?', ans: 200, tol: 5, why: '$P_{черн} = 2 \\cdot P_{белого} = 2 \\cdot 100 = 200$ Вт.' },
|
||||
{ q: 'Какая температура (в К) горячей плиты, если её излучение в 16 раз сильнее излучения тела при $T_0 = 300$ К? ($P \\propto T^4$)', ans: 600, tol: 10, why: '$P/P_0 = (T/T_0)^4 = 16$, откуда $T/T_0 = 2$, $T = 600$ К.' },
|
||||
{ q: 'Какой цвет одежды летом холоднее: белый или чёрный? Введите 1, если чёрный, 2, если белый.', ans: 2, tol: 0.1, why: 'Белая отражает солнечное излучение лучше — в ней прохладнее.' },
|
||||
{ q: 'Тело площадью $S = 0{,}5$ м² излучает $P = 200$ Вт. Найдите интенсивность излучения $I = P/S$ (Вт/м²).', ans: 400, tol: 10, why: '$I = P/S = 200/0{,}5 = 400$ Вт/м².' },
|
||||
],
|
||||
|
||||
p8: [ // Плавление (Q = λm)
|
||||
{ q: 'Сколько теплоты (в кДж) нужно для плавления $m = 2$ кг льда при $0\\,^\\circ$C? ($\\lambda_{льда} = 330$ кДж/кг)', ans: 660, tol: 5, why: '$Q = \\lambda m = 330 \\cdot 2 = 660$ кДж.' },
|
||||
{ q: 'Какая масса (в кг) свинца расплавится, получив $Q = 50$ кДж? ($\\lambda_{св} = 25$ кДж/кг)', ans: 2, tol: 0.1, why: '$m = Q/\\lambda = 50/25 = 2$ кг.' },
|
||||
{ q: 'Найдите удельную теплоту плавления вещества (кДж/кг), если на плавление $m = 0{,}5$ кг затрачено $Q = 100$ кДж.', ans: 200, tol: 5, why: '$\\lambda = Q/m = 100/0{,}5 = 200$ кДж/кг.' },
|
||||
{ q: 'Сколько теплоты (кДж) нужно, чтобы расплавить $m = 5$ кг алюминия при $T_{пл}$? ($\\lambda_{Al} = 380$ кДж/кг)', ans: 1900, tol: 20, why: '$Q = \\lambda m = 380 \\cdot 5 = 1900$ кДж.' },
|
||||
{ q: 'Лёд массой $m = 1$ кг при $0\\,^\\circ$C сначала нагрели до $t = 0\\,^\\circ$C (не нужно тепла), затем расплавили. Сколько кДж потратили? ($\\lambda = 330$)', ans: 330, tol: 3, why: '$Q = \\lambda m = 330 \\cdot 1 = 330$ кДж — только на плавление.' },
|
||||
],
|
||||
|
||||
p10: [ // Испарение (Q = rm)
|
||||
{ q: 'Сколько теплоты (в кДж) нужно, чтобы испарить $m = 0{,}2$ кг воды при $100\\,^\\circ$C? ($r_{воды} = 2300$ кДж/кг)', ans: 460, tol: 5, why: '$Q = rm = 2300 \\cdot 0{,}2 = 460$ кДж.' },
|
||||
{ q: 'При испарении $m = 5$ кг этилового спирта поглощено $Q = 4500$ кДж. Найдите $r$ (кДж/кг).', ans: 900, tol: 10, why: '$r = Q/m = 4500/5 = 900$ кДж/кг.' },
|
||||
{ q: 'Какая масса (в кг) воды испарится, если ей сообщили $Q = 1150$ кДж при $100\\,^\\circ$C? ($r = 2300$)', ans: 0.5, tol: 0.02, why: '$m = Q/r = 1150/2300 = 0{,}5$ кг.' },
|
||||
{ q: 'Лужа площадью $S = 0{,}5$ м² и толщиной $d = 1$ мм испаряется. Сколько кДж нужно? ($\\rho_{воды} = 1000$ кг/м³, $r = 2300$ кДж/кг)', ans: 1.15, tol: 0.05, why: '$V = Sd = 0{,}5 \\cdot 0{,}001 = 5 \\cdot 10^{-4}$ м³, $m = \\rho V = 0{,}5$ кг $\\cdot 10^{-3} = 0{,}0005$ кг, $Q = rm = 2300 \\cdot 0{,}0005 = 1{,}15$ кДж.' },
|
||||
{ q: 'Почему пот холодит кожу? При испарении пота поглощается теплота. Если испарилось $m = 100$ г пота ($r \\approx 2400$ кДж/кг), сколько кДж унесено с кожи?', ans: 240, tol: 5, why: '$Q = rm = 2400 \\cdot 0{,}1 = 240$ кДж.' },
|
||||
],
|
||||
|
||||
};
|
||||
|
||||
// === Generate iv5 widget HTML + initializer function per pid ===
|
||||
function makeIv5Widget(pid) {
|
||||
const n = pid.slice(1);
|
||||
return `
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: ${TASKS[pid].length} расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="${pid}-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="${pid}-tasks5-i">1</b> / ${TASKS[pid].length}</span><span>Правильно: <b id="${pid}-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
`;
|
||||
}
|
||||
|
||||
function makeIv5Init(pid) {
|
||||
const n = pid.slice(1);
|
||||
const tasksLit = JSON.stringify(TASKS[pid]);
|
||||
return `
|
||||
function _init${pid}_iv5(){
|
||||
const TASKS = ${tasksLit};
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('${pid}-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="${pid}-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="${pid}-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="${pid}-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="${pid}-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="${pid}-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="${pid}-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('${pid}-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('${pid}-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('${pid}-iv5-fb');
|
||||
const wh = document.getElementById('${pid}-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('${pid}-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('${pid}-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('${pid}-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('${pid}-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('${pid}-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, '${pid}-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
// === Patch ch1 file ===
|
||||
let patchedCount = 0;
|
||||
for (const pid of Object.keys(TASKS)) {
|
||||
// 1. Append IV-5 widget HTML inside build_pN before `box.innerHTML = h + secNavFor`
|
||||
// 2. Append init call after wireReadBtn line
|
||||
// 3. Append _initPN_iv5 function after the build_pN function block
|
||||
const widget = makeIv5Widget(pid);
|
||||
const init = makeIv5Init(pid);
|
||||
|
||||
// Marker to insert widget: find `box.innerHTML = h + secNavFor('pN') + readButton('pN');`
|
||||
const insertWidgetBefore = `box.innerHTML = h + secNavFor('${pid}') + readButton('${pid}');`;
|
||||
if (!h.includes(insertWidgetBefore)) {
|
||||
console.warn(`${pid}: insert marker not found`);
|
||||
continue;
|
||||
}
|
||||
h = h.replace(insertWidgetBefore, widget.trim() + '\n\n ' + insertWidgetBefore);
|
||||
|
||||
// Marker to insert init call: after `wireReadBtn('pN');` add `_initPN_iv5();`
|
||||
const wireMarker = `wireReadBtn('${pid}');`;
|
||||
h = h.replace(wireMarker, wireMarker + `\n _init${pid}_iv5();`);
|
||||
|
||||
// Append the _initPN_iv5 function — insert before the closing }\n of build_pN
|
||||
// Search end of build_pN
|
||||
const fnStart = h.indexOf(`function build_${pid}()`);
|
||||
// Find closing brace of the function (look for `\n}\n` after fnStart, going past the new init call)
|
||||
const fnEnd = h.indexOf('\n}\n', fnStart);
|
||||
// Insert init function AFTER build_pN closing brace
|
||||
const insertPos = fnEnd + 3; // skip "\n}\n"
|
||||
h = h.slice(0, insertPos) + '\n' + init.trim() + '\n' + h.slice(insertPos);
|
||||
patchedCount++;
|
||||
console.log(` ${pid}: patched (${TASKS[pid].length} tasks)`);
|
||||
}
|
||||
|
||||
fs.writeFileSync(DST, h);
|
||||
console.log('Patched', patchedCount, '/', Object.keys(TASKS).length, 'paragraphs');
|
||||
console.log('File size:', h.length);
|
||||
|
||||
// Sanity parse
|
||||
const scripts = [...h.matchAll(/<script>([\s\S]*?)<\/script>/g)];
|
||||
for (const m of scripts) {
|
||||
try { new Function(m[1]); }
|
||||
catch(e) { console.error('JS PARSE FAIL:', e.message); process.exit(1); }
|
||||
}
|
||||
console.log('inline JS parses OK');
|
||||
@@ -812,9 +812,18 @@ function build_p1(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p1-mcq-i">1</b> / 6</span><span>Правильно: <b id="p1-mcq-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="p1-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p1-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p1-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p1') + readButton('p1');
|
||||
renderMath(box);
|
||||
wireReadBtn('p1');
|
||||
_initp1_iv5();
|
||||
|
||||
_initP1_sim();
|
||||
_initP1_quiz();
|
||||
@@ -822,6 +831,47 @@ function build_p1(){
|
||||
_initP1_mcq();
|
||||
}
|
||||
|
||||
function _initp1_iv5(){
|
||||
const TASKS = [{"q":"Переведите температуру $t = 27\\,^\\circ$C в кельвины. ($T = t + 273$)","ans":300,"tol":1,"why":"$T = 27 + 273 = 300$ К."},{"q":"Температура воды $T = 373$ К. Чему равно $t$ в градусах Цельсия?","ans":100,"tol":1,"why":"$t = T - 273 = 373 - 273 = 100\\,^\\circ$C — кипение воды."},{"q":"У стакана воды массой $m_1 = 0{,}5$ кг и у бочки воды массой $m_2 = 50$ кг одинаковая температура. У кого внутренняя энергия больше во сколько раз?","ans":100,"tol":1,"why":"$U \\propto m$ при одинаковой $T$. $U_2/U_1 = m_2/m_1 = 50/0{,}5 = 100$."},{"q":"Тело нагрели на $\\Delta T = 30$ К. На сколько градусов Цельсия изменилась его температура?","ans":30,"tol":0.5,"why":"Шкалы Кельвина и Цельсия отличаются только сдвигом — разность температур одинакова."},{"q":"При какой температуре по шкале Цельсия средняя кинетическая энергия молекул равна нулю (абсолютный ноль)?","ans":-273,"tol":1,"why":"Абсолютный ноль $T = 0$ К соответствует $t = 0 - 273 = -273\\,^\\circ$C."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('p1-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="p1-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="p1-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="p1-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="p1-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="p1-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="p1-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('p1-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('p1-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('p1-iv5-fb');
|
||||
const wh = document.getElementById('p1-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('p1-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('p1-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('p1-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('p1-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('p1-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p1-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
/* === §1 IV-1: газ-симуляция === */
|
||||
function _initP1_sim(){
|
||||
_killSim('p1sim');
|
||||
@@ -1116,9 +1166,18 @@ function build_p2(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p2-mcq-i">1</b> / 6</span><span>Правильно: <b id="p2-mcq-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="p2-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p2-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p2-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p2') + readButton('p2');
|
||||
renderMath(box);
|
||||
wireReadBtn('p2');
|
||||
_initp2_iv5();
|
||||
|
||||
_initP2_sim();
|
||||
_initP2_quiz();
|
||||
@@ -1126,6 +1185,47 @@ function build_p2(){
|
||||
_initP2_mcq();
|
||||
}
|
||||
|
||||
function _initp2_iv5(){
|
||||
const TASKS = [{"q":"Газу передали $Q = 200$ Дж теплоты, и он совершил работу $A = 60$ Дж. На сколько увеличилась его внутренняя энергия? ($\\Delta U = Q - A$)","ans":140,"tol":2,"why":"$\\Delta U = Q - A = 200 - 60 = 140$ Дж (первое начало термодинамики)."},{"q":"Над газом совершили работу $A_{внеш} = 150$ Дж, газ отдал $Q = 50$ Дж тепла. На сколько изменилась $U$?","ans":100,"tol":2,"why":"$\\Delta U = A_{внеш} - Q_{отд} = 150 - 50 = 100$ Дж."},{"q":"Газ адиабатно (без теплообмена, $Q = 0$) расширился, совершив $A = 80$ Дж. Найдите $|\\Delta U|$.","ans":80,"tol":2,"why":"При $Q = 0$: $\\Delta U = -A = -80$ Дж. Модуль изменения $|\\Delta U| = 80$ Дж."},{"q":"Молотом массой $0{,}5$ кг, движущимся со скоростью $v = 4$ м/с, ударили по гвоздю. Вся кинетическая энергия перешла в тепло. На сколько Джоулей увеличилась $U$ гвоздя?","ans":4,"tol":0.1,"why":"$E_к = \\dfrac{mv^2}{2} = \\dfrac{0{,}5 \\cdot 16}{2} = 4$ Дж $= \\Delta U$."},{"q":"Газу сообщили $Q = 500$ Дж, при этом $\\Delta U = 350$ Дж. Какую работу совершил газ?","ans":150,"tol":3,"why":"$A = Q - \\Delta U = 500 - 350 = 150$ Дж."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('p2-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="p2-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="p2-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="p2-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="p2-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="p2-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="p2-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('p2-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('p2-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('p2-iv5-fb');
|
||||
const wh = document.getElementById('p2-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('p2-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('p2-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('p2-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('p2-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('p2-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p2-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
/* === §2 IV-1: симуляция «работа vs теплопередача» === */
|
||||
function _initP2_sim(){
|
||||
_killSim('p2sim');
|
||||
@@ -1433,9 +1533,18 @@ function build_p3(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p3-mcq-i">1</b> / 6</span><span>Правильно: <b id="p3-mcq-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="p3-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p3-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p3-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p3') + readButton('p3');
|
||||
renderMath(box);
|
||||
wireReadBtn('p3');
|
||||
_initp3_iv5();
|
||||
|
||||
_initP3_sim();
|
||||
_initP3_quiz();
|
||||
@@ -1443,6 +1552,47 @@ function build_p3(){
|
||||
_initP3_mcq();
|
||||
}
|
||||
|
||||
function _initp3_iv5(){
|
||||
const TASKS = [{"q":"Через стенку площадью $S = 2$ м² с разностью температур $\\Delta T = 20$ К за $t = 100$ с прошло $Q = 200$ Дж. Найдите тепловой поток (Вт): $P = Q/t$.","ans":2,"tol":0.05,"why":"$P = Q/t = 200 / 100 = 2$ Вт."},{"q":"Тепловой поток через стенку $P = 50$ Вт. Сколько джоулей теплоты пройдёт через неё за $t = 1$ час?","ans":180000,"tol":1000,"why":"$Q = P \\cdot t = 50 \\cdot 3600 = 180\\,000$ Дж."},{"q":"У какого материала теплопроводность больше при прочих равных: у $\\lambda_1 = 400$ Вт/(м·К) (медь) или $\\lambda_2 = 0{,}5$ Вт/(м·К) (вода)? Введите $\\lambda_1/\\lambda_2$.","ans":800,"tol":5,"why":"$\\lambda_1 / \\lambda_2 = 400 / 0{,}5 = 800$ — металлы намного лучше проводят тепло."},{"q":"Стенка толщиной $d_1 = 0{,}1$ м заменена на стенку толщиной $d_2 = 0{,}05$ м из того же материала. Во сколько раз вырастет тепловой поток?","ans":2,"tol":0.05,"why":"Поток $P \\propto 1/d$, поэтому $P_2/P_1 = d_1/d_2 = 0{,}1/0{,}05 = 2$."},{"q":"Площадь стенки увеличили в 3 раза. Во сколько раз вырастет тепловой поток (при той же толщине и $\\Delta T$)?","ans":3,"tol":0.05,"why":"Поток $P \\propto S$, поэтому увеличивается в 3 раза."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('p3-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="p3-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="p3-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="p3-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="p3-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="p3-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="p3-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('p3-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('p3-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('p3-iv5-fb');
|
||||
const wh = document.getElementById('p3-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('p3-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('p3-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('p3-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('p3-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('p3-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p3-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
function _initP3_sim(){
|
||||
_killSim('p3sim');
|
||||
const svg = document.getElementById('p3-sim'); if(!svg) return;
|
||||
@@ -1647,9 +1797,18 @@ function build_p4(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p4-mcq-i">1</b> / 6</span><span>Правильно: <b id="p4-mcq-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="p4-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p4-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p4-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p4') + readButton('p4');
|
||||
renderMath(box);
|
||||
wireReadBtn('p4');
|
||||
_initp4_iv5();
|
||||
|
||||
_initP4_sim();
|
||||
_initP4_quiz();
|
||||
@@ -1657,6 +1816,47 @@ function build_p4(){
|
||||
_initP4_mcq();
|
||||
}
|
||||
|
||||
function _initp4_iv5(){
|
||||
const TASKS = [{"q":"Плотность тёплого воздуха в $\\rho_1 = 1{,}1$ кг/м³, холодного $\\rho_2 = 1{,}3$ кг/м³. На сколько % холодный плотнее? $((\\rho_2 - \\rho_1)/\\rho_1) \\cdot 100$.","ans":18,"tol":1,"why":"$(1{,}3 - 1{,}1)/1{,}1 \\cdot 100 \\approx 18\\,\\%$."},{"q":"Радиатор отдаёт мощность $P = 1500$ Вт, нагревая воздух массой $m = 50$ кг за $t = 60$ с. На сколько $\\Delta T$ нагрелся воздух? ($c_{возд} = 1000$ Дж/(кг·К))","ans":1.8,"tol":0.1,"why":"$\\Delta T = Q/(cm) = (P\\cdot t)/(cm) = (1500 \\cdot 60)/(1000 \\cdot 50) = 1{,}8$ К."},{"q":"Вода нагревается снизу. Где будет тёплая вода: $a)$ снизу, $b)$ сверху? Введите 2, если сверху, 1, если снизу.","ans":2,"tol":0.1,"why":"Тёплая вода легче — поднимается вверх. Это и есть конвекция."},{"q":"Холодильник остужает $m = 2$ кг воздуха с $T_1 = 25$ до $T_2 = 5\\,^\\circ$C. Какое тепло (в кДж) он унёс? ($c = 1000$)","ans":40,"tol":1,"why":"$Q = cm\\Delta T = 1000 \\cdot 2 \\cdot 20 = 40\\,000$ Дж $= 40$ кДж."},{"q":"Ветер охлаждает кожу. Если без ветра тело отдаёт $P_0 = 50$ Вт, а с ветром $P = 200$ Вт, во сколько раз быстрее идёт теплоотдача?","ans":4,"tol":0.1,"why":"$P/P_0 = 200/50 = 4$ раза."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('p4-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="p4-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="p4-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="p4-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="p4-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="p4-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="p4-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('p4-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('p4-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('p4-iv5-fb');
|
||||
const wh = document.getElementById('p4-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('p4-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('p4-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('p4-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('p4-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('p4-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p4-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
function _initP4_sim(){
|
||||
_killSim('p4sim');
|
||||
const svg = document.getElementById('p4-sim'); if(!svg) return;
|
||||
@@ -1904,9 +2104,18 @@ function build_p5(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p5-mcq-i">1</b> / 6</span><span>Правильно: <b id="p5-mcq-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="p5-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p5-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p5-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p5') + readButton('p5');
|
||||
renderMath(box);
|
||||
wireReadBtn('p5');
|
||||
_initp5_iv5();
|
||||
|
||||
_initP5_sim();
|
||||
_initP5_quiz();
|
||||
@@ -1914,6 +2123,47 @@ function build_p5(){
|
||||
_initP5_mcq();
|
||||
}
|
||||
|
||||
function _initp5_iv5(){
|
||||
const TASKS = [{"q":"Солнце нагревает квадратный метр земной поверхности с мощностью $P = 1000$ Вт. Сколько теплоты получит $S = 5$ м² за $t = 60$ с?","ans":300000,"tol":5000,"why":"$Q = P \\cdot S \\cdot t = 1000 \\cdot 5 \\cdot 60 = 300\\,000$ Дж = $300$ кДж."},{"q":"Черное тело излучает в 2 раза эффективнее белого. Если белое тело отдаёт $P_1 = 100$ Вт, сколько отдаст чёрное при той же $T$?","ans":200,"tol":5,"why":"$P_{черн} = 2 \\cdot P_{белого} = 2 \\cdot 100 = 200$ Вт."},{"q":"Какая температура (в К) горячей плиты, если её излучение в 16 раз сильнее излучения тела при $T_0 = 300$ К? ($P \\propto T^4$)","ans":600,"tol":10,"why":"$P/P_0 = (T/T_0)^4 = 16$, откуда $T/T_0 = 2$, $T = 600$ К."},{"q":"Какой цвет одежды летом холоднее: белый или чёрный? Введите 1, если чёрный, 2, если белый.","ans":2,"tol":0.1,"why":"Белая отражает солнечное излучение лучше — в ней прохладнее."},{"q":"Тело площадью $S = 0{,}5$ м² излучает $P = 200$ Вт. Найдите интенсивность излучения $I = P/S$ (Вт/м²).","ans":400,"tol":10,"why":"$I = P/S = 200/0{,}5 = 400$ Вт/м²."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('p5-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="p5-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="p5-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="p5-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="p5-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="p5-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="p5-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('p5-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('p5-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('p5-iv5-fb');
|
||||
const wh = document.getElementById('p5-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('p5-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('p5-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('p5-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('p5-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('p5-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p5-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
function _initP5_sim(){
|
||||
_killSim('p5sim');
|
||||
const svg = document.getElementById('p5-sim'); if(!svg) return;
|
||||
@@ -2635,9 +2885,18 @@ function build_p8(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p8-mcq-i">1</b> / 6</span><span>Правильно: <b id="p8-mcq-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="p8-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p8-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p8-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p8') + readButton('p8');
|
||||
renderMath(box);
|
||||
wireReadBtn('p8');
|
||||
_initp8_iv5();
|
||||
|
||||
_initP8_graph();
|
||||
_initP8_quiz();
|
||||
@@ -2645,6 +2904,47 @@ function build_p8(){
|
||||
_initP8_mcq();
|
||||
}
|
||||
|
||||
function _initp8_iv5(){
|
||||
const TASKS = [{"q":"Сколько теплоты (в кДж) нужно для плавления $m = 2$ кг льда при $0\\,^\\circ$C? ($\\lambda_{льда} = 330$ кДж/кг)","ans":660,"tol":5,"why":"$Q = \\lambda m = 330 \\cdot 2 = 660$ кДж."},{"q":"Какая масса (в кг) свинца расплавится, получив $Q = 50$ кДж? ($\\lambda_{св} = 25$ кДж/кг)","ans":2,"tol":0.1,"why":"$m = Q/\\lambda = 50/25 = 2$ кг."},{"q":"Найдите удельную теплоту плавления вещества (кДж/кг), если на плавление $m = 0{,}5$ кг затрачено $Q = 100$ кДж.","ans":200,"tol":5,"why":"$\\lambda = Q/m = 100/0{,}5 = 200$ кДж/кг."},{"q":"Сколько теплоты (кДж) нужно, чтобы расплавить $m = 5$ кг алюминия при $T_{пл}$? ($\\lambda_{Al} = 380$ кДж/кг)","ans":1900,"tol":20,"why":"$Q = \\lambda m = 380 \\cdot 5 = 1900$ кДж."},{"q":"Лёд массой $m = 1$ кг при $0\\,^\\circ$C сначала нагрели до $t = 0\\,^\\circ$C (не нужно тепла), затем расплавили. Сколько кДж потратили? ($\\lambda = 330$)","ans":330,"tol":3,"why":"$Q = \\lambda m = 330 \\cdot 1 = 330$ кДж — только на плавление."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('p8-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="p8-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="p8-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="p8-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="p8-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="p8-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="p8-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('p8-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('p8-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('p8-iv5-fb');
|
||||
const wh = document.getElementById('p8-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('p8-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('p8-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('p8-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('p8-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('p8-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p8-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
function _initP8_graph(){
|
||||
const svg = document.getElementById('p8-sim'); if(!svg) return;
|
||||
function draw(){
|
||||
@@ -3060,9 +3360,18 @@ function build_p10(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p10-mcq-i">1</b> / 6</span><span>Правильно: <b id="p10-mcq-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV5 — Расчётные задачи (auto-injected) */
|
||||
h += '<div class="wg">'
|
||||
+'<div class="wg-header"><span class="wg-badge">IV-5</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||||
+'<div class="wg-help">Введи числовой ответ (можно с точкой как разделителем). Решено все верно — +20 XP.</div>'
|
||||
+'<div id="p10-tasks5"></div>'
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p10-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p10-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p10') + readButton('p10');
|
||||
renderMath(box);
|
||||
wireReadBtn('p10');
|
||||
_initp10_iv5();
|
||||
|
||||
_initP10_sim();
|
||||
_initP10_quiz();
|
||||
@@ -3070,6 +3379,47 @@ function build_p10(){
|
||||
_initP10_mcq();
|
||||
}
|
||||
|
||||
function _initp10_iv5(){
|
||||
const TASKS = [{"q":"Сколько теплоты (в кДж) нужно, чтобы испарить $m = 0{,}2$ кг воды при $100\\,^\\circ$C? ($r_{воды} = 2300$ кДж/кг)","ans":460,"tol":5,"why":"$Q = rm = 2300 \\cdot 0{,}2 = 460$ кДж."},{"q":"При испарении $m = 5$ кг этилового спирта поглощено $Q = 4500$ кДж. Найдите $r$ (кДж/кг).","ans":900,"tol":10,"why":"$r = Q/m = 4500/5 = 900$ кДж/кг."},{"q":"Какая масса (в кг) воды испарится, если ей сообщили $Q = 1150$ кДж при $100\\,^\\circ$C? ($r = 2300$)","ans":0.5,"tol":0.02,"why":"$m = Q/r = 1150/2300 = 0{,}5$ кг."},{"q":"Лужа площадью $S = 0{,}5$ м² и толщиной $d = 1$ мм испаряется. Сколько кДж нужно? ($\\rho_{воды} = 1000$ кг/м³, $r = 2300$ кДж/кг)","ans":1.15,"tol":0.05,"why":"$V = Sd = 0{,}5 \\cdot 0{,}001 = 5 \\cdot 10^{-4}$ м³, $m = \\rho V = 0{,}5$ кг $\\cdot 10^{-3} = 0{,}0005$ кг, $Q = rm = 2300 \\cdot 0{,}0005 = 1{,}15$ кДж."},{"q":"Почему пот холодит кожу? При испарении пота поглощается теплота. Если испарилось $m = 100$ г пота ($r \\approx 2400$ кДж/кг), сколько кДж унесено с кожи?","ans":240,"tol":5,"why":"$Q = rm = 2400 \\cdot 0{,}1 = 240$ кДж."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
function render(){
|
||||
const t = TASKS[i]; const wrap = document.getElementById('p10-tasks5'); if(!wrap) return;
|
||||
wrap.innerHTML =
|
||||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.55"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||||
+'<div class="actions"><input type="number" step="0.001" class="tinp" id="p10-iv5-inp" placeholder="число" style="width:140px">'
|
||||
+'<button class="btn primary" id="p10-iv5-go">Ответ</button>'
|
||||
+'<button class="btn" id="p10-iv5-hint">Подсказка</button>'
|
||||
+'<button class="btn" id="p10-iv5-next">Следующая</button></div>'
|
||||
+'<details class="spoiler" id="p10-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||||
+'<div class="feedback" id="p10-iv5-fb"></div>';
|
||||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
document.getElementById('p10-iv5-go').onclick = () => {
|
||||
const v = parseFloat(document.getElementById('p10-iv5-inp').value.replace(',','.'));
|
||||
const fb = document.getElementById('p10-iv5-fb');
|
||||
const wh = document.getElementById('p10-iv5-why-wrap');
|
||||
if (Math.abs(v - t.ans) <= t.tol) {
|
||||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||||
document.getElementById('p10-tasks5-ok').textContent = ok;
|
||||
wh.style.display = 'block';
|
||||
} else {
|
||||
fb.className = 'feedback fail'; fb.innerHTML = 'Не совсем. Ожидался $' + t.ans + '$. Загляни в подсказку.';
|
||||
if (window.renderMathInElement) try { renderMathInElement(fb, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||||
}
|
||||
};
|
||||
document.getElementById('p10-iv5-hint').onclick = () => {
|
||||
const wh = document.getElementById('p10-iv5-why-wrap');
|
||||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||||
};
|
||||
document.getElementById('p10-iv5-next').onclick = () => {
|
||||
i = (i + 1) % TASKS.length;
|
||||
document.getElementById('p10-tasks5-i').textContent = i + 1;
|
||||
render();
|
||||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p10-iv5'); }
|
||||
};
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
function _initP10_sim(){
|
||||
_killSim('p10sim');
|
||||
const svg = document.getElementById('p10-sim'); if(!svg) return;
|
||||
|
||||
Reference in New Issue
Block a user