da6dd96aac
§12 Charge Sandbox: canvas с динамическим добавлением зарядов. Click → +заряд (или - через кнопку), drag для перемещения, стрелки взаимодействия по Кулону (красные=отталкивание, зелёные=притяжение). Кнопки '+/-', 'Очистить'. §17 Field Visualizer: drag-зарядов с live перерисовкой силовых линий. От каждого + рисуются 16 линий, идущих по полю E через интегрирование шагами. Линии останавливаются у − зарядов или вылетают за canvas. §22 Закон Ома: SVG цепь батарея + резистор + лампа. Scrubbers U (0.5-12 В), R (1-100 Ом). I=U/R обновляется live, яркость лампы ∝ I (glow при I>0.3). §25 Параллельные резисторы: SVG цепь с разветвлением. Scrubbers R₁, R₂. Live расчёт R_общ = R₁R₂/(R₁+R₂), I₁, I₂ для каждой ветви, общий I. §28 Магниты: canvas с 2 drag-магнитами (N-S полюса). При сближении inner полюсов (S-N) рисуются стрелки притяжения с величиной по F~1/d². §30 Опыт Эрстеда: SVG провод с током (scrubber -5..+5 А) и компас под ним. Силовые линии магн. поля вокруг провода (концентрические штриховые круги) с opacity ∝ |I|. Стрелка компаса отклоняется по arctan(I), угол выводится.
6615 lines
495 KiB
HTML
6615 lines
495 KiB
HTML
<!
|
||
function _initP30_iv6(){
|
||
const sb = document.getElementById('p30-iv6-sandbox');
|
||
if (!sb || !window.P8Helpers) return;
|
||
const svg = P8Helpers.svg.create(560, 240);
|
||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||
sb.appendChild(svg);
|
||
let I = 0;
|
||
function render(){
|
||
svg.innerHTML = '';
|
||
/* Wire (horizontal) */
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 40, y1: 120, x2: 520, y2: 120, stroke: '#0f172a', 'stroke-width': 5 }));
|
||
/* Current arrow direction */
|
||
if (Math.abs(I) > 0.05) {
|
||
const dir = I > 0 ? 1 : -1;
|
||
const arrowX = 320;
|
||
svg.appendChild(P8Helpers.svg.el('polygon', {
|
||
points: dir > 0 ? (arrowX+8)+',120 '+(arrowX-12)+',114 '+(arrowX-12)+',126' : (arrowX-8)+',120 '+(arrowX+12)+',114 '+(arrowX+12)+',126',
|
||
fill: '#dc2626'
|
||
}));
|
||
svg.appendChild(P8Helpers.svg.el('text', { x: 100, y: 110, 'font-family':"'JetBrains Mono',monospace", 'font-size':11, 'font-weight':700, fill:'#dc2626', text: 'I = '+I.toFixed(1)+' А' }));
|
||
}
|
||
/* Field lines around wire (concentric circles) */
|
||
const intensity = Math.abs(I) / 5;
|
||
if (intensity > 0.05) {
|
||
[30, 50, 70, 90].forEach((r, i) => {
|
||
svg.appendChild(P8Helpers.svg.el('circle', { cx: 280, cy: 120, r, fill: 'none', stroke: '#7c3aed', 'stroke-width': 1.5, opacity: intensity * (1 - i * 0.15), 'stroke-dasharray': '5 3' }));
|
||
});
|
||
}
|
||
/* Compass below wire (initially N up = 0°) */
|
||
const angle = Math.atan2(0, 1) * 180 / Math.PI; /* baseline */
|
||
/* Angle deflection ∝ I (sign determines direction) */
|
||
const deflection = Math.atan(I * 0.5) * 60; /* approx */
|
||
/* Compass body */
|
||
svg.appendChild(P8Helpers.svg.el('circle', { cx: 280, cy: 195, r: 28, fill: '#fff', stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('text', { x: 280, y: 172, 'font-family':"'Unbounded',sans-serif", 'font-size':10, 'font-weight':800, fill:'#dc2626', 'text-anchor':'middle', text: 'N' }));
|
||
/* Needle */
|
||
const needleG = P8Helpers.svg.el('g', { transform: 'translate(280, 195) rotate('+deflection+')' });
|
||
needleG.appendChild(P8Helpers.svg.el('polygon', { points: '-2,-22 2,-22 0,-2', fill: '#dc2626' }));
|
||
needleG.appendChild(P8Helpers.svg.el('polygon', { points: '-2,22 2,22 0,2', fill: '#475569' }));
|
||
needleG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 3, fill: '#0f172a' }));
|
||
svg.appendChild(needleG);
|
||
document.getElementById('p30-iv6-ang').textContent = Math.round(deflection);
|
||
}
|
||
document.getElementById('p30-iv6-i').oninput = ev => { I = +ev.target.value; document.getElementById('p30-iv6-i-val').textContent = I.toFixed(1); render(); };
|
||
render();
|
||
}
|
||
|
||
function _initP28_iv6(){
|
||
const sb = document.getElementById('p28-iv6-sandbox');
|
||
if (!sb || !window.P8Drag) return;
|
||
const W = 560, H = 240;
|
||
const canvas = document.createElement('canvas');
|
||
canvas.width = W; canvas.height = H;
|
||
canvas.style.width='100%'; canvas.style.height='100%'; canvas.style.display='block';
|
||
sb.appendChild(canvas);
|
||
const ctx = canvas.getContext('2d');
|
||
const magnets = [
|
||
{ x: 140, y: 120, angle: 0, r: 50 },
|
||
{ x: 420, y: 120, angle: 0, r: 50 }
|
||
];
|
||
function drawMagnet(m){
|
||
const w = 100, h = 32;
|
||
ctx.save();
|
||
ctx.translate(m.x, m.y);
|
||
ctx.rotate(m.angle);
|
||
/* N half (red) */
|
||
ctx.fillStyle = '#dc2626';
|
||
ctx.fillRect(-w/2, -h/2, w/2, h);
|
||
/* S half (blue) */
|
||
ctx.fillStyle = '#2563eb';
|
||
ctx.fillRect(0, -h/2, w/2, h);
|
||
ctx.strokeStyle = '#0f172a';
|
||
ctx.lineWidth = 2;
|
||
ctx.strokeRect(-w/2, -h/2, w, h);
|
||
ctx.fillStyle = '#fff';
|
||
ctx.font = "bold 18px sans-serif";
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'middle';
|
||
ctx.fillText('N', -w/4, 0);
|
||
ctx.fillText('S', w/4, 0);
|
||
ctx.restore();
|
||
}
|
||
function draw(){
|
||
ctx.fillStyle = '#fafafa';
|
||
ctx.fillRect(0, 0, W, H);
|
||
/* Compute interaction between the two magnets — their inner poles */
|
||
/* Magnet 1: right side is S (blue, at +50), Magnet 2: left side is N (red, at -50) */
|
||
const m1S_x = magnets[0].x + 50 * Math.cos(magnets[0].angle);
|
||
const m1S_y = magnets[0].y + 50 * Math.sin(magnets[0].angle);
|
||
const m2N_x = magnets[1].x - 50 * Math.cos(magnets[1].angle);
|
||
const m2N_y = magnets[1].y - 50 * Math.sin(magnets[1].angle);
|
||
const dx = m2N_x - m1S_x;
|
||
const dy = m2N_y - m1S_y;
|
||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||
if (dist < 250 && dist > 30) {
|
||
/* N-S → attraction */
|
||
const F = 5000 / (dist * dist);
|
||
const ux = dx / dist, uy = dy / dist;
|
||
const len = Math.min(50, F * 50);
|
||
const color = '#dc2626';
|
||
/* Arrow 1 from m1S toward m2N */
|
||
ctx.strokeStyle = color; ctx.lineWidth = 2;
|
||
ctx.beginPath();
|
||
ctx.moveTo(m1S_x, m1S_y);
|
||
ctx.lineTo(m1S_x + ux * len, m1S_y + uy * len);
|
||
ctx.stroke();
|
||
/* Arrow 2 from m2N back */
|
||
ctx.beginPath();
|
||
ctx.moveTo(m2N_x, m2N_y);
|
||
ctx.lineTo(m2N_x - ux * len, m2N_y - uy * len);
|
||
ctx.stroke();
|
||
ctx.fillStyle = color;
|
||
ctx.font = "bold 12px sans-serif";
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('притяжение', (m1S_x + m2N_x)/2, (m1S_y + m2N_y)/2 - 12);
|
||
}
|
||
magnets.forEach(drawMagnet);
|
||
}
|
||
/* Drag */
|
||
const dragObjs = magnets.map((m, i) => ({ x: m.x, y: m.y, r: 50, idx: i }));
|
||
const drag = P8Drag.attachCanvas(canvas, {
|
||
objects: dragObjs,
|
||
onDrag: (obj, pos) => {
|
||
magnets[obj.idx].x = pos.x;
|
||
magnets[obj.idx].y = pos.y;
|
||
draw();
|
||
}
|
||
});
|
||
draw();
|
||
}
|
||
|
||
function _initP25_iv6(){
|
||
const sb = document.getElementById('p25-iv6-sandbox');
|
||
if (!sb || !window.P8Helpers) return;
|
||
const svg = P8Helpers.svg.create(560, 240);
|
||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||
sb.appendChild(svg);
|
||
const U = 12;
|
||
let R1 = 20, R2 = 30;
|
||
function render(){
|
||
svg.innerHTML = '';
|
||
const R = 1 / (1/R1 + 1/R2);
|
||
const I1 = U / R1, I2 = U / R2, I = I1 + I2;
|
||
/* Battery left */
|
||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 80, 120, 'h', U+' В'));
|
||
/* Branch split */
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 110, y1: 120, x2: 200, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 60, x2: 200, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 60, x2: 380, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 60, x2: 290, y2: 60, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 320, y1: 60, x2: 380, y2: 60, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 200, y1: 180, x2: 290, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 320, y1: 180, x2: 380, y2: 180, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
/* R1 (top) */
|
||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 305, 60, 'h', R1+' Ом'));
|
||
/* R2 (bottom) */
|
||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 305, 180, 'h', R2+' Ом'));
|
||
/* Right wire */
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 380, y1: 120, x2: 510, y2: 120, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 120, x2: 510, y2: 210, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 120, x2: 50, y2: 210, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 50, y1: 210, x2: 510, y2: 210, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
/* Current labels */
|
||
svg.appendChild(P8Helpers.svg.el('text', { x: 290, y: 48, 'font-family':"'JetBrains Mono',monospace", 'font-size':11, 'font-weight':700, fill:'var(--el-mid,#06b6d4)', 'text-anchor':'middle', text: 'I₁ = '+I1.toFixed(2)+' А' }));
|
||
svg.appendChild(P8Helpers.svg.el('text', { x: 290, y: 218, 'font-family':"'JetBrains Mono',monospace", 'font-size':11, 'font-weight':700, fill:'var(--el-mid,#06b6d4)', 'text-anchor':'middle', text: 'I₂ = '+I2.toFixed(2)+' А' }));
|
||
svg.appendChild(P8Helpers.svg.el('text', { x: 150, y: 138, 'font-family':"'JetBrains Mono',monospace", 'font-size':11, 'font-weight':700, fill:'#dc2626', 'text-anchor':'middle', text: 'I = '+I.toFixed(2)+' А' }));
|
||
document.getElementById('p25-iv6-r').textContent = R.toFixed(1);
|
||
document.getElementById('p25-iv6-i1').textContent = I1.toFixed(2);
|
||
document.getElementById('p25-iv6-i2').textContent = I2.toFixed(2);
|
||
}
|
||
document.getElementById('p25-iv6-r1').oninput = ev => { R1 = +ev.target.value; document.getElementById('p25-iv6-r1-val').textContent = R1; render(); };
|
||
document.getElementById('p25-iv6-r2').oninput = ev => { R2 = +ev.target.value; document.getElementById('p25-iv6-r2-val').textContent = R2; render(); };
|
||
render();
|
||
}
|
||
|
||
function _initP22_iv6(){
|
||
const sb = document.getElementById('p22-iv6-sandbox');
|
||
if (!sb || !window.P8Helpers) return;
|
||
const svg = P8Helpers.svg.create(560, 220);
|
||
svg.setAttribute('width','100%'); svg.setAttribute('height','100%'); svg.style.display='block';
|
||
sb.appendChild(svg);
|
||
let U = 6, R = 12;
|
||
function render(){
|
||
svg.innerHTML = '';
|
||
const I = U / R;
|
||
/* Circuit */
|
||
/* Battery */
|
||
svg.appendChild(P8Helpers.em.circuitComponent('battery', 120, 110, 'h', U+' В'));
|
||
/* Resistor */
|
||
svg.appendChild(P8Helpers.em.circuitComponent('resistor', 280, 110, 'h', R+' Ом'));
|
||
/* Lamp (brightness varies with I) */
|
||
const lampG = P8Helpers.svg.el('g', { transform: 'translate(440, 110)' });
|
||
const brightness = Math.min(1, I / 1.5);
|
||
lampG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 26, fill: '#fef3c7', opacity: brightness * 0.6 + 0.1 }));
|
||
lampG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 16, fill: '#fef3c7', stroke: '#0f172a', 'stroke-width': 2 }));
|
||
if (brightness > 0.3) {
|
||
lampG.appendChild(P8Helpers.svg.el('circle', { cx: 0, cy: 0, r: 30, fill: 'none', stroke: '#facc15', 'stroke-width': 3, opacity: brightness }));
|
||
}
|
||
lampG.appendChild(P8Helpers.svg.el('line', { x1: -10, y1: -10, x2: 10, y2: 10, stroke: '#0f172a', 'stroke-width': 1.5 }));
|
||
lampG.appendChild(P8Helpers.svg.el('line', { x1: -10, y1: 10, x2: 10, y2: -10, stroke: '#0f172a', 'stroke-width': 1.5 }));
|
||
svg.appendChild(lampG);
|
||
/* Connect wires */
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 150, y1: 110, x2: 250, y2: 110, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 310, y1: 110, x2: 414, y2: 110, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 466, y1: 110, x2: 510, y2: 110, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 510, y1: 110, x2: 510, y2: 170, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 90, y1: 110, x2: 90, y2: 170, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
svg.appendChild(P8Helpers.svg.el('line', { x1: 90, y1: 170, x2: 510, y2: 170, stroke: '#0f172a', 'stroke-width': 2 }));
|
||
/* Current label */
|
||
svg.appendChild(P8Helpers.svg.el('text', { x: 300, y: 195, 'font-family':"'JetBrains Mono',monospace", 'font-size':14, 'font-weight':800, fill:'var(--el-mid,#06b6d4)', 'text-anchor':'middle', text: 'I = '+I.toFixed(2)+' А' }));
|
||
document.getElementById('p22-iv6-i').textContent = I.toFixed(2);
|
||
}
|
||
document.getElementById('p22-iv6-u').oninput = ev => { U = +ev.target.value; document.getElementById('p22-iv6-u-val').textContent = U.toFixed(1); render(); };
|
||
document.getElementById('p22-iv6-r').oninput = ev => { R = +ev.target.value; document.getElementById('p22-iv6-r-val').textContent = R; render(); };
|
||
render();
|
||
}
|
||
|
||
function _initP17_iv6(){
|
||
const sb = document.getElementById('p17-iv6-sandbox');
|
||
if (!sb || !window.P8Drag) return;
|
||
const W = 560, H = 320;
|
||
const canvas = document.createElement('canvas');
|
||
canvas.width = W; canvas.height = H;
|
||
canvas.style.width = '100%'; canvas.style.height = '100%'; canvas.style.display = 'block';
|
||
sb.appendChild(canvas);
|
||
const ctx = canvas.getContext('2d');
|
||
let charges = [
|
||
{ x: 200, y: 160, sign: 1, r: 22 },
|
||
{ x: 360, y: 160, sign: -1, r: 22 }
|
||
];
|
||
function E(x, y) {
|
||
let ex = 0, ey = 0;
|
||
charges.forEach(c => {
|
||
const dx = x - c.x, dy = y - c.y;
|
||
const r2 = dx*dx + dy*dy;
|
||
if (r2 < 200) return;
|
||
const r = Math.sqrt(r2);
|
||
const k = 5000 * c.sign / r2;
|
||
ex += k * dx / r; ey += k * dy / r;
|
||
});
|
||
return { ex, ey, mag: Math.sqrt(ex*ex + ey*ey) };
|
||
}
|
||
function draw(){
|
||
ctx.fillStyle = '#fafafa';
|
||
ctx.fillRect(0, 0, W, H);
|
||
/* Draw field lines starting from + charges */
|
||
charges.filter(c => c.sign > 0).forEach(c => {
|
||
for (let i = 0; i < 16; i++) {
|
||
const a = i * 2 * Math.PI / 16;
|
||
let x = c.x + 25 * Math.cos(a);
|
||
let y = c.y + 25 * Math.sin(a);
|
||
ctx.strokeStyle = '#dc2626';
|
||
ctx.lineWidth = 1.2;
|
||
ctx.globalAlpha = 0.75;
|
||
ctx.beginPath();
|
||
ctx.moveTo(x, y);
|
||
for (let step = 0; step < 200; step++) {
|
||
const e = E(x, y);
|
||
if (e.mag < 0.01) break;
|
||
const dx = e.ex / e.mag * 3;
|
||
const dy = e.ey / e.mag * 3;
|
||
x += dx; y += dy;
|
||
if (x < 0 || x > W || y < 0 || y > H) break;
|
||
/* Stop near - charge */
|
||
let nearNeg = false;
|
||
for (const neg of charges) {
|
||
if (neg.sign < 0 && (x - neg.x)**2 + (y - neg.y)**2 < 600) { nearNeg = true; break; }
|
||
}
|
||
ctx.lineTo(x, y);
|
||
if (nearNeg) break;
|
||
}
|
||
ctx.stroke();
|
||
ctx.globalAlpha = 1;
|
||
}
|
||
});
|
||
/* Charges */
|
||
charges.forEach(c => {
|
||
const color = c.sign > 0 ? '#dc2626' : '#2563eb';
|
||
const fill = c.sign > 0 ? '#fecaca' : '#bfdbfe';
|
||
ctx.fillStyle = fill;
|
||
ctx.strokeStyle = color;
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.arc(c.x, c.y, 20, 0, 2 * Math.PI);
|
||
ctx.fill();
|
||
ctx.stroke();
|
||
ctx.fillStyle = color;
|
||
ctx.font = "bold 20px sans-serif";
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'middle';
|
||
ctx.fillText(c.sign > 0 ? '+' : '−', c.x, c.y + 1);
|
||
});
|
||
}
|
||
const drag = P8Drag.attachCanvas(canvas, {
|
||
objects: charges,
|
||
onDrag: () => draw()
|
||
});
|
||
document.getElementById('p17-iv6-add-pos').onclick = () => {
|
||
charges.push({ x: 100 + Math.random() * (W - 200), y: 80 + Math.random() * (H - 160), sign: 1, r: 22 });
|
||
drag.updateObjects(charges);
|
||
draw();
|
||
};
|
||
document.getElementById('p17-iv6-add-neg').onclick = () => {
|
||
charges.push({ x: 100 + Math.random() * (W - 200), y: 80 + Math.random() * (H - 160), sign: -1, r: 22 });
|
||
drag.updateObjects(charges);
|
||
draw();
|
||
};
|
||
document.getElementById('p17-iv6-clear').onclick = () => {
|
||
charges.length = 0;
|
||
charges.push({ x: 200, y: 160, sign: 1, r: 22 }, { x: 360, y: 160, sign: -1, r: 22 });
|
||
drag.updateObjects(charges);
|
||
draw();
|
||
};
|
||
draw();
|
||
}
|
||
|
||
function _initP12_iv6(){
|
||
const sb = document.getElementById('p12-iv6-sandbox');
|
||
if (!sb || !window.P8Helpers || !window.P8Drag) return;
|
||
const W = 560, H = 300;
|
||
const canvas = document.createElement('canvas');
|
||
canvas.width = W; canvas.height = H;
|
||
canvas.style.width = '100%'; canvas.style.height = '100%'; canvas.style.display = 'block';
|
||
sb.appendChild(canvas);
|
||
const ctx = canvas.getContext('2d');
|
||
const charges = [];
|
||
let nextSign = 1;
|
||
function draw(){
|
||
ctx.fillStyle = '#fafafa';
|
||
ctx.fillRect(0, 0, W, H);
|
||
/* Forces between pairs */
|
||
for (let i = 0; i < charges.length; i++) {
|
||
for (let j = i + 1; j < charges.length; j++) {
|
||
const a = charges[i], b = charges[j];
|
||
const dx = b.x - a.x, dy = b.y - a.y;
|
||
const r2 = dx*dx + dy*dy;
|
||
if (r2 < 100) continue;
|
||
const r = Math.sqrt(r2);
|
||
const F = 4e6 * a.sign * b.sign / r2;
|
||
const fx = F * dx / r, fy = F * dy / r;
|
||
/* Arrow from a in direction (-fx, -fy) means: force on a from b */
|
||
const len = Math.min(80, Math.abs(F) * 5);
|
||
const dir = a.sign * b.sign > 0 ? -1 : 1;
|
||
const aex = a.x + dir * fx / Math.abs(F) * len;
|
||
const aey = a.y + dir * fy / Math.abs(F) * len;
|
||
ctx.strokeStyle = a.sign * b.sign > 0 ? '#dc2626' : '#16a34a';
|
||
ctx.lineWidth = 1.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(a.x, a.y);
|
||
ctx.lineTo(aex, aey);
|
||
ctx.stroke();
|
||
/* Arrowhead */
|
||
const ang = Math.atan2(aey - a.y, aex - a.x);
|
||
ctx.beginPath();
|
||
ctx.moveTo(aex, aey);
|
||
ctx.lineTo(aex - 7 * Math.cos(ang - 0.3), aey - 7 * Math.sin(ang - 0.3));
|
||
ctx.lineTo(aex - 7 * Math.cos(ang + 0.3), aey - 7 * Math.sin(ang + 0.3));
|
||
ctx.closePath();
|
||
ctx.fillStyle = ctx.strokeStyle;
|
||
ctx.fill();
|
||
}
|
||
}
|
||
/* Charges */
|
||
charges.forEach(c => {
|
||
const color = c.sign > 0 ? '#dc2626' : '#2563eb';
|
||
const fill = c.sign > 0 ? '#fecaca' : '#bfdbfe';
|
||
ctx.fillStyle = fill;
|
||
ctx.strokeStyle = color;
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.arc(c.x, c.y, 18, 0, 2 * Math.PI);
|
||
ctx.fill();
|
||
ctx.stroke();
|
||
ctx.fillStyle = color;
|
||
ctx.font = "bold 18px sans-serif";
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'middle';
|
||
ctx.fillText(c.sign > 0 ? '+' : '−', c.x, c.y + 1);
|
||
});
|
||
document.getElementById('p12-iv6-count').textContent = charges.length;
|
||
}
|
||
const drag = P8Drag.attachCanvas(canvas, {
|
||
objects: charges.map(c => ({ ...c, r: 22 })),
|
||
onPickup: c => {},
|
||
onDrag: (c, pos) => {
|
||
/* Sync back to charges by id */
|
||
const orig = charges.find(ch => ch === c || (ch.id === c.id));
|
||
if (orig) { orig.x = pos.x; orig.y = pos.y; }
|
||
draw();
|
||
},
|
||
onClick: (pos) => {
|
||
charges.push({ x: pos.x, y: pos.y, sign: nextSign, id: Date.now() + Math.random() });
|
||
drag.updateObjects(charges.map(c => ({ ...c, r: 22 })));
|
||
draw();
|
||
if (window.addXp && charges.length === 2) addXp(10, 'p12-iv6-first');
|
||
}
|
||
});
|
||
document.getElementById('p12-iv6-add-pos').onclick = () => {
|
||
nextSign = 1;
|
||
charges.push({ x: 80 + Math.random() * (W - 160), y: 80 + Math.random() * (H - 160), sign: 1, id: Date.now() + Math.random() });
|
||
drag.updateObjects(charges.map(c => ({ ...c, r: 22 })));
|
||
draw();
|
||
};
|
||
document.getElementById('p12-iv6-add-neg').onclick = () => {
|
||
nextSign = -1;
|
||
charges.push({ x: 80 + Math.random() * (W - 160), y: 80 + Math.random() * (H - 160), sign: -1, id: Date.now() + Math.random() });
|
||
drag.updateObjects(charges.map(c => ({ ...c, r: 22 })));
|
||
draw();
|
||
};
|
||
document.getElementById('p12-iv6-clear').onclick = () => {
|
||
charges.length = 0;
|
||
drag.updateObjects([]);
|
||
draw();
|
||
};
|
||
draw();
|
||
}
|
||
|
||
function _initp31_iv5(){
|
||
const TASKS = [{"q":"У электромагнита было $N_1 = 100$ витков, его магнитное поле $B_1$. После добавления стало $N_2 = 500$ витков (тот же ток). Во сколько раз вырастет $B$?","ans":5,"tol":0.2,"why":"$B \\propto N$, поэтому $B_2/B_1 = N_2/N_1 = 5$."},{"q":"Ток в катушке вырос с $I_1 = 0{,}2$ А до $I_2 = 1$ А. Во сколько раз увеличилось магнитное поле электромагнита?","ans":5,"tol":0.2,"why":"$B \\propto I$, поэтому $B_2/B_1 = I_2/I_1 = 5$."},{"q":"Без сердечника поле электромагнита $B_0 = 1$ мТл. С железным сердечником стало $B = 1000$ мТл. Во сколько раз сердечник усилил поле?","ans":1000,"tol":10,"why":"Железо имеет магнитную проницаемость $\\mu \\sim 1000$. $B/B_0 = 1000$."},{"q":"Электромагнит подняет груз массой $m = 50$ кг с силой $F = 500$ Н. Какова перегрузка $F/(mg)$? ($g = 10$ м/с²)","ans":1,"tol":0.05,"why":"$F/(mg) = 500/(50 \\cdot 10) = 500/500 = 1$ — сила в точности уравновешивает вес."},{"q":"Если ток отключить, что произойдёт с магн. полем электромагнита? ($1$ — останется, $0$ — исчезнет)","ans":0,"tol":0.1,"why":"Магнитное поле электромагнита создаётся током. Нет тока — нет поля. (В отличие от постоянного магнита.)"}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p31-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="p31-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p31-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p31-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p31-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p31-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p31-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p31-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p31-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p31-iv5-fb');
|
||
const wh = document.getElementById('p31-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p31-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('p31-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p31-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p31-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p31-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p31-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp30_iv5(){
|
||
const TASKS = [{"q":"В каком году Эрстед обнаружил магнитное действие тока?","ans":1820,"tol":5,"why":"Х. Эрстед открыл связь электрического тока и магнетизма в 1820 году."},{"q":"Стрелка компаса находится над проводником. Какой угол (в градусах) к проводнику она составит при отсутствии тока? ($1$ — $0°$, $2$ — $90°$)","ans":1,"tol":0.1,"why":"Без тока стрелка направлена вдоль магнитного поля Земли. Над проводником, протянутым с севера на юг, стрелка $\\parallel$ проводнику ($0°$)."},{"q":"При включении тока стрелка отклоняется. Когда ток отключают, что произойдёт? ($1$ — останется, $2$ — вернётся в исходное положение)","ans":2,"tol":0.1,"why":"Без тока магнитное поле проводника исчезает, на стрелку действует только поле Земли — она возвращается."},{"q":"Правило буравчика: если ток течёт вверх, в каком направлении вращаются силовые линии магн. поля? ($1$ — по часовой при взгляде сверху, $2$ — против часовой при взгляде сверху)","ans":2,"tol":0.1,"why":"Правило правой руки: большой палец — направление тока, согнутые пальцы показывают направление поля. При токе вверх — против часовой при взгляде сверху."},{"q":"Сила тока удвоилась. Во сколько раз сильнее отклонится магнитная стрелка (приближённо)?","ans":2,"tol":0.1,"why":"Магнитное поле $B \\propto I$, отклонение стрелки тоже растёт примерно линейно — в $2$ раза."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p30-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="p30-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p30-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p30-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p30-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p30-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p30-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p30-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p30-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p30-iv5-fb');
|
||
const wh = document.getElementById('p30-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p30-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('p30-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p30-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p30-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p30-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p30-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp29_iv5(){
|
||
const TASKS = [{"q":"Опыт Эрстеда: магнитная стрелка отклоняется при включении тока в проводнике. Это значит, что вокруг тока есть... ($1$ — электрическое поле, $2$ — магнитное поле, $3$ — гравитационное)","ans":2,"tol":0.1,"why":"Вокруг любого тока существует магнитное поле — ключевое открытие Эрстеда (1820)."},{"q":"Линии магнитного поля прямого тока — это: ($1$ — прямые, $2$ — концентрические окружности вокруг проводника, $3$ — параболы)","ans":2,"tol":0.1,"why":"Силовые линии магнитного поля прямого тока — концентрические окружности в плоскостях, перпендикулярных проводнику."},{"q":"У одного провода ток $I_1 = 2$ А, у другого $I_2 = 8$ А. У какого индукция магнитного поля на одинаковом расстоянии больше во сколько раз? ($B \\propto I$)","ans":4,"tol":0.1,"why":"$B \\propto I$, поэтому $B_2/B_1 = I_2/I_1 = 8/2 = 4$ раза."},{"q":"Сила, действующая на проводник с током в магнитном поле, при $I = 5$ А, $B = 0{,}2$ Тл, $L = 0{,}1$ м: $F = BIL$ (Н)?","ans":0.1,"tol":0.005,"why":"$F = BIL = 0{,}2 \\cdot 5 \\cdot 0{,}1 = 0{,}1$ Н."},{"q":"Если ток в проводнике увеличить в $3$ раза, во сколько раз увеличится сила в магнитном поле?","ans":3,"tol":0.1,"why":"$F = BIL \\propto I$, поэтому $F$ увеличится в $3$ раза."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p29-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="p29-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p29-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p29-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p29-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p29-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p29-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p29-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p29-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p29-iv5-fb');
|
||
const wh = document.getElementById('p29-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p29-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('p29-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p29-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p29-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p29-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p29-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp28_iv5(){
|
||
const TASKS = [{"q":"Сколько полюсов у любого магнита?","ans":2,"tol":0.1,"why":"У любого магнита всегда $2$ полюса: северный N и южный S. Магнитного «монополя» не существует."},{"q":"Если разрезать магнит на $2$ части, сколько магнитов получится?","ans":2,"tol":0.1,"why":"Каждая часть будет иметь свои $2$ полюса — получаем $2$ магнита."},{"q":"Магнит разрезали на $5$ кусков. Сколько всего полюсов у всех кусков?","ans":10,"tol":0.1,"why":"Каждый магнит имеет $2$ полюса. Всего: $5 \\cdot 2 = 10$."},{"q":"У одного магнита N-полюс, у другого S-полюс. Они притягиваются или отталкиваются? ($1$ — притягиваются, $0$ — отталкиваются)","ans":1,"tol":0.1,"why":"Разноимённые магнитные полюса притягиваются (как и разноимённые заряды)."},{"q":"Какой полюс у Земли находится около географического Северного полюса? ($1$ — северный магнитный, $2$ — южный магнитный)","ans":2,"tol":0.1,"why":"Около географ. севера — южный магнитный полюс Земли (поэтому стрелка компаса N притягивается к нему)."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p28-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="p28-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p28-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p28-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p28-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p28-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p28-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p28-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p28-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p28-iv5-fb');
|
||
const wh = document.getElementById('p28-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p28-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('p28-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p28-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p28-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p28-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p28-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp21_iv5(){
|
||
const TASKS = [{"q":"За $t = 2$ с через сечение проводника прошёл заряд $q = 6$ Кл. Найдите силу тока $I$ (А). $I = q/t$.","ans":3,"tol":0.05,"why":"$I = q/t = 6/2 = 3$ А."},{"q":"В цепи течёт ток $I = 0{,}5$ А. Какой заряд (Кл) пройдёт за минуту?","ans":30,"tol":0.5,"why":"$q = It = 0{,}5 \\cdot 60 = 30$ Кл."},{"q":"Через лампочку прошло $q = 60$ Кл за $t = 5$ мин. Найдите $I$ (мА). Внимание: переведите минуты в секунды.","ans":200,"tol":5,"why":"$t = 300$ с, $I = q/t = 60/300 = 0{,}2$ А $= 200$ мА."},{"q":"В лампе сила тока $I = 0{,}3$ А. Сколько электронов проходит через сечение нити за $t = 1$ с? ($e = 1{,}6 \\cdot 10^{-19}$ Кл). Ответ $\\times 10^{18}$.","ans":1.875,"tol":0.05,"why":"$n = q/e = It/e = 0{,}3 / 1{,}6 \\cdot 10^{-19} \\approx 1{,}88 \\cdot 10^{18}$."},{"q":"Какой ток (А) в цепи, где за $0{,}5$ часа прошло $q = 900$ Кл?","ans":0.5,"tol":0.02,"why":"$t = 1800$ с, $I = q/t = 900/1800 = 0{,}5$ А."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p21-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="p21-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p21-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p21-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p21-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p21-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p21-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p21-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p21-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p21-iv5-fb');
|
||
const wh = document.getElementById('p21-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p21-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('p21-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p21-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p21-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p21-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p21-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp19_iv5(){
|
||
const TASKS = [{"q":"Батарея делает работу $A = 12$ Дж по перемещению заряда $q = 4$ Кл. Найдите ЭДС $\\mathcal{E}$ (В). $\\mathcal{E} = A/q$.","ans":3,"tol":0.05,"why":"$\\mathcal{E} = A/q = 12/4 = 3$ В."},{"q":"ЭДС источника $\\mathcal{E} = 9$ В. Какую работу (Дж) совершат сторонние силы по переносу заряда $q = 5$ Кл?","ans":45,"tol":1,"why":"$A = \\mathcal{E} \\cdot q = 9 \\cdot 5 = 45$ Дж."},{"q":"Аккумулятор отдал заряд $q = 0{,}5$ Кл при ЭДС $\\mathcal{E} = 12$ В. Сколько Дж работы он совершил?","ans":6,"tol":0.1,"why":"$A = \\mathcal{E} q = 12 \\cdot 0{,}5 = 6$ Дж."},{"q":"У батарейки ЭДС $1{,}5$ В. Сколько Кл нужно перенести, чтобы получить $3$ Дж?","ans":2,"tol":0.05,"why":"$q = A/\\mathcal{E} = 3/1{,}5 = 2$ Кл."},{"q":"Гальванический элемент работает $t = 60$ с с током $I = 0{,}1$ А и ЭДС $\\mathcal{E} = 1{,}5$ В. Какую работу (Дж) он совершил? ($A = \\mathcal{E} I t$)","ans":9,"tol":0.2,"why":"$A = \\mathcal{E} \\cdot I \\cdot t = 1{,}5 \\cdot 0{,}1 \\cdot 60 = 9$ Дж."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p19-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="p19-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p19-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p19-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p19-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p19-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p19-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p19-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p19-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p19-iv5-fb');
|
||
const wh = document.getElementById('p19-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p19-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('p19-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p19-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p19-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p19-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p19-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp17_iv5(){
|
||
const TASKS = [{"q":"В точке поля на заряд $q = 2$ нКл действует сила $F = 4 \\cdot 10^{-5}$ Н. Найдите модуль напряжённости $E$ (В/м). $E = F/q$.","ans":20000,"tol":500,"why":"$E = F/q = 4 \\cdot 10^{-5} / 2 \\cdot 10^{-9} = 2 \\cdot 10^{4} = 20\\,000$ В/м."},{"q":"Напряжённость поля $E = 1000$ В/м. Какая сила (мкН) действует на заряд $q = 5$ нКл?","ans":5,"tol":0.2,"why":"$F = qE = 5 \\cdot 10^{-9} \\cdot 1000 = 5 \\cdot 10^{-6}$ Н $= 5$ мкН."},{"q":"Однородное поле напряжённостью $E = 200$ В/м. Какая работа поля (мкДж) при перемещении заряда $q = 1$ мкКл вдоль линии поля на $d = 10$ см?","ans":20,"tol":1,"why":"$A = qEd = 10^{-6} \\cdot 200 \\cdot 0{,}1 = 2 \\cdot 10^{-5}$ Дж $= 20$ мкДж."},{"q":"На пробный заряд $q_0$ в поле действует сила $F$. Если заряд $q_0$ удвоить, во сколько раз изменится $E$ в этой точке?","ans":1,"tol":0.05,"why":"$E$ — характеристика поля, не зависит от пробного заряда: $E$ не меняется (коэффициент $= 1$)."},{"q":"Силовые линии однородного поля идут параллельно с плотностью $5$ линий/см. У сильного поля плотность $20$ линий/см. Во сколько раз больше $E$?","ans":4,"tol":0.2,"why":"Густота линий пропорциональна $E$: $20/5 = 4$ раза."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p17-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="p17-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p17-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p17-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p17-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p17-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p17-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p17-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p17-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p17-iv5-fb');
|
||
const wh = document.getElementById('p17-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p17-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('p17-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p17-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p17-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p17-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p17-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp16_iv5(){
|
||
const TASKS = [{"q":"У атома водорода $1$ электрон. Каков заряд электронной оболочки (в единицах $e$)? Введите модуль.","ans":1,"tol":0.1,"why":"Один электрон с зарядом $-e$. Модуль $|q| = e = 1$ в этих единицах."},{"q":"Электрон имеет заряд $e = 1{,}6 \\cdot 10^{-19}$ Кл. Какой суммарный заряд (Кл) у $n = 10^{20}$ электронов? Дайте ответ в виде $\\times 10^{1}$ Кл.","ans":16,"tol":0.5,"why":"$q = ne = 10^{20} \\cdot 1{,}6 \\cdot 10^{-19} = 16$ Кл."},{"q":"Какой заряд имеет атомное ядро углерода $^{12}_{6}$C (в единицах $e$)?","ans":6,"tol":0.1,"why":"У углерода $Z = 6$ протонов, каждый с зарядом $+e$. Заряд ядра $= +6e$."},{"q":"Атом нейтрален. Сколько электронов вокруг ядра кислорода $^{16}_{8}$O?","ans":8,"tol":0.1,"why":"В нейтральном атоме число электронов равно числу протонов: $Z = 8$."},{"q":"Сколько Кл составляет заряд $5$ протонов? ($e = 1{,}6 \\cdot 10^{-19}$ Кл). Ответ $\\times 10^{-19}$.","ans":8,"tol":0.2,"why":"$q = 5e = 5 \\cdot 1{,}6 \\cdot 10^{-19} = 8 \\cdot 10^{-19}$ Кл."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p16-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="p16-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p16-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p16-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p16-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p16-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p16-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p16-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p16-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p16-iv5-fb');
|
||
const wh = document.getElementById('p16-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p16-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('p16-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p16-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p16-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p16-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p16-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp14_iv5(){
|
||
const TASKS = [{"q":"К незаряженному проводнику поднесли $+$-заряженный шар. Какой заряд индуцируется на ближнем конце проводника?","ans":-1,"tol":0.1,"why":"Свободные электроны притянутся к $+$ — на ближнем конце $-1$ (отрицательный заряд). Введите $-1$."},{"q":"Шар с зарядом $q = +20$ нКл коснулся незаряженного такого же шара. Заряд (нКл) на одном шаре после разделения?","ans":10,"tol":0.2,"why":"Заряды выравниваются: $q/2 = 10$ нКл."},{"q":"Электроскоп заряжен зарядом $q = 5$ нКл. Что произойдёт с углом отклонения лепестков, если к нему поднести заряд того же знака? ($1$ — уменьшится, $2$ — увеличится, $3$ — не изменится)","ans":2,"tol":0.1,"why":"Одноимённые заряды отталкиваются — лепестки разойдутся сильнее."},{"q":"Если поднести $+$-заряд к нейтральному шару и заземлить его (отвести электроны), какой заряд останется на шаре после удаления $+$-заряда? ($1$ — положительный, $-1$ — отрицательный)","ans":-1,"tol":0.1,"why":"Электроны притянулись и не ушли — шар стал отрицательным. Ответ $-1$."},{"q":"Заряженная палочка приближается к листку фольги. Лепесток отклоняется на угол $\\alpha$. Если палочку удалить, какой будет $\\alpha$?","ans":0,"tol":0.1,"why":"Без внешнего поля индуцированные заряды перераспределяются обратно — отклонение $0$."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p14-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="p14-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p14-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p14-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p14-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p14-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p14-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p14-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p14-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p14-iv5-fb');
|
||
const wh = document.getElementById('p14-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p14-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('p14-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p14-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p14-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p14-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p14-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp13_iv5(){
|
||
const TASKS = [{"q":"У проводника плотность свободных электронов $n = 10^{29}$ м⁻³, у диэлектрика $\\sim 10^{17}$ м⁻³. Во сколько раз больше носителей у проводника? (степень 10)","ans":12,"tol":0.5,"why":"$n_{пр}/n_{ди} = 10^{29}/10^{17} = 10^{12}$."},{"q":"Стержень проводника $L = 10$ см заряжен. Если соединить с таким же незаряженным, какая часть (в %) заряда уйдёт на второй?","ans":50,"tol":1,"why":"Заряды выравниваются, на каждом — половина исходного: $50\\,\\%$."},{"q":"Какой материал лучший проводник: $1$ — стекло, $2$ — сухое дерево, $3$ — медь, $4$ — пластик? Введите номер.","ans":3,"tol":0.1,"why":"Металлы (медь) — лучшие проводники из перечисленных."},{"q":"У диэлектрика свободных зарядов нет, но связанные могут поляризоваться. Сколько свободных носителей в идеальном диэлектрике?","ans":0,"tol":0.1,"why":"В идеальном диэлектрике $n_{своб} = 0$ — есть только связанные заряды атомов и молекул."},{"q":"Через тело прошло за $t = 2$ с $q = 4$ Кл. Какова сила тока $I$ (А)?","ans":2,"tol":0.05,"why":"$I = q/t = 4/2 = 2$ А."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p13-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="p13-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p13-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p13-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p13-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p13-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p13-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p13-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p13-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p13-iv5-fb');
|
||
const wh = document.getElementById('p13-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p13-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('p13-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p13-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p13-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p13-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p13-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
|
||
function _initp12_iv5(){
|
||
const TASKS = [{"q":"Два одинаковых шарика имели заряды $q_1 = +6$ мкКл и $q_2 = -2$ мкКл. После соприкосновения и разделения, какой заряд (мкКл) остался на каждом?","ans":2,"tol":0.05,"why":"При контакте одинаковых шаров заряды выравниваются: $q = (q_1 + q_2)/2 = (+6 - 2)/2 = +2$ мкКл."},{"q":"У эбонитовой палочки $-30$ нКл, у шерсти $+30$ нКл. Какой суммарный заряд (нКл) системы по закону сохранения заряда?","ans":0,"tol":0.5,"why":"Заряд изолированной системы сохраняется. Если до трения было $0$ — и после $0$: $-30 + 30 = 0$."},{"q":"У шарика заряд $q = +4$ мкКл. Сколько электронов нужно добавить, чтобы он стал нейтральным? ($e = 1{,}6 \\cdot 10^{-19}$ Кл). Ответ дайте в единицах $\\times 10^{13}$.","ans":2.5,"tol":0.1,"why":"$n = q/e = 4 \\cdot 10^{-6} / 1{,}6 \\cdot 10^{-19} = 2{,}5 \\cdot 10^{13}$ электронов."},{"q":"Тело потеряло $n = 5 \\cdot 10^{12}$ электронов. Каков стал его заряд (мкКл)? ($e = 1{,}6 \\cdot 10^{-19}$ Кл)","ans":0.8,"tol":0.02,"why":"$q = n \\cdot e = 5 \\cdot 10^{12} \\cdot 1{,}6 \\cdot 10^{-19} = 8 \\cdot 10^{-7}$ Кл $= 0{,}8$ мкКл (положительный, т. к. потерял электроны)."},{"q":"Если соединить шары с зарядами $q_1 = +10$ нКл и $q_2 = +6$ нКл одинакового размера, какой заряд (нКл) будет на каждом после разделения?","ans":8,"tol":0.2,"why":"$q = (q_1 + q_2)/2 = 16/2 = 8$ нКл."}];
|
||
let i = 0, ok = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p12-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="p12-iv5-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p12-iv5-go">Ответ</button>'
|
||
+'<button class="btn" id="p12-iv5-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p12-iv5-next">Следующая</button></div>'
|
||
+'<details class="spoiler" id="p12-iv5-why-wrap" style="margin-top:8px;display:none"><summary>Решение</summary><div class="spoiler-body">'+t.why+'</div></details>'
|
||
+'<div class="feedback" id="p12-iv5-fb"></div>';
|
||
if (window.renderMathInElement) try { renderMathInElement(wrap, {delimiters:[{left:'$',right:'$',display:false}],throwOnError:false}); } catch(e){}
|
||
document.getElementById('p12-iv5-go').onclick = () => {
|
||
const v = parseFloat(document.getElementById('p12-iv5-inp').value.replace(',','.'));
|
||
const fb = document.getElementById('p12-iv5-fb');
|
||
const wh = document.getElementById('p12-iv5-why-wrap');
|
||
if (Math.abs(v - t.ans) <= t.tol) {
|
||
fb.className = 'feedback ok'; fb.innerHTML = 'Верно!'; ok++;
|
||
document.getElementById('p12-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('p12-iv5-hint').onclick = () => {
|
||
const wh = document.getElementById('p12-iv5-why-wrap');
|
||
wh.style.display = wh.style.display === 'block' ? 'none' : 'block';
|
||
};
|
||
document.getElementById('p12-iv5-next').onclick = () => {
|
||
i = (i + 1) % TASKS.length;
|
||
document.getElementById('p12-tasks5-i').textContent = i + 1;
|
||
render();
|
||
if (ok === TASKS.length && !awarded) { awarded = true; if (typeof addXp === 'function') addXp(20, 'p12-iv5'); }
|
||
};
|
||
}
|
||
render();
|
||
}
|
||
doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||
<meta http-equiv="Pragma" content="no-cache">
|
||
<meta http-equiv="Expires" content="0">
|
||
<title>Физика 8 · Глава 2 · «Электромагнитные явления»</title>
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
|
||
<link rel="stylesheet" href="/css/phys8-interactives.css">
|
||
<link rel="stylesheet" href="/css/phys8-design-system.css">
|
||
<link rel="stylesheet" href="/css/phys-textbook-widgets.css">
|
||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
|
||
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
|
||
<script src="/js/api.js" defer></script>
|
||
<script src="/js/xp.js" defer></script>
|
||
<script src="/js/g3d.js" defer></script>
|
||
<script src="/js/phys.js" defer></script>
|
||
<script src="/js/phys8-helpers.js" defer></script>
|
||
<script src="/js/phys8-drag.js" defer></script>
|
||
<script src="/js/phys8-anim.js" defer></script>
|
||
<script src="/js/optics.js" defer></script>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{
|
||
--bg:#fffbeb; --card:#fff; --card-soft:#f8fafc; --text:#0f172a; --ink:#0f172a; --muted:#64748b;
|
||
--border:#e2e8f0; --sh:0 1px 3px rgba(0,0,0,.06); --sh2:0 4px 14px rgba(0,0,0,.08);
|
||
--pri:#7c3aed; --pri2:#5b21b6; --pri-soft:#ede9fe;
|
||
--acc:#a78bfa; --acc2:#7c3aed; --acc-soft:#ede9fe;
|
||
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
|
||
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
|
||
}
|
||
.dark{--bg:#0a0a0e; --card:#13120a; --card-soft:#18160a; --text:#fef9e7; --ink:#fef9e7; --muted:#a39070; --border:#2a2512}
|
||
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
|
||
html,body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.55;font-size:15px}
|
||
button,input,select,textarea{font-family:inherit;font-size:inherit}
|
||
button{cursor:pointer;border:0;background:transparent;color:inherit}
|
||
a{color:inherit;text-decoration:none}
|
||
.ic{width:16px;height:16px;display:inline-block;flex-shrink:0;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;vertical-align:middle}
|
||
|
||
.hdr{position:relative;background:linear-gradient(110deg,#78350f 0%,#d97706 55%,#fcd34d 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(255,255,255,.2);min-height:130px}
|
||
.hdr-row{position:relative;z-index:1;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
|
||
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:900;letter-spacing:-.01em;line-height:1.3;padding-top:4px}
|
||
.hdr-sub{font-size:.85rem;opacity:.88;margin-top:6px;font-weight:500;line-height:1.4}
|
||
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
||
.hdr-btn{padding:7px 12px;border-radius:9px;background:rgba(255,255,255,.14);color:#fff;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;text-decoration:none}
|
||
.hdr-btn:hover{background:rgba(255,255,255,.24)}
|
||
|
||
.main{max-width:1240px;margin:0 auto;padding:22px;width:100%;display:grid;grid-template-columns:1fr 280px;gap:24px}
|
||
@media(max-width:980px){.main{grid-template-columns:1fr;padding:14px}}
|
||
.col-main{min-width:0}
|
||
|
||
.hero{background:linear-gradient(135deg,var(--pri-soft) 0%,var(--acc-soft) 50%,var(--pri-soft) 100%);background-size:200% 200%;animation:heroShift 12s ease-in-out infinite;border:1px solid var(--border);border-radius:18px;padding:24px 22px;margin-bottom:24px;position:relative;overflow:hidden}
|
||
@keyframes heroShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
|
||
.hero h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px;letter-spacing:-.01em}
|
||
.hero p{font-size:.95rem;color:var(--text);opacity:.88;margin-bottom:14px;max-width:640px}
|
||
.hero-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
|
||
.btn-primary{padding:11px 22px;background:linear-gradient(135deg,var(--pri),var(--pri2));color:#fff;border-radius:11px;font-weight:700;font-size:.92rem;display:inline-flex;align-items:center;gap:8px;box-shadow:var(--sh2);transition:transform .15s,box-shadow .15s}
|
||
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(0,0,0,.18)}
|
||
.hero-progress{flex:1;min-width:200px;max-width:280px}
|
||
.hp-label{font-size:.74rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;display:block;margin-bottom:5px}
|
||
.hp-bar{height:8px;background:rgba(0,0,0,.12);border-radius:5px;overflow:hidden}
|
||
.hp-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:5px;width:0%;transition:width .6s cubic-bezier(.16,1,.3,1)}
|
||
.hp-text{font-size:.78rem;color:var(--muted);font-weight:700;margin-top:4px;display:block}
|
||
.hero-xp-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:linear-gradient(135deg,var(--warn,#f59e0b),var(--pri));color:#fff;border-radius:99px;font-size:.82rem;font-weight:800;letter-spacing:.02em;box-shadow:0 4px 12px rgba(0,0,0,.18);font-family:'Unbounded',sans-serif}
|
||
|
||
.psel{margin-bottom:24px}
|
||
.psel-title{font-size:.72rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:10px}
|
||
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
|
||
.psel-card{background:var(--card);border:1.5px solid var(--border);border-radius:13px;padding:14px;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s;text-align:left;position:relative}
|
||
.psel-card:hover{transform:translateY(-3px);box-shadow:var(--sh2);border-color:var(--pri)}
|
||
.psel-card.active{border-color:var(--pri);background:linear-gradient(135deg,var(--pri-soft),var(--card));box-shadow:var(--sh2)}
|
||
.psel-card.active::after{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:13px 13px 0 0}
|
||
.psel-num{font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;color:var(--pri);text-transform:uppercase;letter-spacing:.08em;margin-bottom:5px}
|
||
.psel-name{font-size:.86rem;font-weight:700;color:var(--text);line-height:1.3;margin-bottom:8px}
|
||
.psel-prog{height:4px;background:rgba(0,0,0,.10);border-radius:3px;overflow:hidden}
|
||
.psel-prog-fill{height:100%;background:var(--pri);width:0%;transition:width .4s}
|
||
.psel-card.final{background:linear-gradient(135deg,var(--acc-soft),var(--pri-soft))}
|
||
.psel-card.final .psel-num{color:var(--warn)}
|
||
|
||
.sec[id="sec-p12"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p13"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p14"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p15"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p16"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p17"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p18"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p19"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p20"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p21"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p22"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p23"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p24"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p25"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p26"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p27"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p28"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p29"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p30"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p31"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-final2"]{ --sec-acc:#d97706; --sec-acc-d:#92400e; --sec-acc-soft:#fef3c7; }
|
||
|
||
.sec{display:none;position:relative;animation:fadeIn .35s ease}
|
||
.sec.active{display:block}
|
||
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
|
||
.sec-header{margin-bottom:22px;padding-bottom:14px;border-bottom:2px solid var(--sec-acc-soft,var(--pri-soft));position:relative;z-index:1}
|
||
.sec-num{display:inline-block;padding:4px 10px;background:linear-gradient(135deg,var(--sec-acc,var(--pri)),var(--sec-acc-d,var(--pri2)));color:#fff;border-radius:7px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;margin-bottom:8px}
|
||
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.6rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));letter-spacing:-.01em;line-height:1.25}
|
||
|
||
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:18px 20px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04),0 8px 24px rgba(0,0,0,.04);position:relative;z-index:1;transition:transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s}
|
||
.card:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(0,0,0,.06),0 16px 36px rgba(0,0,0,.08)}
|
||
.card-header{display:flex;align-items:center;gap:10px;margin-bottom:12px;padding-bottom:10px;border-bottom:1px dashed var(--border)}
|
||
.card-icon{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff}
|
||
.card-icon.repeat{background:#0ea5e9}.card-icon.theory{background:#8b5cf6}.card-icon.algo{background:#f59e0b}.card-icon.rule{background:#ec4899}.card-icon.example{background:#10b981}.card-icon.oral{background:#06b6d4}
|
||
.card-icon .ic{width:18px;height:18px}
|
||
.card-title{font-family:'Unbounded',sans-serif;font-size:.82rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);flex:1}
|
||
.card-num{font-size:.74rem;font-weight:700;color:var(--muted);background:var(--sec-acc-soft,var(--pri-soft));padding:3px 7px;border-radius:5px}
|
||
.card-body{font-size:.94rem;line-height:1.65}
|
||
.card-body p{margin-bottom:8px}
|
||
.card-body p:last-child{margin-bottom:0}
|
||
|
||
.btn{padding:8px 16px;border-radius:8px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:600;font-size:.88rem;transition:background .15s,border-color .15s,transform .1s}
|
||
.btn:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
|
||
.btn:active{transform:scale(.96)}
|
||
.btn.primary{background:var(--sec-acc,var(--pri));color:#fff;border-color:var(--sec-acc,var(--pri))}
|
||
.btn.primary:hover{background:var(--sec-acc-d,var(--pri2));border-color:var(--sec-acc-d,var(--pri2))}
|
||
|
||
.feedback{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none}
|
||
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
|
||
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
|
||
|
||
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
|
||
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
|
||
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
||
.sidecard-row{margin-bottom:8px;font-size:.86rem;line-height:1.6}
|
||
.sidecard-row b{color:var(--pri);font-weight:700}
|
||
.sidecard-row:last-child{margin-bottom:0}
|
||
@media(max-width:980px){.col-side{position:static;max-height:none}}
|
||
|
||
.xp-card{background:linear-gradient(135deg,var(--acc-soft),var(--pri-soft));border:1.5px solid var(--acc);border-radius:12px;padding:14px;margin-bottom:14px}
|
||
.xp-card-title{font-size:.68rem;font-weight:800;color:var(--acc2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between}
|
||
.xp-level{font-size:1.1rem;font-weight:900;color:var(--acc2);font-family:'Unbounded',sans-serif}
|
||
.xp-bar{height:9px;background:rgba(0,0,0,.10);border-radius:6px;overflow:hidden;margin:7px 0}
|
||
.xp-fill{height:100%;background:linear-gradient(90deg,var(--acc),var(--pri));border-radius:6px;transition:width .5s cubic-bezier(.4,0,.2,1)}
|
||
.xp-nums{font-size:.74rem;color:var(--muted);display:flex;justify-content:space-between}
|
||
|
||
.sec-nav{display:flex;gap:10px;margin-top:24px;padding-top:20px;border-top:1px solid var(--border);justify-content:space-between;flex-wrap:wrap}
|
||
.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
|
||
|
||
.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,var(--pri),var(--acc));color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(0,0,0,.32);z-index:1002;display:none;align-items:center;gap:8px;max-width:340px}
|
||
.ach-popup.show{display:flex}
|
||
|
||
.col-side-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.42);z-index:9990;display:none}
|
||
.col-side-backdrop.show{display:block}
|
||
@media(min-width:981px){#sidebar-btn{display:none}.col-side-backdrop.show{display:none}}
|
||
@media(max-width:980px){
|
||
.col-side{position:fixed;top:0;right:0;height:100vh;width:300px;max-width:88vw;background:var(--bg);box-shadow:-12px 0 24px rgba(0,0,0,.18);padding:18px 16px;overflow-y:auto;transform:translateX(100%);transition:transform .25s ease;z-index:9991;max-height:none}
|
||
.col-side.open{transform:none}
|
||
}
|
||
|
||
.search-modal{position:fixed;inset:0;background:rgba(15,23,42,.55);backdrop-filter:blur(4px);z-index:9993;display:none;align-items:flex-start;justify-content:center;padding-top:14vh}
|
||
.search-modal.show{display:flex}
|
||
.search-box{background:var(--bg);border:1px solid var(--border);border-radius:14px;width:560px;max-width:92vw;max-height:70vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 64px rgba(0,0,0,.4)}
|
||
.search-input{padding:14px 16px;font-size:1rem;border:0;border-bottom:1px solid var(--border);background:transparent;color:var(--text);outline:none}
|
||
.search-results{flex:1;overflow-y:auto;padding:6px 0}
|
||
.search-row{display:block;padding:8px 16px;cursor:pointer;border-bottom:1px solid var(--border);text-align:left;background:transparent;border:0;width:100%;color:var(--text)}
|
||
.search-row:hover,.search-row.active{background:var(--sec-acc-soft,var(--pri-soft))}
|
||
.search-row .sr-kind{font-size:.7rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px}
|
||
.search-row .sr-title{font-weight:700;font-size:.92rem;color:var(--text)}
|
||
.search-row .sr-desc{font-size:.8rem;color:var(--muted);margin-top:2px}
|
||
.search-empty{padding:20px;text-align:center;color:var(--muted);font-size:.88rem}
|
||
.search-foot{padding:8px 14px;border-top:1px solid var(--border);font-size:.74rem;color:var(--muted);display:flex;gap:14px}
|
||
.search-foot kbd{padding:2px 6px;background:var(--card);border:1px solid var(--border);border-radius:4px;font-family:'JetBrains Mono',monospace;font-size:.72rem}
|
||
|
||
.sec{transition:opacity .25s}
|
||
</style>
|
||
</head>
|
||
<body class="p8-theme-electric">
|
||
|
||
<header class="p8-hero">
|
||
<div class="p8-hero-wm"><svg viewBox="0 0 100 100" aria-hidden="true">
|
||
<path d="M55 8 L25 56 L46 56 L40 92 L75 38 L52 38 L60 8 Z"/>
|
||
</svg></div>
|
||
<div class="p8-hero-meter" id="p8-meter-ch2"><span id="p8-meter-val">0.5</span> А</div>
|
||
<div class="p8-hero-inner">
|
||
<div class="p8-hero-eyebrow">Глава 2 · 20 параграфов</div>
|
||
<h1 class="p8-hero-title">Электромагнитные явления</h1>
|
||
<div class="p8-hero-sub">Заряд, ток, цепь, магнитное поле. Конструируйте цепи из компонентов, перемещайте заряды, наблюдайте за искрами и полями.</div>
|
||
<div class="hdr-side" style="margin-top:18px;display:flex;gap:8px;flex-wrap:wrap;position:relative;z-index:1">
|
||
<a href="/textbook/physics-8" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 8</a>
|
||
<button id="search-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> Поиск</button>
|
||
<button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
|
||
<button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="main">
|
||
<div class="col-main">
|
||
|
||
<section class="hero">
|
||
<h2>Электромагнитные явления — от заряда до магнита</h2>
|
||
<p>Заряды притягиваются и отталкиваются, образуют электрическое поле. По проводнику течёт ток, и закон Ома связывает $U$, $I$, $R$. У постоянных магнитов и проводников с током есть магнитное поле.</p>
|
||
<div class="hero-row">
|
||
<button class="btn-primary" onclick="goTo('p12')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 12</button>
|
||
<div class="hero-progress">
|
||
<span class="hp-label">Прогресс по главе</span>
|
||
<div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div>
|
||
<span id="hero-hp-text" class="hp-text">0%</span>
|
||
</div>
|
||
<div id="hero-xp-badge" class="hero-xp-badge" data-gamified></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="psel">
|
||
<div class="psel-title">Параграфы главы</div>
|
||
<div id="psel-grid" class="psel-grid"></div>
|
||
</section>
|
||
|
||
<section id="sec-p12" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p12" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="35" cy="50" r="14" fill="currentColor"/><circle cx="65" cy="50" r="14" fill="currentColor"/><path d="M40 50 L60 50 M50 40 L50 60" stroke="currentColor" stroke-width="3" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 12</span><h2 class="sec-h">Электризация тел. Взаимодействие зарядов</h2></div><div id="p12-body"></div></section>
|
||
<section id="sec-p13" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p13" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="20" y="40" width="60" height="20" fill="none" stroke="currentColor" stroke-width="4"/><circle cx="35" cy="50" r="3" fill="currentColor"/><circle cx="50" cy="50" r="3" fill="currentColor"/><circle cx="65" cy="50" r="3" fill="currentColor"/></svg></div><div class="sec-header"><span class="sec-num">§ 13</span><h2 class="sec-h">Проводники и диэлектрики</h2></div><div id="p13-body"></div></section>
|
||
<section id="sec-p14" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p14" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="24" fill="none" stroke="currentColor" stroke-width="4"/><path d="M50 26 L50 14 M50 86 L50 74 M26 50 L14 50 M86 50 L74 50" stroke="currentColor" stroke-width="4"/></svg></div><div class="sec-header"><span class="sec-num">§ 14</span><h2 class="sec-h">Электризация через влияние</h2></div><div id="p14-body"></div></section>
|
||
<section id="sec-p15" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p15" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="16" fill="currentColor"/><path d="M50 30 L50 18 M50 82 L50 70 M30 50 L18 50 M82 50 L70 50" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 15</span><h2 class="sec-h">Электрический заряд. Элементарный заряд</h2></div><div id="p15-body"></div></section>
|
||
<section id="sec-p16" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p16" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="6" fill="currentColor"/><ellipse cx="50" cy="50" rx="32" ry="14" fill="none" stroke="currentColor" stroke-width="2.5"/><ellipse cx="50" cy="50" rx="14" ry="32" fill="none" stroke="currentColor" stroke-width="2.5"/></svg></div><div class="sec-header"><span class="sec-num">§ 16</span><h2 class="sec-h">Строение атома. Ионы</h2></div><div id="p16-body"></div></section>
|
||
<section id="sec-p17" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p17" aria-hidden="true"><svg viewBox="0 0 100 100"><line x1="20" y1="50" x2="80" y2="50" stroke="currentColor" stroke-width="3"/><line x1="20" y1="35" x2="80" y2="65" stroke="currentColor" stroke-width="3"/><line x1="20" y1="65" x2="80" y2="35" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 17</span><h2 class="sec-h">Электрическое поле. Электрическое напряжение</h2></div><div id="p17-body"></div></section>
|
||
<section id="sec-p18" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p18" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M30 50 L70 50" stroke="currentColor" stroke-width="5" fill="none"/><path d="M65 45 L70 50 L65 55" stroke="currentColor" stroke-width="3" fill="none"/><text x="30" y="40" font-family="Inter" font-size="14" font-weight="700" fill="currentColor">U</text></svg></div><div class="sec-header"><span class="sec-num">§ 18</span><h2 class="sec-h">Единица электрического напряжения. Расчёт работы в электрическом поле</h2></div><div id="p18-body"></div></section>
|
||
<section id="sec-p19" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p19" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="20" y="40" width="14" height="20" fill="currentColor"/><rect x="38" y="35" width="6" height="30" fill="currentColor"/><line x1="50" y1="50" x2="80" y2="50" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 19</span><h2 class="sec-h">Электрический ток. Источники тока</h2></div><div id="p19-body"></div></section>
|
||
<section id="sec-p20" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p20" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M20 70 L40 30 L60 70 L80 30" stroke="currentColor" stroke-width="4" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 20</span><h2 class="sec-h">Сила и направление электрического тока</h2></div><div id="p20-body"></div></section>
|
||
<section id="sec-p21" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p21" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="20" y="40" width="60" height="20" fill="none" stroke="currentColor" stroke-width="3"/><path d="M30 50 L50 50 M55 45 L60 50 L55 55" stroke="currentColor" stroke-width="2" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 21</span><h2 class="sec-h">Электрическая цепь. Измерение силы тока и напряжения</h2></div><div id="p21-body"></div></section>
|
||
<section id="sec-p22" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p22" aria-hidden="true"><svg viewBox="0 0 100 100"><text x="50" y="60" font-family="Unbounded" font-size="36" font-weight="900" fill="currentColor" text-anchor="middle">Ω</text></svg></div><div class="sec-header"><span class="sec-num">§ 22</span><h2 class="sec-h">Связь силы тока и напряжения. Закон Ома для участка электрической цепи</h2></div><div id="p22-body"></div></section>
|
||
<section id="sec-p23" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p23" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M20 50 Q30 20, 40 50 T60 50 T80 50" stroke="currentColor" stroke-width="4" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 23</span><h2 class="sec-h">Единица сопротивления. Расчёт сопротивления</h2></div><div id="p23-body"></div></section>
|
||
<section id="sec-p24" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p24" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M15 50 L25 50 L30 40 L40 60 L50 40 L60 60 L70 40 L75 50 L85 50" stroke="currentColor" stroke-width="3" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 24</span><h2 class="sec-h">Последовательное соединение проводников. Реостат</h2></div><div id="p24-body"></div></section>
|
||
<section id="sec-p25" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p25" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M20 30 L80 30 M20 70 L80 70 M50 30 L50 70" stroke="currentColor" stroke-width="3" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 25</span><h2 class="sec-h">Параллельное соединение проводников</h2></div><div id="p25-body"></div></section>
|
||
<section id="sec-p26" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p26" aria-hidden="true"><svg viewBox="0 0 100 100"><text x="50" y="60" font-family="Unbounded" font-size="32" font-weight="900" fill="currentColor" text-anchor="middle">P</text></svg></div><div class="sec-header"><span class="sec-num">§ 26</span><h2 class="sec-h">Работа и мощность электрического тока. Закон Джоуля — Ленца</h2></div><div id="p26-body"></div></section>
|
||
<section id="sec-p27" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p27" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="28" fill="none" stroke="currentColor" stroke-width="4"/><path d="M28 50 L72 50 M50 28 L50 72" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 27</span><h2 class="sec-h">Использование и экономия электроэнергии. Безопасность</h2></div><div id="p27-body"></div></section>
|
||
<section id="sec-p28" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p28" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="20" y="42" width="60" height="16" fill="currentColor"/><text x="32" y="56" font-family="Unbounded" font-size="14" font-weight="900" fill="#fff" text-anchor="middle">N</text><text x="68" y="56" font-family="Unbounded" font-size="14" font-weight="900" fill="#fff" text-anchor="middle">S</text></svg></div><div class="sec-header"><span class="sec-num">§ 28</span><h2 class="sec-h">Постоянные магниты</h2></div><div id="p28-body"></div></section>
|
||
<section id="sec-p29" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p29" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="6" fill="currentColor"/><ellipse cx="50" cy="50" rx="36" ry="18" fill="none" stroke="currentColor" stroke-width="3"/><path d="M82 38 L86 48 L78 46" stroke="currentColor" stroke-width="3" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 29</span><h2 class="sec-h">Магнитное поле</h2></div><div id="p29-body"></div></section>
|
||
<section id="sec-p30" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p30" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="6" fill="currentColor"/><line x1="50" y1="20" x2="50" y2="80" stroke="currentColor" stroke-width="3"/><line x1="20" y1="50" x2="80" y2="50" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 30</span><h2 class="sec-h">Магнитное поле тока</h2></div><div id="p30-body"></div></section>
|
||
<section id="sec-p31" class="sec">
|
||
<div class="p8-sec-wm" id="p8-sec-wm-p31" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M30 30 Q40 20, 50 30 T70 30 M30 50 Q40 40, 50 50 T70 50 M30 70 Q40 60, 50 70 T70 70" stroke="currentColor" stroke-width="3" fill="none"/><rect x="48" y="20" width="4" height="60" fill="currentColor"/></svg></div><div class="sec-header"><span class="sec-num">§ 31</span><h2 class="sec-h">Магнитное поле прямого проводника и катушки с током. Электромагнит</h2></div><div id="p31-body"></div></section>
|
||
<section id="sec-final2" class="sec"><div class="sec-header"><span class="sec-num">★</span><h2 class="sec-h">Финал главы</h2></div><div id="final2-body"></div></section>
|
||
|
||
</div>
|
||
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
|
||
<div class="col-side-backdrop" id="col-side-backdrop"></div>
|
||
</main>
|
||
|
||
<footer class="foot">Интерактивный учебник «Физика 8» · Глава 2 · «Электромагнитные явления» · LearnSpace</footer>
|
||
|
||
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><polygon points="12,2 22,20 2,20"/></svg><span id="ach-text">Достижение!</span></div>
|
||
<div id="search-modal" class="search-modal" role="dialog">
|
||
<div class="search-box">
|
||
<input type="text" id="search-input" class="search-input" placeholder="Поиск…" autocomplete="off">
|
||
<div id="search-results" class="search-results"></div>
|
||
<div class="search-foot"><span><kbd>↑↓</kbd> навигация</span><span><kbd>Enter</kbd> открыть</span><span><kbd>Esc</kbd> закрыть</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
'use strict';
|
||
|
||
const STATE = { current:'p12', progress:{}, achievements:new Map(), xp:0, level:1 };
|
||
const TOTAL_PARAS = 21;
|
||
const _TB_SLUG = 'physics-8-ch2';
|
||
const LS_PREFIX = 'physics8_ch2';
|
||
const LS_XP = 'physics8_xp';
|
||
|
||
const PARAS = [
|
||
{ id:'p12', num:'\u00a7 12', name:'Электризация тел. Взаимодействие зарядов', sub:'Два рода зарядов' },
|
||
{ id:'p13', num:'\u00a7 13', name:'Проводники и диэлектрики', sub:'Свободные носители' },
|
||
{ id:'p14', num:'\u00a7 14', name:'Электризация через влияние', sub:'Индукция' },
|
||
{ id:'p15', num:'\u00a7 15', name:'Электрический заряд. Элементарный заряд', sub:'$e = 1{,}6 \\cdot 10^{-19}$ Кл' },
|
||
{ id:'p16', num:'\u00a7 16', name:'Строение атома. Ионы', sub:'Ядро + электроны' },
|
||
{ id:'p17', num:'\u00a7 17', name:'Электрическое поле. Электрическое напряжение', sub:'$U$ как работа поля' },
|
||
{ id:'p18', num:'\u00a7 18', name:'Единица электрического напряжения. Расчёт работы в электрическом поле', sub:'$A = qU$' },
|
||
{ id:'p19', num:'\u00a7 19', name:'Электрический ток. Источники тока', sub:'Упорядоченное движение' },
|
||
{ id:'p20', num:'\u00a7 20', name:'Сила и направление электрического тока', sub:'$I = q/t$' },
|
||
{ id:'p21', num:'\u00a7 21', name:'Электрическая цепь. Измерение силы тока и напряжения', sub:'A — последов., V — паралл.' },
|
||
{ id:'p22', num:'\u00a7 22', name:'Связь силы тока и напряжения. Закон Ома для участка электрической цепи', sub:'$I = U/R$' },
|
||
{ id:'p23', num:'\u00a7 23', name:'Единица сопротивления. Расчёт сопротивления', sub:'$R = \\rho l/S$' },
|
||
{ id:'p24', num:'\u00a7 24', name:'Последовательное соединение проводников. Реостат', sub:'$R = R_1 + R_2$' },
|
||
{ id:'p25', num:'\u00a7 25', name:'Параллельное соединение проводников', sub:'$1/R = 1/R_1 + 1/R_2$' },
|
||
{ id:'p26', num:'\u00a7 26', name:'Работа и мощность электрического тока. Закон Джоуля — Ленца', sub:'$P = UI$, $Q = I^2 Rt$' },
|
||
{ id:'p27', num:'\u00a7 27', name:'Использование и экономия электроэнергии. Безопасность', sub:'кВт·ч, ТБ' },
|
||
{ id:'p28', num:'\u00a7 28', name:'Постоянные магниты', sub:'N, S, поле Земли' },
|
||
{ id:'p29', num:'\u00a7 29', name:'Магнитное поле', sub:'$\\vec{B}$, линии' },
|
||
{ id:'p30', num:'\u00a7 30', name:'Магнитное поле тока', sub:'Опыт Эрстеда' },
|
||
{ id:'p31', num:'\u00a7 31', name:'Магнитное поле прямого проводника и катушки с током. Электромагнит', sub:'Правило правой руки' },
|
||
{ id:'final2', num:'\u2605', name:'Финал главы', sub:'Итоги · 10 боссов', final:true }
|
||
];
|
||
PARAS.forEach(p => { STATE.progress[p.id] = 0; });
|
||
|
||
const ACH_LABELS = {
|
||
start:"Начало главы 2!",
|
||
p12_done:"Электризация тел. Взаимодействие зарядов освоен!",
|
||
p13_done:"Проводники и диэлектрики освоен!",
|
||
p14_done:"Электризация через влияние освоен!",
|
||
p15_done:"Электрический заряд. Элементарный заряд освоен!",
|
||
p16_done:"Строение атома. Ионы освоен!",
|
||
p17_done:"Электрическое поле. Электрическое напряжение освоен!",
|
||
p18_done:"Единица электрического напряжения. Расчёт работы в электрическом поле освоен!",
|
||
p19_done:"Электрический ток. Источники тока освоен!",
|
||
p20_done:"Сила и направление электрического тока освоен!",
|
||
p21_done:"Электрическая цепь. Измерение силы тока и напряжения освоен!",
|
||
p22_done:"Связь силы тока и напряжения. Закон Ома для участка электрической цепи освоен!",
|
||
p23_done:"Единица сопротивления. Расчёт сопротивления освоен!",
|
||
p24_done:"Последовательное соединение проводников. Реостат освоен!",
|
||
p25_done:"Параллельное соединение проводников освоен!",
|
||
p26_done:"Работа и мощность электрического тока. Закон Джоуля — Ленца освоен!",
|
||
p27_done:"Использование и экономия электроэнергии. Безопасность освоен!",
|
||
p28_done:"Постоянные магниты освоен!",
|
||
p29_done:"Магнитное поле освоен!",
|
||
p30_done:"Магнитное поле тока освоен!",
|
||
p31_done:"Магнитное поле прямого проводника и катушки с током. Электромагнит освоен!",
|
||
ch2_done:"Глава 2 пройдена!",
|
||
em_master:"Мастер электромагнетизма — все боссы главы 2 повержены!"
|
||
};
|
||
|
||
const SIDEBARS = {
|
||
p12:{title:"Шпаргалка § 12",rows:[
|
||
["2 рода зарядов","+ (стекло о шёлк), − (эбонит о шерсть)"],
|
||
["Одноимённые","отталкиваются"],
|
||
["Разноимённые","притягиваются"],
|
||
["При трении","заряд один — +, другой — −"],
|
||
["Сумма","сохраняется (закон сохр. заряда)"]
|
||
]},
|
||
p13:{title:"Шпаргалка § 13",rows:[
|
||
["Проводники","есть свободные носители"],
|
||
["Примеры пров.","металлы, графит, растворы солей, кислот, щелочей"],
|
||
["Диэлектрики","эбонит, стекло, дерево, пластик, дист. вода"],
|
||
["В проводнике","заряд по поверхности"],
|
||
["В диэлектрике","остаётся где появился"]
|
||
]},
|
||
p14:{title:"Шпаргалка § 14",rows:[
|
||
["Индукция","перераспределение зарядов в проводнике"],
|
||
["Без касания","нейтральный проводник $\\to$ разделение"],
|
||
["Ближний конец","заряд противоположного знака"],
|
||
["Если разделить","на 2 заряженные части"]
|
||
]},
|
||
p15:{title:"Шпаргалка § 15",rows:[
|
||
["Элементарный заряд","$e = 1{,}6 \\cdot 10^{-19}$ Кл"],
|
||
["Формула","$q = N e$ ($N$ — число избыт. электронов)"],
|
||
["Знак $-q$","избыток электронов"],
|
||
["Знак $+q$","нехватка электронов"],
|
||
["1 Кл","заряд $6{,}25 \\cdot 10^{18}$ электронов"],
|
||
["Сохранение","$\\sum q = $ const"]
|
||
]},
|
||
p16:{title:"Шпаргалка § 16",rows:[
|
||
["Атом","ядро (+) + электроны (−)"],
|
||
["Ядро","протоны + нейтроны"],
|
||
["Нейтр. атом","$N_{электр} = Z$ (атомный номер)"],
|
||
["Катион (+)","потерял электрон(ы)"],
|
||
["Анион (−)","принял электрон(ы)"],
|
||
["Электронные оболочки","K, L, M, …"]
|
||
]},
|
||
p17:{title:"Шпаргалка § 17",rows:[
|
||
["Эл. поле","материя вокруг заряда"],
|
||
["Действует","силой на другие заряды"],
|
||
["Линии поля","от + к −"],
|
||
["Напряжение $U$","энергет. характеристика"],
|
||
["$U_{AB}$","разность потенциалов между A и B"]
|
||
]},
|
||
p18:{title:"Шпаргалка § 18",rows:[
|
||
["Формула","$A = q U$"],
|
||
["Единица","[U] = В = Дж/Кл"],
|
||
["Батарейка","1,5 В"],
|
||
["Аккумулятор","12 В"],
|
||
["Розетка","220 В"],
|
||
["1 В","работа 1 Дж на 1 Кл"]
|
||
]},
|
||
p19:{title:"Шпаргалка § 19",rows:[
|
||
["Ток","упорядоченное движение зарядов"],
|
||
["Условие 1","свободные носители"],
|
||
["Условие 2","эл. поле от источника"],
|
||
["Источники","батарейки, аккумуляторы, генераторы"],
|
||
["Внутри источника","сторонние силы $\\to$ ЭДС"]
|
||
]},
|
||
p20:{title:"Шпаргалка § 20",rows:[
|
||
["Формула","$I = q/t$"],
|
||
["Единица","[I] = А = Кл/с"],
|
||
["1 А","заряд 1 Кл за 1 с"],
|
||
["Направление тока","от + к − (исторически)"],
|
||
["В металлах","электроны против тока"]
|
||
]},
|
||
p21:{title:"Шпаргалка § 21",rows:[
|
||
["Цепь","источник, проводник, потребитель, ключ"],
|
||
["Амперметр","ПОСЛЕДОВАТЕЛЬНО, малое $R$"],
|
||
["Вольтметр","ПАРАЛЛЕЛЬНО, большое $R$"],
|
||
["Шкала А","А, мА, мкА"],
|
||
["Шкала В","В, мВ, кВ"]
|
||
]},
|
||
p22:{title:"Шпаргалка § 22",rows:[
|
||
["Закон Ома","$I = U / R$"],
|
||
["$R$","сопротивление, Ом"],
|
||
["ВАХ металла","прямая через 0"],
|
||
["Больше $U$","больше $I$ (пропорц.)"],
|
||
["Больше $R$","меньше $I$"]
|
||
]},
|
||
p23:{title:"Шпаргалка § 23",rows:[
|
||
["Формула","$R = \\rho \\, l / S$"],
|
||
["$\\rho$","удельное сопр., Ом·мм²/м"],
|
||
["медь","$\\rho = 0{,}017$"],
|
||
["алюминий","$\\rho = 0{,}028$"],
|
||
["нихром","$\\rho = 1{,}1$"],
|
||
["1 Ом","$U=1$ В $\\to I=1$ А"]
|
||
]},
|
||
p24:{title:"Шпаргалка § 24",rows:[
|
||
["Послед. соед.","$I = $ const"],
|
||
["Напряжение","$U = U_1 + U_2$"],
|
||
["Сопротивл.","$R = R_1 + R_2$"],
|
||
["Реостат","переменный резистор"],
|
||
["Поломка одного","вся цепь обесточена"]
|
||
]},
|
||
p25:{title:"Шпаргалка § 25",rows:[
|
||
["Паралл. соед.","$U = $ const"],
|
||
["Ток","$I = I_1 + I_2$"],
|
||
["Сопротивл.","$1/R = 1/R_1 + 1/R_2$"],
|
||
["Два равных","$R_{общ} = R/2$"],
|
||
["Поломка одного","остальные работают"]
|
||
]},
|
||
p26:{title:"Шпаргалка § 26",rows:[
|
||
["Работа тока","$A = U I t$"],
|
||
["Мощность","$P = U I = A/t$"],
|
||
["Также","$P = U^2/R = I^2 R$"],
|
||
["Джоуль-Ленц","$Q = I^2 R t$"],
|
||
["[P]","Вт"],
|
||
["1 кВт·ч","$3{,}6 \\cdot 10^6$ Дж"]
|
||
]},
|
||
p27:{title:"Шпаргалка § 27",rows:[
|
||
["Энергия","$W = P \\tau$ (кВт·ч)"],
|
||
["Стоимость","$\\text{руб} = W \\cdot \\text{тариф}$"],
|
||
["1-фазная розетка","220 В, 16 А max"],
|
||
["ТБ","не голыми руками!"],
|
||
["Заземление","для защиты"]
|
||
]},
|
||
p28:{title:"Шпаргалка § 28",rows:[
|
||
["Полюсы","N (север), S (юг)"],
|
||
["Одноим.","отталкиваются"],
|
||
["Разноим.","притягиваются"],
|
||
["Разрез магнита","2 новых магнита (нет монополя)"],
|
||
["Магн. поле Земли","ось $\\approx$ географ."]
|
||
]},
|
||
p29:{title:"Шпаргалка § 29",rows:[
|
||
["$\\vec B$","магнитная индукция, Тл"],
|
||
["Линии $\\vec B$","выходят из N, входят в S"],
|
||
["Линии замкнуты","нет источника / стока"],
|
||
["Опилки","показывают линии $\\vec B$"]
|
||
]},
|
||
p30:{title:"Шпаргалка § 30",rows:[
|
||
["Опыт Эрстеда","1820 г"],
|
||
["Вывод","ток создаёт магн. поле"],
|
||
["Связь","электричество $\\leftrightarrow$ магнетизм"],
|
||
["Стрелка над током","отклоняется"]
|
||
]},
|
||
p31:{title:"Шпаргалка § 31",rows:[
|
||
["Прямой проводник","линии — концентр. окружности"],
|
||
["Правило прав. руки","большой палец = ток"],
|
||
["Соленоид","как полосовой магнит"],
|
||
["Электромагнит","катушка + сердечник"],
|
||
["$|B|$ катушки","$\\propto I N$"]
|
||
]},
|
||
final2:{title:"Финал главы 2",rows:[
|
||
["§§12-31","электромагнитные явления"],
|
||
["3 части","статика, ток, магнетизм"],
|
||
["Награда","+50 XP + Мастер ЭМ"]
|
||
]}
|
||
};
|
||
|
||
const TIPS=[
|
||
{sec:'p12',html:"Потри расчёску о волосы — она начнёт притягивать клочки бумаги. Это <b>электризация</b>. При трении один предмет получает <b>положительный</b> заряд, другой — <b>отрицательный</b>. Одноимённые отталкиваются, разноимённые — притягиваются."},
|
||
{sec:'p13',html:"Металлы — отличные проводники: их электроны легко двигаются. Эбонит, стекло, пластик — диэлектрики: электроны связаны атомами. Поэтому ручка отвёртки из пластика — а сама отвёртка металлическая."},
|
||
{sec:'p14',html:"Поднеси заряженный шар к незаряженному металлическому шарику — он притянется. В нейтральном проводнике под действием внешнего заряда электроны перераспределяются, и ближний конец получает противоположный знак."},
|
||
{sec:'p15',html:"Заряд не бывает «дробным» — все заряды кратны элементарному $e = 1{,}6 \\cdot 10^{-19}$ Кл. Если у тела «лишние» $N$ электронов, его заряд $q = -Ne$. 1 Кл — это очень много: примерно $6 \\cdot 10^{18}$ электронов."},
|
||
{sec:'p16',html:"Атом — это плотное положительное ядро (протоны+нейтроны) и облако отрицательных электронов вокруг. В обычном атоме число электронов равно числу протонов — он нейтрален. Если потерять электрон → ион +, если получить → ион −."},
|
||
{sec:'p17',html:"Заряд не «торкает» другие заряды напрямую — он создаёт вокруг себя <b>электрическое поле</b>, а уже оно действует силой на другие заряды. Линии поля идут от + к − и показывают направление силы на пробный +заряд."},
|
||
{sec:'p18',html:"Напряжение $U$ — это работа поля по перемещению единичного заряда: $A = qU$. Единица — 1 Вольт. Розетка 220 В, батарейка 1,5 В. Чем больше $U$, тем «сильнее» поле толкает заряд."},
|
||
{sec:'p19',html:"Ток — это упорядоченное движение свободных зарядов. Чтобы оно поддерживалось, нужен <b>источник тока</b> — батарейка, аккумулятор, генератор. Внутри источника <i>сторонние силы</i> переносят заряды против поля — это и есть «насос электричества»."},
|
||
{sec:'p20',html:"$I = q/t$ — сколько Кулонов прошло через сечение провода за 1 секунду. Единица — <b>Ампер</b> ($1$ А = $1$ Кл/с). За направление тока приняли движение «+» зарядов — хотя в металлах реально двигаются электроны (против тока)."},
|
||
{sec:'p21',html:"Простейшая цепь: батарея, лампа, ключ, провода. Чтобы измерить ток через лампу — амперметр включают <b>последовательно</b> с лампой. Чтобы измерить напряжение на лампе — вольтметр включают <b>параллельно</b>."},
|
||
{sec:'p22',html:"Закон Ома для участка цепи: $I = U/R$. Увеличил напряжение в 2 раза — ток вырос в 2 раза. Поставил резистор побольше — ток упал. Прямая зависимость для металлов."},
|
||
{sec:'p23',html:"Сопротивление провода зависит от трёх вещей: <b>материала</b> ($\\rho$), <b>длины</b> ($l$) и <b>толщины</b> ($S$). Длинный тонкий нихром — большое $R$ (спираль чайника), короткий толстый медный — маленькое $R$ (провод)."},
|
||
{sec:'p24',html:"При последовательном соединении ток течёт через все элементы один и тот же. Напряжения складываются. Сопротивления складываются. Реостат — переменный резистор, при сдвиге движка меняется длина включённой проволоки."},
|
||
{sec:'p25',html:"При параллельном соединении на каждой ветви одно и то же напряжение. Токи складываются. Сопротивление считается по особой формуле — в итоге $R_{общ}$ <b>меньше</b> любого из $R_1$, $R_2$."},
|
||
{sec:'p26',html:"$A = UIt$ — энергия, которую ток отдаёт прибору. $P = UI$ — это мощность (Дж/с = Вт). В резисторе вся эта энергия превращается в тепло — это <b>закон Джоуля-Ленца</b>: $Q = I^2 R t$."},
|
||
{sec:'p27',html:"Счётчик в квартире меряет энергию в <b>кВт·ч</b>: 1 кВт·ч — это работа за 1 час мощностью 1 кВт. Стоимость = энергия × тариф. ТБ: розетка под 220 В может ударить смертельным током."},
|
||
{sec:'p28',html:"Два полюса магнита: N (север) и S (юг). Как и заряды: одноимённые отталкиваются, разноимённые притягиваются. Но в отличие от зарядов, разрезать магнит и получить «только N» нельзя — выскочат новые два полюса."},
|
||
{sec:'p29',html:"Вокруг магнита есть магнитное поле — оно действует на железные предметы и магнитные стрелки. Линии поля выходят из N и входят в S, и они <b>замкнуты</b> (в отличие от линий эл. поля). Опилки на бумаге над магнитом красиво «рисуют» эти линии."},
|
||
{sec:'p30',html:"Великое открытие Эрстеда (1820): магнитная стрелка отклоняется около проводника с током. Значит, ток создаёт магнитное поле! Это первый «мост» между электричеством и магнетизмом."},
|
||
{sec:'p31',html:"Линии поля вокруг прямого провода — концентрические окружности. Направление определяет правило правой руки. Катушка с током (соленоид) ведёт себя как полосовой магнит. Электромагнит = катушка + железный сердечник: сильный, управляемый магнит."},
|
||
{sec:'final2',html:"Финал главы 2 — 10 интегрированных боссов по всей электротехнике 8 класса. Заряды, поле, ток, закон Ома, соединения, мощность, кВт·ч, магнетизм. +50 XP и ачивка «Мастер электромагнетизма»."}
|
||
];
|
||
|
||
const BUILDERS = {
|
||
p12: ()=>{ build_p12(); },
|
||
p13: ()=>{ build_p13(); },
|
||
p14: ()=>{ build_p14(); },
|
||
p15: ()=>{ build_p15(); },
|
||
p16: ()=>{ build_p16(); },
|
||
p17: ()=>{ build_p17(); },
|
||
p18: ()=>{ build_p18(); },
|
||
p19: ()=>{ build_p19(); },
|
||
p20: ()=>{ build_p20(); },
|
||
p21: ()=>{ build_p21(); },
|
||
p22: ()=>{ build_p22(); },
|
||
p23: ()=>{ build_p23(); },
|
||
p24: ()=>{ build_p24(); },
|
||
p25: ()=>{ build_p25(); },
|
||
p26: ()=>{ build_p26(); },
|
||
p27: ()=>{ build_p27(); },
|
||
p28: ()=>{ build_p28(); },
|
||
p29: ()=>{ build_p29(); },
|
||
p30: ()=>{ build_p30(); },
|
||
p31: ()=>{ build_p31(); },
|
||
final2: ()=>{ build_final2(); }
|
||
};
|
||
|
||
function calcLevel(xp){ return Math.floor(Math.sqrt((xp||0)/100))+1; }
|
||
function _xpForLevel(lv){ return (lv-1)*(lv-1)*100; }
|
||
|
||
function loadProgress(){
|
||
try{
|
||
const s=localStorage.getItem(LS_PREFIX+'_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
|
||
const a=localStorage.getItem(LS_PREFIX+'_achievements');
|
||
if(a){ const p=JSON.parse(a); if(Array.isArray(p)) p.forEach(id=>STATE.achievements.set(id, ACH_LABELS[id]||id)); else if(p&&typeof p==='object'){ for(const[id,t] of Object.entries(p)) STATE.achievements.set(id,(t&&t!==id)?t:(ACH_LABELS[id]||id)); } }
|
||
STATE.xp=+(localStorage.getItem(LS_XP)||0); STATE.level=calcLevel(STATE.xp);
|
||
}catch(e){}
|
||
}
|
||
function saveProgress(){
|
||
try{
|
||
localStorage.setItem(LS_PREFIX+'_progress', JSON.stringify(STATE.progress));
|
||
localStorage.setItem(LS_PREFIX+'_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
|
||
localStorage.setItem(LS_XP, String(STATE.xp));
|
||
}catch(e){}
|
||
}
|
||
function bumpProgress(key, delta){
|
||
STATE.progress[key]=Math.max(0,Math.min(100,(STATE.progress[key]||0)+delta));
|
||
saveProgress(); refreshProgressUI();
|
||
if(STATE.progress[key]>=50) markParaRead(key);
|
||
}
|
||
|
||
const _markedRead=new Set();
|
||
let _pendingProgressBody=null, _progressTimer=null;
|
||
function _flushProgress(){
|
||
const body=_pendingProgressBody; _pendingProgressBody=null; if(!body) return;
|
||
const tok=(window.LS&&LS.getToken)?LS.getToken():''; if(!tok) return;
|
||
fetch('/api/textbooks/'+_TB_SLUG+'/progress',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+tok},body:JSON.stringify(body),keepalive:true}).catch(()=>{});
|
||
}
|
||
function _queueProgress(patch){ _pendingProgressBody=Object.assign(_pendingProgressBody||{},patch); if(_progressTimer) clearTimeout(_progressTimer); _progressTimer=setTimeout(_flushProgress, 600); }
|
||
function markLastPara(id){ _queueProgress({last_para:id}); }
|
||
function markParaRead(id){ if(_markedRead.has(id)) return; _markedRead.add(id); _queueProgress({mark_read:id}); }
|
||
window.addEventListener('beforeunload', _flushProgress);
|
||
function loadServerReadState(){
|
||
const tok=(window.LS&&LS.getToken)?LS.getToken():''; if(!tok) return;
|
||
fetch('/api/textbooks/'+_TB_SLUG,{headers:{'Authorization':'Bearer '+tok}}).then(r=>r.ok?r.json():null).then(d=>{
|
||
if(!d||!d.progress) return;
|
||
(d.progress.read||[]).forEach(k=>{_markedRead.add(k); if((STATE.progress[k]||0)<50) STATE.progress[k]=100;});
|
||
saveProgress(); refreshProgressUI();
|
||
}).catch(()=>{});
|
||
}
|
||
|
||
function addXp(n,src){
|
||
if(!n) return;
|
||
const prev=STATE.level; STATE.xp=Math.max(0,(STATE.xp||0)+n); STATE.level=calcLevel(STATE.xp);
|
||
saveProgress(); refreshProgressUI();
|
||
if(window.LS&&window.LS.xp) window.LS.xp.add(n, LS_PREFIX+'-'+(src||'misc'));
|
||
if(STATE.level>prev){
|
||
const pop=document.getElementById('ach-popup');
|
||
if(pop){ document.getElementById('ach-text').textContent='Уровень '+STATE.level+'!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'),2600); }
|
||
}
|
||
}
|
||
|
||
function refreshProgressUI(){
|
||
const total=Math.round(Object.values(STATE.progress).reduce((a,b)=>a+b,0)/TOTAL_PARAS);
|
||
const f=document.getElementById('hero-hp-fill'); if(f) f.style.width=total+'%';
|
||
const t=document.getElementById('hero-hp-text'); if(t) t.textContent=total+'% пройдено';
|
||
document.querySelectorAll('[data-prog-card]').forEach(el=>{ const k=el.dataset.progCard; const fl=el.querySelector('.psel-prog-fill'); if(fl) fl.style.width=(STATE.progress[k]||0)+'%'; });
|
||
const xpBadge=document.getElementById('hero-xp-badge');
|
||
if(xpBadge){ xpBadge.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:13px;height:13px"><polygon points="12 2 22 20 2 20"/></svg> Ур. '+STATE.level+' \xb7 '+(STATE.xp||0)+' XP'; }
|
||
if(STATE.current && document.getElementById('sidebar-content')){ try{ buildSidebar(STATE.current); }catch(e){} }
|
||
}
|
||
|
||
function achievement(id,text){
|
||
if(STATE.achievements.has(id)) return;
|
||
STATE.achievements.set(id, text||ACH_LABELS[id]||id); saveProgress();
|
||
const pop=document.getElementById('ach-popup');
|
||
if(pop){ document.getElementById('ach-text').textContent=text||ACH_LABELS[id]||id; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'),3300); }
|
||
addXp(20,'ach-'+id);
|
||
}
|
||
|
||
function buildParaSelector(){
|
||
const g=document.getElementById('psel-grid'); g.innerHTML='';
|
||
PARAS.forEach(p=>{
|
||
const card=document.createElement('div');
|
||
card.className='psel-card'+(p.final?' final':'');
|
||
card.dataset.id=p.id; card.dataset.progCard=p.id;
|
||
card.innerHTML='<div class="psel-num">'+p.num+'</div><div class="psel-name">'+p.name+'</div><div class="psel-prog"><div class="psel-prog-fill"></div></div>';
|
||
card.addEventListener('click', ()=>goTo(p.id));
|
||
g.appendChild(card);
|
||
});
|
||
}
|
||
|
||
const BUILT=new Set();
|
||
function ensureBuilt(id){ if(BUILT.has(id)) return; const fn=BUILDERS[id]; if(fn){ fn(); BUILT.add(id); } }
|
||
function goTo(id){
|
||
STATE.current=id; ensureBuilt(id);
|
||
document.querySelectorAll('.sec').forEach(s=>s.classList.remove('active'));
|
||
const el=document.getElementById('sec-'+id); if(el) el.classList.add('active');
|
||
document.querySelectorAll('.psel-card').forEach(c=>c.classList.toggle('active', c.dataset.id===id));
|
||
buildSidebar(id);
|
||
window.scrollTo({top:0,behavior:'smooth'});
|
||
if((STATE.progress[id]||0)<10) bumpProgress(id, 10);
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(el), 0);
|
||
markLastPara(id);
|
||
}
|
||
|
||
function buildSidebar(id){
|
||
const box=document.getElementById('sidebar-content');
|
||
const sb=SIDEBARS[id]||SIDEBARS[PARAS[0].id];
|
||
let html='';
|
||
const xpForLv=_xpForLevel(STATE.level), xpNext=_xpForLevel(STATE.level+1);
|
||
const xpInLv=STATE.xp-xpForLv, xpRange=xpNext-xpForLv;
|
||
const xpPct=xpRange>0?Math.round(xpInLv/xpRange*100):100;
|
||
html+='<div class="xp-card" data-gamified><div class="xp-card-title" data-gamified><span>XP-прогресс</span><span class="xp-level">Ур. '+STATE.level+'</span></div><div class="xp-bar"><div class="xp-fill" style="width:'+xpPct+'%"></div></div><div class="xp-nums"><span>'+STATE.xp+' XP</span><span>'+xpNext+' XP</span></div></div>';
|
||
html+='<div class="sidecard"><h4>'+sb.title+'</h4>';
|
||
sb.rows.forEach(([k,v])=>{ html+='<div class="sidecard-row"><b>'+k+'</b>'+(v?' \u2014 '+v:'')+'</div>'; });
|
||
html+='</div>';
|
||
const tip=TIPS.find(t=>t.sec===id)||TIPS[0];
|
||
if(tip){
|
||
html+='<div class="sidecard" style="background:linear-gradient(135deg,var(--warn-bg,#fef3c7),var(--pri-soft));border-color:var(--warn,#f59e0b)"><h4 style="color:#92400e;display:flex;align-items:center;gap:6px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px"><polygon points="12,2 22,20 2,20"/></svg>Подсказка</h4><div class="sidecard-row" style="margin-bottom:0;font-size:.84rem;line-height:1.55">'+tip.html+'</div></div>';
|
||
}
|
||
if(STATE.achievements.size>0){
|
||
html+='<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">'+STATE.achievements.size+'</span></h4>';
|
||
[...STATE.achievements.values()].slice(-4).forEach(text=>{ html+='<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">✓ '+text+'</div>'; });
|
||
html+='</div>';
|
||
}
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) try{ renderMath(box); }catch(e){}
|
||
}
|
||
|
||
function initTheme(){
|
||
const t=localStorage.getItem(LS_PREFIX+'_theme')||'light';
|
||
if(t==='dark') document.documentElement.classList.add('dark');
|
||
document.getElementById('theme-lab').textContent=t==='dark'?'Светлая':'Тёмная';
|
||
document.getElementById('theme-btn').addEventListener('click', ()=>{
|
||
document.documentElement.classList.toggle('dark');
|
||
const dark=document.documentElement.classList.contains('dark');
|
||
localStorage.setItem(LS_PREFIX+'_theme', dark?'dark':'light');
|
||
document.getElementById('theme-lab').textContent=dark?'Светлая':'Тёмная';
|
||
});
|
||
}
|
||
|
||
function renderMath(root){ if(window.renderMathInElement){ try{ renderMathInElement(root, {delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false}); }catch(e){} } }
|
||
function feedback(elm, ok, text){ if(!elm) return; elm.className='feedback '+(ok?'ok':'fail'); elm.innerHTML=text||(ok?'✓ Верно!':'✗ Неверно'); elm.style.display='block'; try{renderMath(elm);}catch(e){} }
|
||
function fmt(n){ if(!isFinite(n)) return '?'; if(Number.isInteger(n)) return String(n); return Math.abs(n-Math.round(n))<1e-9?String(Math.round(n)):(+n.toFixed(6)).toString(); }
|
||
function ipow(base, exp){ let r=1; for(let i=0;i<Math.abs(exp);i++) r*=base; return exp<0 ? 1/r : r; }
|
||
function gcd(a,b){ a=Math.abs(a|0); b=Math.abs(b|0); while(b){ const t=b; b=a%b; a=t; } return a||1; }
|
||
function makeCard(kind, title, num, body){
|
||
const labels = {repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно'};
|
||
return '<div class="card"><div class="card-header"><div class="card-icon '+kind+'">'+ICONS[kind]+'</div><div class="card-title">'+(labels[kind]||'')+(title&&title!==labels[kind]?' \xb7 '+title:'')+'</div>'+(num?'<div class="card-num">'+num+'</div>':'')+'</div><div class="card-body">'+body+'</div></div>';
|
||
}
|
||
|
||
/* === SVG-хелперы === */
|
||
function axes2D(W, H, pad, xmin, xmax, ymin, ymax){
|
||
const ux = (W - 2*pad) / (xmax - xmin);
|
||
const uy = (H - 2*pad) / (ymax - ymin);
|
||
const toX = v => pad + (v - xmin) * ux;
|
||
const toY = v => H - pad - (v - ymin) * uy;
|
||
let g = '';
|
||
g += '<g stroke="#e5e7eb" stroke-width="1">';
|
||
for (let x = Math.ceil(xmin); x <= xmax; x++){
|
||
g += '<line x1="'+toX(x)+'" y1="'+pad+'" x2="'+toX(x)+'" y2="'+(H-pad)+'"/>';
|
||
}
|
||
for (let y = Math.ceil(ymin); y <= ymax; y++){
|
||
g += '<line x1="'+pad+'" y1="'+toY(y)+'" x2="'+(W-pad)+'" y2="'+toY(y)+'"/>';
|
||
}
|
||
g += '</g>';
|
||
const y0 = toY(0), x0 = toX(0);
|
||
g += '<line x1="'+pad+'" y1="'+y0+'" x2="'+(W-pad)+'" y2="'+y0+'" stroke="#0f172a" stroke-width="1.5"/>';
|
||
g += '<line x1="'+x0+'" y1="'+pad+'" x2="'+x0+'" y2="'+(H-pad)+'" stroke="#0f172a" stroke-width="1.5"/>';
|
||
g += '<text x="'+(W-pad+2)+'" y="'+(y0-4)+'" font-size="11" fill="#0f172a">x</text>';
|
||
g += '<text x="'+(x0+4)+'" y="'+(pad-2)+'" font-size="11" fill="#0f172a">y</text>';
|
||
g += '<g font-size="10" fill="#64748b">';
|
||
for (let x = Math.ceil(xmin); x <= xmax; x++){
|
||
if (x !== 0) g += '<text x="'+(toX(x)-3)+'" y="'+(y0+12)+'">'+x+'</text>';
|
||
}
|
||
for (let y = Math.ceil(ymin); y <= ymax; y++){
|
||
if (y !== 0) g += '<text x="'+(x0+4)+'" y="'+(toY(y)+3)+'">'+y+'</text>';
|
||
}
|
||
g += '<text x="'+(x0+4)+'" y="'+(y0+12)+'">0</text>';
|
||
g += '</g>';
|
||
return { content: g, toX, toY, ux, uy };
|
||
}
|
||
function plotFunc(f, xmin, xmax, toX, toY, color, N){
|
||
N = N || 200;
|
||
let d = '';
|
||
let prevValid = false;
|
||
for (let i = 0; i <= N; i++){
|
||
const x = xmin + (xmax - xmin) * i / N;
|
||
let y;
|
||
try { y = f(x); } catch(e){ y = NaN; }
|
||
if (!isFinite(y) || isNaN(y) || y < -1e4 || y > 1e4){ prevValid = false; continue; }
|
||
d += (prevValid ? ' L' : ' M') + toX(x).toFixed(2) + ',' + toY(y).toFixed(2);
|
||
prevValid = true;
|
||
}
|
||
return '<path d="'+d+'" stroke="'+color+'" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>';
|
||
}
|
||
function pointWithDrop(x, fx, toX, toY, color, label){
|
||
const px = toX(x), py = toY(fx);
|
||
let s = '';
|
||
s += '<line x1="'+px+'" y1="'+py+'" x2="'+px+'" y2="'+toY(0)+'" stroke="'+color+'" stroke-width="1.2" stroke-dasharray="3 3" opacity=".7"/>';
|
||
s += '<line x1="'+px+'" y1="'+py+'" x2="'+toX(0)+'" y2="'+py+'" stroke="'+color+'" stroke-width="1.2" stroke-dasharray="3 3" opacity=".7"/>';
|
||
s += '<circle cx="'+px+'" cy="'+py+'" r="4.5" fill="'+color+'" stroke="#fff" stroke-width="2"/>';
|
||
if (label){
|
||
s += '<text x="'+(px+8)+'" y="'+(py-8)+'" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="'+color+'">'+label+'</text>';
|
||
}
|
||
return s;
|
||
}
|
||
function asymptote(orientation, value, toX, toY, xmin, xmax, ymin, ymax, color){
|
||
color = color || '#94a3b8';
|
||
if (orientation === 'h'){
|
||
const y = toY(value);
|
||
return '<line x1="'+toX(xmin)+'" y1="'+y+'" x2="'+toX(xmax)+'" y2="'+y+'" stroke="'+color+'" stroke-width="1.3" stroke-dasharray="6 4"/>';
|
||
} else {
|
||
const x = toX(value);
|
||
return '<line x1="'+x+'" y1="'+toY(ymin)+'" x2="'+x+'" y2="'+toY(ymax)+'" stroke="'+color+'" stroke-width="1.3" stroke-dasharray="6 4"/>';
|
||
}
|
||
}
|
||
function snapToValue(value, snapPoints, tolerance){
|
||
tolerance = tolerance || 0.1;
|
||
for (const sp of snapPoints){
|
||
if (Math.abs(value - sp) < tolerance) return sp;
|
||
}
|
||
return value;
|
||
}
|
||
function rightAngleMark(V, uIn, wIn, s){
|
||
s = s || 9;
|
||
const p1 = {x: V.x + s*uIn.x, y: V.y + s*uIn.y};
|
||
const c = {x: p1.x + s*wIn.x, y: p1.y + s*wIn.y};
|
||
const p2 = {x: V.x + s*wIn.x, y: V.y + s*wIn.y};
|
||
return p1.x+','+p1.y+' '+c.x+','+c.y+' '+p2.x+','+p2.y;
|
||
}
|
||
function angleArcAuto(V, uA, uB, R){
|
||
const sA = {x: V.x + R*uA.x, y: V.y + R*uA.y};
|
||
const eB = {x: V.x + R*uB.x, y: V.y + R*uB.y};
|
||
const cross = uA.x*uB.y - uA.y*uB.x;
|
||
const sweep = cross > 0 ? 1 : 0;
|
||
return 'M'+sA.x+','+sA.y+' A'+R+','+R+' 0 0,'+sweep+' '+eB.x+','+eB.y;
|
||
}
|
||
function unitVec(p1, p2){
|
||
const dx = p2.x - p1.x, dy = p2.y - p1.y;
|
||
const len = Math.sqrt(dx*dx + dy*dy) || 1;
|
||
return {x: dx/len, y: dy/len};
|
||
}
|
||
function deg2rad(d){ return d * Math.PI / 180; }
|
||
|
||
const ICONS = {
|
||
repeat:'<svg class="ic" viewBox="0 0 24 24"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',
|
||
theory:'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>',
|
||
algo:'<svg class="ic" viewBox="0 0 24 24"><polyline points="17 11 21 7 17 3"/><line x1="21" y1="7" x2="9" y2="7"/><polyline points="7 13 3 17 7 21"/><line x1="3" y1="17" x2="15" y2="17"/></svg>',
|
||
rule:'<svg class="ic" viewBox="0 0 24 24"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>',
|
||
example:'<svg class="ic" viewBox="0 0 24 24"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 13c1 1 2 2 2 4h4c0-2 1-3 2-4a7 7 0 0 0-4-13z"/></svg>',
|
||
oral:'<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>'
|
||
};
|
||
|
||
function secNavFor(curId){
|
||
const idx = PARAS.findIndex(p => p.id === curId);
|
||
const prev = idx > 0 ? PARAS[idx-1].id : null;
|
||
const next = idx < PARAS.length - 1 ? PARAS[idx+1].id : null;
|
||
return secNav(prev, next);
|
||
}
|
||
function secNav(prev, next){
|
||
function lbl(id){ if(!id) return ''; const p=PARAS.find(x=>x.id===id); return p?p.num:id; }
|
||
let h='<div class="sec-nav">';
|
||
h+=prev?'<button class="btn" onclick="goTo(\''+prev+'\')"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> '+lbl(prev)+'</button>':'<span></span>';
|
||
h+=next?'<button class="btn primary" onclick="goTo(\''+next+'\')">'+lbl(next)+' <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>':'<span></span>';
|
||
h+='</div>'; return h;
|
||
}
|
||
|
||
function readButton(paraId){
|
||
const p = PARAS.find(x => x.id === paraId);
|
||
const labelTail = p && p.final ? 'финал' : (p ? p.num : '?');
|
||
return '<div style="margin-top:18px;display:flex;justify-content:center">'
|
||
+'<button class="btn primary" id="'+paraId+'-read-btn">'
|
||
+'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>'
|
||
+' Я прочитал \u2014 '+labelTail+' (+10 XP)'
|
||
+'</button></div>';
|
||
}
|
||
function wireReadBtn(paraId){
|
||
const btn = document.getElementById(paraId+'-read-btn'); if(!btn) return;
|
||
btn.addEventListener('click', ()=>{
|
||
addXp(10, paraId+'-read'); bumpProgress(paraId, 30);
|
||
btn.textContent='Прочитано! +10 XP'; btn.disabled=true; btn.style.opacity=.6;
|
||
const aId = paraId+'_done';
|
||
if(ACH_LABELS[aId]) achievement(aId);
|
||
});
|
||
}
|
||
|
||
function setupSorter(cfg){
|
||
const placed = {}; const pool = document.getElementById(cfg.poolId); const scope = document.querySelector(cfg.scopeSelector);
|
||
if(!pool||!scope) return {placed,render:()=>{},reset:()=>{}};
|
||
pool.classList.add('dnd-pool'); if(cfg.columnLayout) pool.classList.add('col');
|
||
let armed = null;
|
||
function buildChip(it,isPlaced){ const e=document.createElement('div'); e.className='dnd-chip'+(isPlaced?' placed':''); e.dataset.id=it.id; e.innerHTML='<span class="dnd-txt">'+it.html+'</span><span class="dnd-x" title="Убрать">\xd7</span>'; attach(e,it.id); return e; }
|
||
function attach(elm,itId){ let ghost=null,dragging=false,sx=0,sy=0; elm.addEventListener('pointerdown',ev=>{ if(ev.button!==undefined&&ev.button!==0) return;
|
||
ev.preventDefault(); if(ev.target.classList&&ev.target.classList.contains('dnd-x')){ ev.stopPropagation(); if(placed[itId]){delete placed[itId];render();}else if(armed===itId){armed=null;render();} return; } sx=ev.clientX;sy=ev.clientY; const r=elm.getBoundingClientRect(); const ox=ev.clientX-r.left,oy=ev.clientY-r.top; try{elm.setPointerCapture(ev.pointerId);}catch(e){} function onMove(e){ const dx=e.clientX-sx,dy=e.clientY-sy; if(!dragging&&Math.hypot(dx,dy)>8){ dragging=true; ghost=elm.cloneNode(true); ghost.classList.remove('armed'); ghost.style.cssText='position:fixed;z-index:9999;pointer-events:none;opacity:.9;transform:rotate(-2.5deg);box-shadow:0 14px 36px rgba(0,0,0,.32);width:'+r.width+'px;left:'+(e.clientX-ox)+'px;top:'+(e.clientY-oy)+'px'; document.body.appendChild(ghost); elm.classList.add('dragging'); } if(dragging&&ghost){ ghost.style.left=(e.clientX-ox)+'px';ghost.style.top=(e.clientY-oy)+'px'; const under=document.elementsFromPoint(e.clientX,e.clientY); scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); const tgt=under.find(n=>n.classList&&(n.classList.contains('drop-box')||n.classList.contains('dnd-pool'))); if(tgt)tgt.classList.add('over'); } } function onUp(e){ elm.removeEventListener('pointermove',onMove);elm.removeEventListener('pointerup',onUp);elm.removeEventListener('pointercancel',onUp);elm.classList.remove('dragging'); if(ghost){ghost.remove();ghost=null;} scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); if(dragging){ const under=document.elementsFromPoint(e.clientX,e.clientY); const box=under.find(n=>n.classList&&n.classList.contains('drop-box')); const pl=under.find(n=>n.classList&&n.classList.contains('dnd-pool')); if(box){const di=box.querySelector('[data-cat]');if(di){placed[itId]=di.dataset.cat;armed=null;render();return;}}else if(pl){delete placed[itId];armed=null;render();return;} }else{ if(placed[itId]){delete placed[itId];armed=null;render();}else{armed=(armed===itId)?null:itId;render();} } dragging=false; } elm.addEventListener('pointermove',onMove);elm.addEventListener('pointerup',onUp);elm.addEventListener('pointercancel',onUp); }); }
|
||
function attachBoxTaps(){ scope.querySelectorAll('.drop-box').forEach(box=>{ box.addEventListener('click',ev=>{ if(!armed)return; if(ev.target.closest('.dnd-chip'))return; const di=box.querySelector('[data-cat]'); if(di){placed[armed]=di.dataset.cat;armed=null;render();} }); }); }
|
||
function render(){ pool.innerHTML=''; cfg.items.forEach(it=>{if(placed[it.id])return;const c=buildChip(it,false);if(armed===it.id)c.classList.add('armed');pool.appendChild(c);}); cfg.cats.forEach(cat=>{const box=scope.querySelector('.drop-items[data-cat="'+cat+'"]');if(!box)return;box.innerHTML='';cfg.items.forEach(it=>{if(placed[it.id]!==cat)return;box.appendChild(buildChip(it,true));});}); if(window.renderMathInElement)try{renderMath(scope);}catch(_){} }
|
||
attachBoxTaps(); render();
|
||
return {placed,render,reset(){ for(const k in placed)delete placed[k];armed=null;render(); }};
|
||
}
|
||
|
||
function buildStub(id, name, phase){
|
||
return '<div class="card" style="background:linear-gradient(135deg,var(--sec-acc-soft),var(--card));border:1.5px dashed var(--sec-acc)">'
|
||
+ '<div class="card-header"><div class="card-icon theory">'+ICONS.theory+'</div><div class="card-title">В разработке</div></div>'
|
||
+ '<div class="card-body"><p>Контент <b>'+name+'</b> будет реализован в <b>'+phase+'</b> по плану <code>PLAN_PHYSICS_8.md</code>.</p>'
|
||
+ '<p style="margin-top:8px;color:var(--muted);font-size:.9rem">Phase 0 \u2014 это каркас (skeleton). Все 4 интерактива, 3 теоретические карточки и тренажёр задач будут добавлены в волне.</p>'
|
||
+ '</div></div>';
|
||
}
|
||
|
||
/* ===== Search ===== */
|
||
const SEARCH_INDEX = (function(){
|
||
const arr=[];
|
||
PARAS.forEach(p=>arr.push({kind:'Параграф',title:p.num+' '+p.name,desc:p.sub||'',sec:p.id}));
|
||
return arr;
|
||
})();
|
||
function initSearch(){
|
||
const modal=document.getElementById('search-modal'),inp=document.getElementById('search-input'),out=document.getElementById('search-results'),btn=document.getElementById('search-btn');
|
||
if(!modal||!inp||!out) return;
|
||
let cur=0,rows=[];
|
||
function score(q,it){ const t=(it.title+' '+it.desc).toLowerCase(); if(t.includes(q)) return 100+(it.title.toLowerCase().startsWith(q)?50:0); let s=0; q.split(/\s+/).forEach(w=>{if(w&&t.includes(w))s+=10;}); return s; }
|
||
function rank(q){ q=q.trim().toLowerCase(); if(!q) return SEARCH_INDEX.slice(0,12); return SEARCH_INDEX.map(it=>({it,s:score(q,it)})).filter(x=>x.s>0).sort((a,b)=>b.s-a.s).slice(0,20).map(x=>x.it); }
|
||
function render(){ cur=0; if(!rows.length){out.innerHTML='<div class="search-empty">Ничего не найдено</div>';return;} out.innerHTML=rows.map((r,i)=>'<button class="search-row'+(i===0?' active':'')+'" data-i="'+i+'"><div class="sr-kind">'+r.kind+'</div><div class="sr-title">'+r.title+'</div>'+(r.desc?'<div class="sr-desc">'+(r.desc.length>90?r.desc.slice(0,90)+'\u2026':r.desc)+'</div>':'')+'</button>').join(''); out.querySelectorAll('.search-row').forEach(b=>b.addEventListener('click',()=>{cur=+b.dataset.i;pick();})); }
|
||
function pick(){ const r=rows[cur]; if(!r) return; close(); goTo(r.sec); }
|
||
function move(d){ const items=out.querySelectorAll('.search-row'); if(!items.length) return; items[cur]&&items[cur].classList.remove('active'); cur=(cur+d+items.length)%items.length; items[cur].classList.add('active'); items[cur].scrollIntoView({block:'nearest'}); }
|
||
function open(){ modal.classList.add('show'); inp.value=''; rows=rank(''); render(); setTimeout(()=>inp.focus(),50); }
|
||
function close(){ modal.classList.remove('show'); }
|
||
btn&&btn.addEventListener('click',open);
|
||
modal.addEventListener('click',e=>{if(e.target===modal)close();});
|
||
inp.addEventListener('input',()=>{rows=rank(inp.value);render();});
|
||
inp.addEventListener('keydown',e=>{ if(e.key==='ArrowDown'){e.preventDefault();move(1);}else if(e.key==='ArrowUp'){e.preventDefault();move(-1);}else if(e.key==='Enter'){e.preventDefault();pick();}else if(e.key==='Escape'){e.preventDefault();close();} });
|
||
document.addEventListener('keydown',e=>{ if((e.ctrlKey||e.metaKey)&&(e.key==='k'||e.key==='K')){ e.preventDefault(); if(modal.classList.contains('show')) close(); else open(); } });
|
||
}
|
||
|
||
function initSidebarToggle(){
|
||
const side=document.getElementById('col-side'),back=document.getElementById('col-side-backdrop'),btn=document.getElementById('sidebar-btn');
|
||
if(!side||!btn) return;
|
||
function open(){ side.classList.add('open'); back.classList.add('show'); }
|
||
function close(){ side.classList.remove('open'); back.classList.remove('show'); }
|
||
btn.addEventListener('click',()=>{ if(side.classList.contains('open')) close(); else open(); });
|
||
back.addEventListener('click',close);
|
||
document.addEventListener('keydown',e=>{ if(e.key==='Escape') close(); });
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 2 · WAVE 1 — §12, §13, §14
|
||
====================================================================== */
|
||
|
||
/* Sim-management */
|
||
const _SIMS = {};
|
||
function _killSim(key){ if(_SIMS[key] && _SIMS[key].raf){ cancelAnimationFrame(_SIMS[key].raf); _SIMS[key].raf=0; } }
|
||
function _isVisible(secId){ const el=document.getElementById('sec-'+secId); return el && el.classList.contains('active'); }
|
||
|
||
/* ======== §12 — Электризация тел ======== */
|
||
function build_p12(){
|
||
const box = document.getElementById('p12-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Электрический заряд', '§ 12.1',
|
||
'<p>При трении некоторых тел друг о друга они приобретают свойство притягивать лёгкие предметы — клочки бумаги, волоски. Говорят: тело <b>электризуется</b>, на нём появляется <b>электрический заряд</b>.</p>'
|
||
+'<p>Опыты показывают: существует <b>два рода</b> зарядов.</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li><b>Положительный (+):</b> возникает на стекле, потёртом о шёлк.</li>'
|
||
+'<li><b>Отрицательный (−):</b> возникает на эбоните или пластике, потёртом о шерсть.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('rule', 'Закон взаимодействия зарядов', '§ 12.2',
|
||
'<p><b>Одноимённые</b> заряды (++ или −−) — <b>отталкиваются</b>.<br>'
|
||
+'<b>Разноимённые</b> заряды (+−) — <b>притягиваются</b>.</p>'
|
||
+'<p>При электризации трением заряды на двух телах <b>равны по модулю</b> и <b>противоположны</b> по знаку. Это закон <b>сохранения электрического заряда</b>.</p>'
|
||
+'<p style="margin-top:6px">Электризация происходит из-за переноса электронов с одного тела на другое: потерявшее электроны становится «+», получившее — «−».</p>'
|
||
);
|
||
h += makeCard('example', 'Примеры', '§ 12.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Расчёска после волос притягивает мелкие бумажки.</li>'
|
||
+'<li>Воздушный шарик после трения о волосы прилипает к стене.</li>'
|
||
+'<li>Снятие шерстяного свитера — иногда искрит.</li>'
|
||
+'<li>Молния — гигантский электрический разряд между облаком и землёй.</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — виртуальный электроскоп */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Виртуальный электроскоп</div></div>'
|
||
+'<div class="wg-help">Потри палочку о ткань — она зарядится. Поднеси её к электроскопу — листочки разойдутся: одноимённые заряды отталкиваются.</div>'
|
||
+'<svg id="p12-sim" viewBox="0 0 460 240" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="actions" style="margin-top:10px"><button class="btn primary" id="p12-rub">Потереть палочку</button><button class="btn" id="p12-touch">Поднести к электроскопу</button><button class="btn" id="p12-reset">Сброс</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Заряд палочки: <b id="p12-q">0</b></span><span>Угол листочков: <b id="p12-a">0°</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «знаки зарядов» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Каков знак заряда?</div></div>'
|
||
+'<div class="wg-help">По опыту с трением определи знак заряда тела.</div>'
|
||
+'<div id="p12-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p12-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p12-quiz-r">1</b> / 5</span><span>Правильно: <b id="p12-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «притягивает / отталкивает» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Что происходит при контакте?</div></div>'
|
||
+'<div class="wg-help">Распредели пары зарядов по типу взаимодействия.</div>'
|
||
+'<div id="p12-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Притягиваются</h5><div class="drop-items" data-cat="attr"></div></div>'
|
||
+'<div class="drop-box"><h5>Отталкиваются</h5><div class="drop-items" data-cat="rep"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p12-dnd-check">Проверить</button><button class="btn" id="p12-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p12-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
|
||
+'<div id="p12-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p12-mcq-i">1</b> / 6</span><span>Правильно: <b id="p12-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="p12-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p12-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p12-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — Charge Sandbox (Phase 2.2) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Песочница зарядов — наблюдай взаимодействие</div></div>'
|
||
+'<div class="wg-help">Клик ЛКМ → добавить +заряд, клик ПКМ → добавить -заряд. Перетаскивай существующие. Стрелки показывают силы взаимодействия (закон Кулона $F = k|q_1 q_2|/r^2$).</div>'
|
||
+'<div class="p8-sandbox" id="p12-iv6-sandbox" style="height:300px"></div>'
|
||
+'<div style="margin-top:10px;display:flex;gap:10px;flex-wrap:wrap">'
|
||
+'<button class="btn primary" id="p12-iv6-add-pos">+ Добавить +</button>'
|
||
+'<button class="btn primary" id="p12-iv6-add-neg" style="background:#2563eb;border-color:#2563eb">+ Добавить −</button>'
|
||
+'<button class="btn" id="p12-iv6-clear">Очистить</button>'
|
||
+'<div class="p8-readout"><span class="p8-readout-label">Зарядов</span><span class="p8-readout-value" id="p12-iv6-count">0</span></div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p12') + readButton('p12');
|
||
renderMath(box);
|
||
wireReadBtn('p12');
|
||
_initP12_iv6();
|
||
_initp12_iv5();
|
||
|
||
_initP12_sim();
|
||
_initP12_quiz();
|
||
_initP12_dnd();
|
||
_initP12_mcq();
|
||
}
|
||
|
||
function _initP12_sim(){
|
||
const svg = document.getElementById('p12-sim'); if(!svg) return;
|
||
let charged = false; /* палочка заряжена */
|
||
let touched = false; /* поднесено к электроскопу */
|
||
function draw(){
|
||
let s = '';
|
||
/* электроскоп: стеклянная колба, металлический стержень, два листочка */
|
||
const escCx = 320, escCy = 130;
|
||
s += '<rect x="'+(escCx-50)+'" y="'+(escCy-20)+'" width="100" height="120" fill="rgba(186,230,253,.35)" stroke="#0f172a" stroke-width="1.6" rx="4"/>';
|
||
/* шар сверху */
|
||
s += '<circle cx="'+escCx+'" cy="'+(escCy-40)+'" r="14" fill="#94a3b8" stroke="#0f172a" stroke-width="1.6"/>';
|
||
/* стержень */
|
||
s += '<line x1="'+escCx+'" y1="'+(escCy-26)+'" x2="'+escCx+'" y2="'+(escCy+50)+'" stroke="#475569" stroke-width="3"/>';
|
||
/* листочки */
|
||
const leafAng = touched && charged ? 35 : 4;
|
||
document.getElementById('p12-a').textContent = leafAng+'°';
|
||
const lx1 = escCx, ly1 = escCy+50;
|
||
const len = 36;
|
||
const lx2L = lx1 - len*Math.sin(leafAng*Math.PI/180);
|
||
const ly2L = ly1 + len*Math.cos(leafAng*Math.PI/180);
|
||
const lx2R = lx1 + len*Math.sin(leafAng*Math.PI/180);
|
||
const ly2R = ly1 + len*Math.cos(leafAng*Math.PI/180);
|
||
s += '<line x1="'+lx1+'" y1="'+ly1+'" x2="'+lx2L+'" y2="'+ly2L+'" stroke="#fbbf24" stroke-width="3"/>';
|
||
s += '<line x1="'+lx1+'" y1="'+ly1+'" x2="'+lx2R+'" y2="'+ly2R+'" stroke="#fbbf24" stroke-width="3"/>';
|
||
/* если заряжен и поднесён — рисуем + + на листочках */
|
||
if(touched && charged){
|
||
s += '<text x="'+(lx2L-8)+'" y="'+(ly2L+6)+'" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#dc2626">−</text>';
|
||
s += '<text x="'+(lx2R+4)+'" y="'+(ly2R+6)+'" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#dc2626">−</text>';
|
||
s += '<text x="'+escCx+'" y="'+(escCy-40+4)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="13" font-weight="800" fill="#dc2626">−</text>';
|
||
}
|
||
/* палочка — слева */
|
||
const rodX = touched ? 260 : 100;
|
||
const rodY = 100;
|
||
s += '<rect x="'+rodX+'" y="'+(rodY-10)+'" width="100" height="20" fill="#1e1b4b" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
|
||
if(charged){
|
||
for(let i=0;i<5;i++) s += '<text x="'+(rodX+10+i*20)+'" y="'+(rodY+5)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#fca5a5">−</text>';
|
||
}
|
||
/* ткань (если ещё не тёрли) */
|
||
if(!charged){
|
||
s += '<rect x="20" y="160" width="80" height="40" fill="#f87171" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
|
||
s += '<text x="60" y="184" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#fff">шерсть</text>';
|
||
}
|
||
/* подпись */
|
||
s += '<text x="150" y="50" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" fill="#475569">палочка (эбонит)</text>';
|
||
s += '<text x="320" y="220" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" fill="#475569">электроскоп</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p12-rub').addEventListener('click', ()=>{ charged = true; document.getElementById('p12-q').textContent = '−5 нКл'; draw(); });
|
||
document.getElementById('p12-touch').addEventListener('click', ()=>{
|
||
if(!charged){
|
||
const fb = document.getElementById('p12-q'); fb.textContent = 'сначала потри!'; return;
|
||
}
|
||
touched = true; draw();
|
||
});
|
||
document.getElementById('p12-reset').addEventListener('click', ()=>{ charged=false; touched=false; document.getElementById('p12-q').textContent='0'; draw(); });
|
||
draw();
|
||
}
|
||
|
||
function _initP12_quiz(){
|
||
const QS = [
|
||
{sit:'Стеклянная палочка, потёртая о шёлк', ans:'+', why:'По таблице: стекло о шёлк — стекло положительное.'},
|
||
{sit:'Эбонитовая палочка о шерсть', ans:'-', why:'Эбонит получает электроны от шерсти — становится отрицательным.'},
|
||
{sit:'Шёлк после трения о стекло', ans:'-', why:'Шёлк забирает электроны со стекла — отрицательный.'},
|
||
{sit:'Шерсть после трения об эбонит', ans:'+', why:'Шерсть отдала электроны эбониту — положительная.'},
|
||
{sit:'Воздушный шарик о волосы', ans:'-', why:'Шарик принимает электроны с волос.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p12-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
|
||
+'<button class="btn" data-pick="+" style="padding:14px;font-size:1.1rem"><b>+</b> положительный</button>'
|
||
+'<button class="btn" data-pick="-" style="padding:14px;font-size:1.1rem"><b>−</b> отрицательный</button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p12-quiz-fb"></div>';
|
||
document.getElementById('p12-quiz-r').textContent = (i+1);
|
||
document.getElementById('p12-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p12-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p12-quiz'); bumpProgress('p12', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p12-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p12-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP12_dnd(){
|
||
const items = [
|
||
{id:'pp', cat:'rep', html:'$+q$ и $+q$'},
|
||
{id:'mm', cat:'rep', html:'$-q$ и $-q$'},
|
||
{id:'pm', cat:'attr', html:'$+q$ и $-q$'},
|
||
{id:'mp', cat:'attr', html:'$-q$ и $+q$'},
|
||
{id:'p0', cat:'attr', html:'$+q$ и нейтральный проводник'},
|
||
{id:'m0', cat:'attr', html:'$-q$ и нейтральный проводник'},
|
||
{id:'pn', cat:'attr', html:'$+q$ и капля воды (диэл.)'},
|
||
{id:'pf', cat:'attr', html:'$+q$ и металл. шарик'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p12-dnd-pool', scopeSelector:'#sec-p12', cats:['attr','rep'], items, columnLayout:false });
|
||
document.getElementById('p12-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p12-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Заряженный объект <b>всегда</b> притягивает нейтральные (индукция).'; addXp(15,'p12-dnd'); bumpProgress('p12', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Подсказка: одноимённые отталкиваются; нейтральные всегда притягиваются.'; }
|
||
});
|
||
document.getElementById('p12-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p12-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP12_mcq(){
|
||
const QS = [
|
||
{q:'Сколько родов зарядов существует?', opts:['один','два','три','бесконечно много'], ans:1, why:'+ и −, всего два.'},
|
||
{q:'При электризации стекла о шёлк стекло становится…', opts:['отрицательным','положительным','не заряжается','любым'], ans:1, why:'Стекло теряет электроны → +.'},
|
||
{q:'Что переносится при трении?', opts:['атомы','молекулы','электроны','ядра'], ans:2, why:'Электроны переходят с одного тела на другое.'},
|
||
{q:'Два одинаково заряженных шарика…', opts:['притягиваются','отталкиваются','неподвижны','зависит от размера'], ans:1, why:'Одноимённые всегда отталкиваются.'},
|
||
{q:'Сумма зарядов при трении двух нейтральных тел…', opts:['растёт','становится 0','остаётся 0','становится +'], ans:2, why:'Заряд сохраняется: было 0, стало $+q$ и $-q$, сумма всё ещё 0.'},
|
||
{q:'Почему стенка притягивает шарик после трения о голову?', opts:['стенка тоже зарядилась','индукция в нейтральной стенке','гравитация','клей'], ans:1, why:'В диэлектрике стенки происходит небольшая поляризация — она притягивается к шарику.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p12-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p12-mcq-fb"></div><div class="actions"><button class="btn" id="p12-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p12-mcq-i').textContent = (i+1);
|
||
document.getElementById('p12-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p12-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p12-mcq'); bumpProgress('p12', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p12-mcq-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p12-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден ('+ok+'/'+QS.length+').'; addXp(15,'p12-mcq-bonus'); bumpProgress('p12', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p12-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §13 — Проводники и диэлектрики ======== */
|
||
function build_p13(){
|
||
const box = document.getElementById('p13-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Свободные носители заряда', '§ 13.1',
|
||
'<p>Все вещества разделяют на два больших класса по способности проводить электрический заряд:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li><b>Проводники</b> — есть свободные носители заряда (например, свободные электроны у металлов). Заряд легко перемещается внутри.</li>'
|
||
+'<li><b>Диэлектрики</b> (изоляторы) — носители связаны с атомами/молекулами и не могут свободно перемещаться. Заряд «застревает» там, куда попал.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('rule', 'Примеры', '§ 13.2',
|
||
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><thead><tr style="background:rgba(15,23,42,.04)"><th style="padding:6px;text-align:left">Проводники</th><th style="padding:6px;text-align:left">Диэлектрики</th></tr></thead>'
|
||
+'<tbody><tr><td style="padding:6px;border-bottom:1px dashed var(--border)">все металлы</td><td style="padding:6px;border-bottom:1px dashed var(--border)">эбонит, стекло, янтарь</td></tr>'
|
||
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">графит</td><td style="padding:6px;border-bottom:1px dashed var(--border)">дерево (сухое), пластик, резина</td></tr>'
|
||
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">растворы солей, кислот, щелочей</td><td style="padding:6px;border-bottom:1px dashed var(--border)">фарфор, бумага (сухая)</td></tr>'
|
||
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">тело человека (через жидкости)</td><td style="padding:6px;border-bottom:1px dashed var(--border)">дистиллированная вода, воздух (сухой)</td></tr>'
|
||
+'<tr><td style="padding:6px">влажная земля</td><td style="padding:6px">шёлк, мех</td></tr></tbody></table>'
|
||
);
|
||
h += makeCard('example', 'Где это видно', '§ 13.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Провода — медные (проводник), но в изоляции из пластика (диэлектрик).</li>'
|
||
+'<li>Розетки и выключатели — пластиковые корпуса.</li>'
|
||
+'<li>Заряд на металлическом шарике распределяется по всей поверхности — потому что он проводник.</li>'
|
||
+'<li>Заряд на пластиковой расчёске остаётся в месте трения — там, где «потёрли».</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — Анимация: заряд на проводнике vs диэлектрике */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Куда уходит заряд?</div></div>'
|
||
+'<div class="wg-help">Сравни: на металлическом шарике заряд <b>распределяется</b> по всей поверхности. На пластиковом — остаётся в одном месте.</div>'
|
||
+'<svg id="p13-sim" viewBox="0 0 460 220" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="actions" style="margin-top:10px"><button class="btn primary" id="p13-charge">Дать заряд в одной точке</button><button class="btn" id="p13-reset">Сброс</button></div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина пров/диэл */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Проводник или диэлектрик?</div></div>'
|
||
+'<div class="wg-help">Назови материал — выбери тип.</div>'
|
||
+'<div id="p13-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p13-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p13-quiz-r">1</b> / 8</span><span>Правильно: <b id="p13-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Сортировка материалов</div></div>'
|
||
+'<div class="wg-help">Перетащи материалы в нужную колонку.</div>'
|
||
+'<div id="p13-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Проводники</h5><div class="drop-items" data-cat="cond"></div></div>'
|
||
+'<div class="drop-box"><h5>Диэлектрики</h5><div class="drop-items" data-cat="diel"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p13-dnd-check">Проверить</button><button class="btn" id="p13-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p13-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
|
||
+'<div id="p13-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p13-mcq-i">1</b> / 6</span><span>Правильно: <b id="p13-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="p13-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p13-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p13-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.13) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §13</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.13 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p13') + readButton('p13');
|
||
renderMath(box);
|
||
wireReadBtn('p13');
|
||
_initp13_iv5();
|
||
|
||
_initP13_sim();
|
||
_initP13_quiz();
|
||
_initP13_dnd();
|
||
_initP13_mcq();
|
||
}
|
||
|
||
function _initP13_sim(){
|
||
_killSim('p13sim');
|
||
const svg = document.getElementById('p13-sim'); if(!svg) return;
|
||
/* два шара: металлический (слева) и пластиковый (справа). При нажатии «дать заряд» — на метал. заряды разлетаются по поверхности, на пласт. остаются. */
|
||
const metCx = 130, metCy = 110, R = 60;
|
||
const plCx = 330, plCy = 110;
|
||
let charges = []; /* {x, y, target: 'met'|'pla', angTarget, sett: bool, settAng } */
|
||
let phase = 0; /* 0 = пусто, 1 = заряд дан */
|
||
function reset(){ charges = []; phase = 0; draw(); }
|
||
function giveCharge(){
|
||
/* добавляем 14 минус-зарядов в одной точке (верх каждого шара) */
|
||
if(phase > 0) return;
|
||
phase = 1;
|
||
for(let i=0;i<14;i++){
|
||
const a = Math.PI * 2 * i / 14;
|
||
charges.push({ targetA: a, x: metCx, y: metCy - R + 6, kind:'met', settled: false, t: 0 });
|
||
charges.push({ targetA: 0, x: plCx, y: plCy - R + 6, kind:'pla', settled: true, t: 0 });
|
||
}
|
||
}
|
||
function tick(){
|
||
if(!_isVisible('p13')){ _SIMS.p13sim.raf = requestAnimationFrame(tick); return; }
|
||
for(const c of charges){
|
||
if(c.kind === 'met' && !c.settled){
|
||
/* движение к точке на окружности (под углом targetA) */
|
||
c.t += 0.025;
|
||
const tx = metCx + (R-8) * Math.cos(c.targetA);
|
||
const ty = metCy + (R-8) * Math.sin(c.targetA);
|
||
c.x += (tx - c.x) * 0.06;
|
||
c.y += (ty - c.y) * 0.06;
|
||
if(Math.abs(c.x - tx) < 1 && Math.abs(c.y - ty) < 1) c.settled = true;
|
||
}
|
||
/* пластиковые сразу осели */
|
||
}
|
||
let s = '';
|
||
/* шары */
|
||
s += '<circle cx="'+metCx+'" cy="'+metCy+'" r="'+R+'" fill="#cbd5e1" stroke="#0f172a" stroke-width="2"/>';
|
||
s += '<text x="'+metCx+'" y="'+(metCy+R+22)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">МЕТАЛЛ (проводник)</text>';
|
||
s += '<circle cx="'+plCx+'" cy="'+plCy+'" r="'+R+'" fill="#fde68a" stroke="#0f172a" stroke-width="2"/>';
|
||
s += '<text x="'+plCx+'" y="'+(plCy+R+22)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">ПЛАСТИК (диэлектрик)</text>';
|
||
/* заряды */
|
||
for(const c of charges){
|
||
s += '<text x="'+c.x.toFixed(1)+'" y="'+(c.y+5).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#dc2626">−</text>';
|
||
}
|
||
/* стрелки касания если phase=0 */
|
||
if(phase === 0){
|
||
s += window.PHYS.drawArrow(metCx-30, metCy-R-30, metCx, metCy-R+2, '#10b981', 2, 9);
|
||
s += window.PHYS.drawArrow(plCx-30, plCy-R-30, plCx, plCy-R+2, '#10b981', 2, 9);
|
||
s += '<text x="'+(metCx-60)+'" y="'+(metCy-R-34)+'" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">касание</text>';
|
||
s += '<text x="'+(plCx-60)+'" y="'+(plCy-R-34)+'" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">касание</text>';
|
||
}
|
||
svg.innerHTML = s;
|
||
_SIMS.p13sim.raf = requestAnimationFrame(tick);
|
||
}
|
||
_SIMS.p13sim = { raf: 0 };
|
||
_SIMS.p13sim.raf = requestAnimationFrame(tick);
|
||
document.getElementById('p13-charge').addEventListener('click', giveCharge);
|
||
document.getElementById('p13-reset').addEventListener('click', reset);
|
||
}
|
||
|
||
function _initP13_quiz(){
|
||
const QS = [
|
||
{mat:'медь', ans:'C', why:'Металл — проводник.'},
|
||
{mat:'эбонит', ans:'D', why:'Эбонит — классический диэлектрик.'},
|
||
{mat:'графит (карандаш)', ans:'C', why:'Графит — проводник.'},
|
||
{mat:'стекло', ans:'D', why:'Стекло не проводит ток.'},
|
||
{mat:'раствор поваренной соли', ans:'C', why:'В растворе есть свободные ионы — проводит.'},
|
||
{mat:'дистиллированная вода', ans:'D', why:'Чистая вода — диэлектрик (нет ионов).'},
|
||
{mat:'железо', ans:'C', why:'Металл.'},
|
||
{mat:'фарфор', ans:'D', why:'Фарфор — изолятор, поэтому из него делают изоляторы на линиях электропередачи.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p13-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5;font-weight:700;font-size:1rem">'+q.mat+'</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
|
||
+'<button class="btn" data-pick="C" style="padding:14px"><b>Проводник</b></button>'
|
||
+'<button class="btn" data-pick="D" style="padding:14px"><b>Диэлектрик</b></button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p13-quiz-fb"></div>';
|
||
document.getElementById('p13-quiz-r').textContent = (i+1);
|
||
document.getElementById('p13-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p13-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p13-quiz'); bumpProgress('p13', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p13-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p13-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP13_dnd(){
|
||
const items = [
|
||
{id:'cu', cat:'cond', html:'медь'},
|
||
{id:'al', cat:'cond', html:'алюминий'},
|
||
{id:'gr', cat:'cond', html:'графит'},
|
||
{id:'sl', cat:'cond', html:'солёная вода'},
|
||
{id:'eb', cat:'diel', html:'эбонит'},
|
||
{id:'gl', cat:'diel', html:'стекло'},
|
||
{id:'pl', cat:'diel', html:'пластик'},
|
||
{id:'dw', cat:'diel', html:'дистил. вода'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p13-dnd-pool', scopeSelector:'#sec-p13', cats:['cond','diel'], items, columnLayout:false });
|
||
document.getElementById('p13-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p13-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Металлы и растворы — проводники, остальные — диэлектрики.'; addXp(15,'p13-dnd'); bumpProgress('p13', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Дистиллированная вода — диэлектрик (нет ионов).'; }
|
||
});
|
||
document.getElementById('p13-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p13-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP13_mcq(){
|
||
const QS = [
|
||
{q:'Чем отличаются проводники от диэлектриков?', opts:['массой','цветом','свободными носителями зарядов','температурой'], ans:2, why:'У проводников есть свободные заряды, у диэлектриков — нет.'},
|
||
{q:'Какие частицы свободны в металлах?', opts:['атомы','протоны','электроны','нейтроны'], ans:2, why:'Свободные электроны переносят заряд в металлах.'},
|
||
{q:'Заряд на металлическом шарике распределяется…', opts:['в центре','в одной точке','по всей поверхности','внутри'], ans:2, why:'Свободные заряды отталкиваются и оседают по поверхности.'},
|
||
{q:'Заряд на пластиковой расчёске…', opts:['распределяется','остаётся в месте трения','исчезает','уходит в землю'], ans:1, why:'Диэлектрик не позволяет заряду перемещаться.'},
|
||
{q:'Что используют для изоляции проводов?', opts:['медь','алюминий','пластик','графит'], ans:2, why:'Пластик — хороший диэлектрик.'},
|
||
{q:'Можно ли «зарядить» проводник, держа в руке голыми пальцами?', opts:['да','нет, заряд уйдёт через тело','зависит от металла','только летом'], ans:1, why:'Тело — проводник (через жидкости), заряд уходит в землю.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p13-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p13-mcq-fb"></div><div class="actions"><button class="btn" id="p13-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p13-mcq-i').textContent = (i+1);
|
||
document.getElementById('p13-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p13-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p13-mcq'); bumpProgress('p13', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p13-mcq-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p13-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден ('+ok+'/'+QS.length+').'; addXp(15,'p13-mcq-bonus'); bumpProgress('p13', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p13-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §14 — Электризация через влияние (индукция) ======== */
|
||
function build_p14(){
|
||
const box = document.getElementById('p14-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Что такое индукция', '§ 14.1',
|
||
'<p>Если поднести заряженное тело к нейтральному <b>проводнику</b>, не касаясь его, в проводнике произойдёт <b>перераспределение</b> свободных электронов.</p>'
|
||
+'<p><b>Электризация через влияние</b> (или <b>индукция</b>) — это разделение зарядов в проводнике под действием внешнего заряда без непосредственного контакта.</p>'
|
||
+'<p>Ближний к источнику конец проводника получает заряд <b>противоположного</b> знака, дальний — того же знака.</p>'
|
||
);
|
||
h += makeCard('rule', 'Как это работает', '§ 14.2',
|
||
'<p>Подносим $+q$ к незаряженному металлическому шарику:</p>'
|
||
+'<ol style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Свободные электроны (отрицательные) притягиваются к $+q$ — собираются на <b>ближнем</b> конце.</li>'
|
||
+'<li>На <b>дальнем</b> конце остаются положительные ионы — некомпенсированный $+q$.</li>'
|
||
+'<li>В целом шарик остался нейтральным, но <b>заряды разделились</b>.</li>'
|
||
+'<li>Если теперь шарик разделить на 2 половинки — каждая будет заряжена!</li>'
|
||
+'</ol>'
|
||
);
|
||
h += makeCard('example', 'Примеры явления', '§ 14.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Заряженный шарик притягивает любой кусочек металла — даже нейтральный.</li>'
|
||
+'<li>Расчёска (заряженная) притягивает бумажки (диэлектрик слегка поляризуется).</li>'
|
||
+'<li>В стенке (диэлектрик) поляризация молекул — шарик прилипает.</li>'
|
||
+'<li>Молниеотвод собирает индукцией заряд из грозовой тучи и отводит в землю.</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — Симуляция: палочка + металлический шарик */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Поднеси заряд — увидь индукцию</div></div>'
|
||
+'<div class="wg-help">Двигай заряженную палочку (slider) — наблюдай, как электроны в металлическом шарике перераспределяются.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Положение палочки: <b id="p14-xv">слева</b><input type="range" id="p14-x" min="40" max="160" step="5" value="60"></label>'
|
||
+'<label>Знак: <select id="p14-sig" class="tinp" style="width:auto;padding:6px 10px;font-size:.92rem"><option value="-1">отрицательная (−)</option><option value="1">положительная (+)</option></select></label>'
|
||
+'</div>'
|
||
+'<svg id="p14-sim" viewBox="0 0 460 200" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>Ближний конец шара: <b id="p14-near">+</b> (противоположный палочке)</span>'
|
||
+'<span>Дальний конец шара: <b id="p14-far">−</b> (того же знака)</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина: «что будет с шаром если…» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Что произойдёт?</div></div>'
|
||
+'<div class="wg-help">Дана ситуация — определи итог.</div>'
|
||
+'<div id="p14-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p14-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p14-quiz-r">1</b> / 5</span><span>Правильно: <b id="p14-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD: «в проводнике / в диэлектрике» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Где идёт индукция, а где — поляризация?</div></div>'
|
||
+'<div class="wg-help">В проводниках — <b>индукция</b> (электроны бегут); в диэлектриках — <b>поляризация</b> (молекулы поворачиваются).</div>'
|
||
+'<div id="p14-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Индукция (в проводнике)</h5><div class="drop-items" data-cat="ind"></div></div>'
|
||
+'<div class="drop-box"><h5>Поляризация (в диэлектрике)</h5><div class="drop-items" data-cat="pol"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p14-dnd-check">Проверить</button><button class="btn" id="p14-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p14-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
|
||
+'<div id="p14-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p14-mcq-i">1</b> / 6</span><span>Правильно: <b id="p14-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="p14-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p14-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p14-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.14) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §14</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.14 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p14') + readButton('p14');
|
||
renderMath(box);
|
||
wireReadBtn('p14');
|
||
_initp14_iv5();
|
||
|
||
_initP14_sim();
|
||
_initP14_quiz();
|
||
_initP14_dnd();
|
||
_initP14_mcq();
|
||
}
|
||
|
||
function _initP14_sim(){
|
||
const svg = document.getElementById('p14-sim'); if(!svg) return;
|
||
function draw(){
|
||
const sx = +document.getElementById('p14-x').value;
|
||
const sig = +document.getElementById('p14-sig').value;
|
||
document.getElementById('p14-xv').textContent = sx < 80 ? 'далеко' : (sx < 130 ? 'близко' : 'почти касается');
|
||
/* у шарика: nearLabel = противоп. знаку палочки */
|
||
const nearSym = sig > 0 ? '−' : '+';
|
||
const farSym = sig > 0 ? '+' : '−';
|
||
document.getElementById('p14-near').innerHTML = nearSym;
|
||
document.getElementById('p14-far').innerHTML = farSym;
|
||
/* draw */
|
||
let s = '';
|
||
/* палочка слева */
|
||
s += '<rect x="'+(sx-50)+'" y="80" width="50" height="20" fill="#1e1b4b" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
|
||
const rodCol = sig > 0 ? '#dc2626' : '#2563eb';
|
||
const rodTxt = sig > 0 ? '+' : '−';
|
||
for(let i=0;i<4;i++) s += '<text x="'+(sx-42+i*12)+'" y="95" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="'+rodCol+'">'+rodTxt+'</text>';
|
||
/* металлический шарик в центре */
|
||
const shCx = 260, shCy = 90, shR = 56;
|
||
s += '<circle cx="'+shCx+'" cy="'+shCy+'" r="'+shR+'" fill="#cbd5e1" stroke="#0f172a" stroke-width="2"/>';
|
||
/* концентрация электронов на ближнем конце (если sig=+, электроны к палочке) или ионов */
|
||
const intensity = Math.min(1, (180 - sx) / 100); /* чем ближе палочка, тем сильнее эффект */
|
||
/* near = слева от шара (ближе к палочке), far = справа */
|
||
/* ставим знаки. Если палочка -, на ближнем + (т.е. на левой стороне +) */
|
||
const nearCol = sig > 0 ? '#2563eb' : '#dc2626';
|
||
const farCol = sig > 0 ? '#dc2626' : '#2563eb';
|
||
const nearTxt = sig > 0 ? '−' : '+';
|
||
const farTxt = sig > 0 ? '+' : '−';
|
||
for(let i=0;i<6;i++){
|
||
const ang = -Math.PI/2 + (i-2.5)*0.18;
|
||
const r = shR - 14;
|
||
/* near (слева) */
|
||
const nx = shCx + r*Math.cos(Math.PI + ang*0.4);
|
||
const ny = shCy + r*Math.sin(Math.PI + ang*0.4) - i*0;
|
||
s += '<text x="'+nx.toFixed(1)+'" y="'+(ny+5).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="13" font-weight="800" fill="'+nearCol+'" opacity="'+intensity.toFixed(2)+'">'+nearTxt+'</text>';
|
||
/* far (справа) */
|
||
const fx = shCx + r*Math.cos(ang*0.4);
|
||
const fy = shCy + r*Math.sin(ang*0.4);
|
||
s += '<text x="'+fx.toFixed(1)+'" y="'+(fy+5).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="13" font-weight="800" fill="'+farCol+'" opacity="'+intensity.toFixed(2)+'">'+farTxt+'</text>';
|
||
}
|
||
s += '<text x="'+shCx+'" y="'+(shCy+shR+18)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">МЕТАЛЛ. ШАР (нейтральный)</text>';
|
||
/* подпись индукции */
|
||
if(intensity > 0.3){
|
||
s += '<text x="230" y="40" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#7c3aed">индукция!</text>';
|
||
}
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p14-x').addEventListener('input', draw);
|
||
document.getElementById('p14-sig').addEventListener('change', draw);
|
||
draw();
|
||
}
|
||
|
||
function _initP14_quiz(){
|
||
const QS = [
|
||
{sit:'$+q$ поднесли к нейтральному металлическому шару, не касаясь.', opts:['шар стал +','шар стал −','шар стал нейтральным с разделёнными зарядами','шар не изменился'], ans:2, why:'Произошла индукция: внутри шара разделились заряды, но в целом он остался нейтральным.'},
|
||
{sit:'$-q$ поднесли к шару и коснулись его.', opts:['заряды шара не изменились','шар стал отрицательным','шар стал положительным','шар стал нейтральным'], ans:1, why:'Электроны с палочки перешли на шар.'},
|
||
{sit:'$+q$ долго держали возле шара, а потом убрали (не касаясь).', opts:['шар остался заряженным','шар нейтральный','шар стал отрицательным','шар стал положительным'], ans:1, why:'Без касания заряд просто перераспределялся; при удалении источника всё возвращается, шар нейтрален.'},
|
||
{sit:'$+q$ поднесли к двум прижатым друг к другу шарам. Их разъединили (не убирая $+q$), затем убрали $+q$.', opts:['оба нейтральны','оба +','оба −','один +, другой −'], ans:3, why:'При разделении в присутствии $+q$ заряды зафиксировались: дальний шар стал +, ближний −.'},
|
||
{sit:'$-q$ поднесли к листку бумаги (диэлектрик).', opts:['ничего','бумага зарядилась +','в бумаге поляризация, она притянулась','бумага оттолкнулась'], ans:2, why:'В диэлектрике молекулы поляризуются, листок притягивается.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p14-quiz'); if(!wrap) return;
|
||
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="padding:10px 14px;text-align:left">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
html += '</div><div class="feedback" id="p14-quiz-fb"></div>';
|
||
wrap.innerHTML = html;
|
||
document.getElementById('p14-quiz-r').textContent = (i+1);
|
||
document.getElementById('p14-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p14-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p14-quiz'); bumpProgress('p14', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p14-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p14-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP14_dnd(){
|
||
const items = [
|
||
{id:'ms', cat:'ind', html:'$+q$ возле металлического шара'},
|
||
{id:'mf', cat:'ind', html:'заряженный шар возле фольги'},
|
||
{id:'mp', cat:'ind', html:'заряженный шар возле железной пластины'},
|
||
{id:'mw', cat:'ind', html:'$+q$ возле провода'},
|
||
{id:'pl', cat:'pol', html:'$-q$ возле клочка бумаги'},
|
||
{id:'pg', cat:'pol', html:'$+q$ возле стеклянной палочки'},
|
||
{id:'pw', cat:'pol', html:'$-q$ возле деревянной планки'},
|
||
{id:'pp', cat:'pol', html:'$+q$ возле пластиковой пластины'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p14-dnd-pool', scopeSelector:'#sec-p14', cats:['ind','pol'], items, columnLayout:false });
|
||
document.getElementById('p14-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p14-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. В проводниках индукция, в диэлектриках поляризация — оба эффекта приводят к притяжению.'; addXp(15,'p14-dnd'); bumpProgress('p14', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Металлы и фольга — проводники, остальное — диэлектрики.'; }
|
||
});
|
||
document.getElementById('p14-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p14-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP14_mcq(){
|
||
const QS = [
|
||
{q:'Что такое электризация через влияние?', opts:['заряжение трением','перенос заряда касанием','разделение зарядов в проводнике без касания','испускание электронов'], ans:2, why:'Это разделение зарядов внутри проводника под действием внешнего заряда.'},
|
||
{q:'Ближний к источнику конец проводника получает заряд…', opts:['того же знака','противоположного','становится нейтральным','положительный'], ans:1, why:'Притягиваются заряды противоположного знака.'},
|
||
{q:'После убирания внешнего заряда (без касания) проводник…', opts:['остаётся заряженным','становится нейтральным','меняет знак','раскалывается'], ans:1, why:'Перераспределение исчезает, и проводник снова нейтрален.'},
|
||
{q:'Если в присутствии $+q$ разъединить шар на 2 части, что станет с частями после убирания $+q$?', opts:['обе +','обе −','одна +, другая −','обе нейтральны'], ans:2, why:'Разделение зафиксировалось: ближняя часть −, дальняя +.'},
|
||
{q:'Почему листочки бумаги притягиваются к расчёске?', opts:['индукция','поляризация молекул в диэлектрике','магнетизм','гравитация'], ans:1, why:'В диэлектрике молекулы поляризуются, и листок притягивается.'},
|
||
{q:'Молниеотвод использует…', opts:['индукцию','теплопередачу','излучение','реакцию горения'], ans:0, why:'Индукция собирает заряд из тучи на острие и отводит его в землю.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p14-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p14-mcq-fb"></div><div class="actions"><button class="btn" id="p14-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p14-mcq-i').textContent = (i+1);
|
||
document.getElementById('p14-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p14-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p14-mcq'); bumpProgress('p14', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p14-mcq-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p14-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден ('+ok+'/'+QS.length+').'; addXp(15,'p14-mcq-bonus'); bumpProgress('p14', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p14-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 2 · WAVE 2 — §15, §16
|
||
====================================================================== */
|
||
|
||
const E_CHARGE = 1.6e-19;
|
||
|
||
/* ======== §15 — Электрический заряд. Элементарный заряд ======== */
|
||
function build_p15(){
|
||
const box = document.getElementById('p15-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Элементарный заряд', '§ 15.1',
|
||
'<p>Эксперимент Милликена с масляными каплями показал: <b>заряд тела всегда кратен</b> наименьшей порции — <b>элементарному заряду</b>:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$e = 1{,}6 \\cdot 10^{-19} \\text{ Кл}$$</p>'
|
||
+'<p>Это заряд одного электрона (со знаком «−») и одного протона (со знаком «+»). Меньше — не бывает (это <b>квантуется</b>).</p>'
|
||
);
|
||
h += makeCard('rule', 'Формула $q = N e$', '§ 15.2',
|
||
'<p>Если у тела «лишних» $N$ электронов, его заряд:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$q = N \\cdot e$$</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>$q < 0$ — избыток электронов;</li>'
|
||
+'<li>$q > 0$ — нехватка электронов;</li>'
|
||
+'<li>$q = 0$ — нейтральное тело (число +зарядов = число −зарядов).</li>'
|
||
+'</ul>'
|
||
+'<p>Сколько электронов в 1 Кл? $N = 1/e = 6{,}25 \\cdot 10^{18}$ — это огромное число.</p>'
|
||
);
|
||
h += makeCard('example', 'Закон сохранения заряда', '§ 15.3',
|
||
'<p>В замкнутой системе сумма всех зарядов <b>не меняется</b>:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$\\sum q_i = \\text{const}$$</p>'
|
||
+'<p>Электризация трением — не «появление» заряда, а его <b>перенос</b>: было два нейтральных тела (всего 0), стало $+q$ и $-q$ (сумма всё ещё 0).</p>'
|
||
);
|
||
|
||
/* IV1 — калькулятор q ↔ N */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Сколько электронов?</div></div>'
|
||
+'<div class="wg-help">Преобразуй между числом электронов $N$ и зарядом $q$ в нанокулонах.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Число электронов $N$: <b id="p15-nv">10<sup>9</sup></b><input type="range" id="p15-n" min="6" max="18" step="0.5" value="9"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="margin-top:8px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$N$ = <b id="p15-nval">1 000 000 000</b></span>'
|
||
+'<span>$|q| = N e$ = <b id="p15-qval">1.6×10<sup>-10</sup></b> Кл = <b id="p15-qnc">0.16</b> нКл</span>'
|
||
+'<span style="font-size:.84rem;color:var(--muted)">Это очень малый заряд — почти неощутим.</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина квантования */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Может ли существовать такой заряд?</div></div>'
|
||
+'<div class="wg-help">Проверь, кратен ли указанный заряд $e = 1{,}6 \\cdot 10^{-19}$ Кл.</div>'
|
||
+'<div id="p15-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p15-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p15-quiz-r">1</b> / 6</span><span>Правильно: <b id="p15-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD сохранение заряда */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Сохраняется ли заряд?</div></div>'
|
||
+'<div class="wg-help">Распредели ситуации: где общий заряд изменился, а где остался прежним.</div>'
|
||
+'<div id="p15-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Сохраняется</h5><div class="drop-items" data-cat="keep"></div></div>'
|
||
+'<div class="drop-box"><h5>Меняется (внеш. вмешат.)</h5><div class="drop-items" data-cat="ext"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p15-dnd-check">Проверить</button><button class="btn" id="p15-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p15-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — числовые задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 расчётных задач</div></div>'
|
||
+'<div class="wg-help">4+ правильных — +15 XP. $e = 1{,}6 \\cdot 10^{-19}$ Кл.</div>'
|
||
+'<div id="p15-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p15-task-i">1</b> / 5</span><span>Правильно: <b id="p15-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.15) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §15</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.15 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p15') + readButton('p15');
|
||
renderMath(box);
|
||
wireReadBtn('p15');
|
||
|
||
_initP15_calc();
|
||
_initP15_quiz();
|
||
_initP15_dnd();
|
||
_initP15_tasks();
|
||
}
|
||
|
||
function _initP15_calc(){
|
||
function update(){
|
||
const exp = +document.getElementById('p15-n').value;
|
||
const N = Math.pow(10, exp);
|
||
document.getElementById('p15-nv').innerHTML = '10<sup>'+exp.toFixed(1)+'</sup>';
|
||
document.getElementById('p15-nval').textContent = N.toExponential(2).replace('+','');
|
||
const q = N * E_CHARGE;
|
||
const qExp = Math.floor(Math.log10(q));
|
||
const qMant = (q/Math.pow(10,qExp)).toFixed(2);
|
||
document.getElementById('p15-qval').innerHTML = qMant+'×10<sup>'+qExp+'</sup>';
|
||
document.getElementById('p15-qnc').textContent = (q*1e9).toExponential(2).replace('+','');
|
||
}
|
||
document.getElementById('p15-n').addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
function _initP15_quiz(){
|
||
const QS = [
|
||
{q:'$q = 3{,}2 \\cdot 10^{-19}$ Кл', ans:'Y', why:'$N = q/e = 2$ — кратно, существует.'},
|
||
{q:'$q = 8 \\cdot 10^{-19}$ Кл', ans:'Y', why:'$N = 5$ — целое, существует.'},
|
||
{q:'$q = 2{,}4 \\cdot 10^{-19}$ Кл', ans:'N', why:'$N = 1{,}5$ — не целое, не существует.'},
|
||
{q:'$q = 1 \\cdot 10^{-19}$ Кл', ans:'N', why:'$N = 0{,}625$ — не целое.'},
|
||
{q:'$q = 1{,}6 \\cdot 10^{-18}$ Кл', ans:'Y', why:'$N = 10$ — целое, существует.'},
|
||
{q:'$q = 5 \\cdot 10^{-19}$ Кл', ans:'N', why:'$N = 3{,}125$ — не целое.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p15-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5;font-size:1.05rem">'+q.q+'</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
|
||
+'<button class="btn" data-pick="Y" style="padding:14px"><b>Существует</b></button>'
|
||
+'<button class="btn" data-pick="N" style="padding:14px"><b>Не существует</b></button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p15-quiz-fb"></div>';
|
||
document.getElementById('p15-quiz-r').textContent = (i+1);
|
||
document.getElementById('p15-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p15-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p15-quiz'); bumpProgress('p15', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p15-quiz-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
});
|
||
});
|
||
renderMath(wrap);
|
||
}
|
||
document.getElementById('p15-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP15_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'keep', html:'трение двух тел в изолированной системе'},
|
||
{id:'b', cat:'keep', html:'переход электронов внутри проводника'},
|
||
{id:'c', cat:'keep', html:'индукция в шарике'},
|
||
{id:'d', cat:'keep', html:'два шара соприкоснулись и разъединились'},
|
||
{id:'e', cat:'ext', html:'тело заземлили (заряд ушёл в землю)'},
|
||
{id:'f', cat:'ext', html:'тело потёрли о внешний предмет, а потом убрали'},
|
||
{id:'g', cat:'ext', html:'к телу поднесли «насос электронов»'},
|
||
{id:'h', cat:'ext', html:'тело облучили рентгеном (выбил электроны)'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p15-dnd-pool', scopeSelector:'#sec-p15', cats:['keep','ext'], items, columnLayout:false });
|
||
document.getElementById('p15-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p15-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Заряд сохраняется в изолированной системе.'; addXp(15,'p15-dnd'); bumpProgress('p15', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Заземление и внешнее излучение — это внешнее вмешательство.'; }
|
||
});
|
||
document.getElementById('p15-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p15-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP15_tasks(){
|
||
const TASKS = [
|
||
{q:'Сколько электронов нужно собрать, чтобы получить заряд $q = -1$ нКл? ($e = 1{,}6 \\cdot 10^{-19}$ Кл) — Ответ в формате $N \\cdot 10^9$, введи $N$ с одним знаком после запятой.', ans:6.25, tol:0.1, why:'$N = q/e = 10^{-9}/(1{,}6\\cdot10^{-19}) = 6{,}25 \\cdot 10^9$. Ответ: $6{,}25$.'},
|
||
{q:'У тела «лишних» $5 \\cdot 10^{10}$ электронов. Каков его заряд (в нКл, по модулю)?', ans:8, tol:0.2, why:'$q = Ne = 5\\cdot10^{10} \\cdot 1{,}6\\cdot10^{-19} = 8\\cdot10^{-9}$ Кл = $8$ нКл.'},
|
||
{q:'У одного тела $q_1 = +3$ нКл, у другого $q_2 = -5$ нКл. После их соприкосновения и разделения сумма $q_1 + q_2$ равна (в нКл)?', ans:-2, tol:0.05, why:'Заряд сохраняется: $3 + (-5) = -2$ нКл (так и осталось после контакта).'},
|
||
{q:'Какой заряд (в Кл, по модулю) получится при $N = 2 \\cdot 10^{19}$? Ответ в формате $a \\cdot 10^0$, введи $a$ (одно число).', ans:3.2, tol:0.05, why:'$q = 2\\cdot10^{19} \\cdot 1{,}6\\cdot10^{-19} = 3{,}2$ Кл — это очень много!'},
|
||
{q:'Заряд $q = 4{,}8 \\cdot 10^{-19}$ Кл существует? Если да — сколько в нём электронов? Введи $N$.', ans:3, tol:0.1, why:'$N = q/e = 4{,}8/1{,}6 = 3$. Заряд существует, в нём 3 элементарных.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p15-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p15-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p15-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p15-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p15-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p15-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p15-task-fb"></div>';
|
||
document.getElementById('p15-task-i').textContent = (i+1);
|
||
document.getElementById('p15-task-ok').textContent = ok;
|
||
document.getElementById('p15-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p15-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p15-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p15-task'); bumpProgress('p15', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Правильный ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p15-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p15-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы ('+ok+'/'+TASKS.length+').'; addXp(15,'p15-task-bonus'); bumpProgress('p15', 15); }, 600); }
|
||
});
|
||
document.getElementById('p15-task-hint').addEventListener('click', ()=>{ document.getElementById('p15-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p15-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §16 — Строение атома. Ионы ======== */
|
||
function build_p16(){
|
||
const box = document.getElementById('p16-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Планетарная модель атома', '§ 16.1',
|
||
'<p>Атом устроен как маленькая «солнечная система»:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li><b>Ядро</b> в центре — очень маленькое (10<sup>-15</sup> м), но в нём почти вся масса. Состоит из <b>протонов</b> ($+e$) и <b>нейтронов</b> (нейтральные).</li>'
|
||
+'<li><b>Электроны</b> ($-e$) движутся вокруг ядра по оболочкам.</li>'
|
||
+'<li>Атом в целом размером $\\sim 10^{-10}$ м — ядро в 100 000 раз меньше всего атома.</li>'
|
||
+'</ul>'
|
||
+'<p>В <b>нейтральном</b> атоме число электронов = число протонов = <b>атомный номер</b> $Z$.</p>'
|
||
);
|
||
h += makeCard('rule', 'Ионы', '§ 16.2',
|
||
'<p>Если атом <b>потерял</b> 1 или больше электронов — он становится <b>положительным ионом (катионом)</b>: $\\text{Na} \\to \\text{Na}^+$.</p>'
|
||
+'<p>Если атом <b>принял</b> лишний электрон — он становится <b>отрицательным ионом (анионом)</b>: $\\text{Cl} \\to \\text{Cl}^-$.</p>'
|
||
+'<p>Соли в растворах диссоциируют на ионы — поэтому растворы солей проводят ток.</p>'
|
||
);
|
||
h += makeCard('example', 'Атомы и ионы', '§ 16.3',
|
||
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><thead><tr style="background:rgba(15,23,42,.04)"><th style="padding:6px">Элемент</th><th style="padding:6px;text-align:center">$Z$</th><th style="padding:6px;text-align:center">Электр.</th><th style="padding:6px;text-align:center">Заряд иона</th></tr></thead>'
|
||
+'<tbody><tr><td style="padding:6px;border-bottom:1px dashed var(--border)">водород H</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">1</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">1</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">H<sup>+</sup></td></tr>'
|
||
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">натрий Na</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">11</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">11</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">Na<sup>+</sup></td></tr>'
|
||
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">хлор Cl</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">17</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">17</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">Cl<sup>−</sup></td></tr>'
|
||
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">кальций Ca</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">20</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">20</td><td style="padding:6px;border-bottom:1px dashed var(--border);text-align:center">Ca<sup>2+</sup></td></tr>'
|
||
+'<tr><td style="padding:6px">кислород O</td><td style="padding:6px;text-align:center">8</td><td style="padding:6px;text-align:center">8</td><td style="padding:6px;text-align:center">O<sup>2−</sup></td></tr></tbody></table>'
|
||
);
|
||
|
||
/* IV1 — конструктор атома */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Конструктор атома / иона</div></div>'
|
||
+'<div class="wg-help">Меняй число протонов и электронов — увидь, нейтрален ли атом и какой ион получится.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Протонов ($Z$): <b id="p16-zv">11</b><input type="range" id="p16-z" min="1" max="20" step="1" value="11"></label>'
|
||
+'<label>Электронов: <b id="p16-ev">11</b><input type="range" id="p16-e" min="0" max="20" step="1" value="11"></label>'
|
||
+'</div>'
|
||
+'<svg id="p16-sim" viewBox="0 0 460 240" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>Заряд: <b id="p16-qbal">0</b> (нейтрален)</span>'
|
||
+'<span>Состояние: <b id="p16-state">нейтральный атом</b></span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина по таблице */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Какой заряд у иона?</div></div>'
|
||
+'<div class="wg-help">Дан элемент и преобразование — назови заряд получившегося иона.</div>'
|
||
+'<div id="p16-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p16-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p16-quiz-r">1</b> / 6</span><span>Правильно: <b id="p16-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD сортировка частиц */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Сортировка частиц</div></div>'
|
||
+'<div class="wg-help">Распредели частицы по знаку заряда.</div>'
|
||
+'<div id="p16-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Положительные</h5><div class="drop-items" data-cat="pos"></div></div>'
|
||
+'<div class="drop-box"><h5>Отрицательные</h5><div class="drop-items" data-cat="neg"></div></div>'
|
||
+'<div class="drop-box"><h5>Нейтральные</h5><div class="drop-items" data-cat="neu"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p16-dnd-check">Проверить</button><button class="btn" id="p16-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p16-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
|
||
+'<div id="p16-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p16-mcq-i">1</b> / 6</span><span>Правильно: <b id="p16-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="p16-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p16-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p16-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.16) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §16</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.16 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p16') + readButton('p16');
|
||
renderMath(box);
|
||
wireReadBtn('p16');
|
||
_initp16_iv5();
|
||
|
||
_initP16_atom();
|
||
_initP16_quiz();
|
||
_initP16_dnd();
|
||
_initP16_mcq();
|
||
}
|
||
|
||
function _initP16_atom(){
|
||
const svg = document.getElementById('p16-sim'); if(!svg) return;
|
||
function draw(){
|
||
const Z = +document.getElementById('p16-z').value;
|
||
const N = +document.getElementById('p16-e').value;
|
||
document.getElementById('p16-zv').textContent = Z;
|
||
document.getElementById('p16-ev').textContent = N;
|
||
const delta = Z - N;
|
||
document.getElementById('p16-qbal').textContent = (delta > 0 ? '+'+delta : (delta < 0 ? delta : '0'))+' e';
|
||
let state = '';
|
||
if(delta === 0) state = 'нейтральный атом';
|
||
else if(delta > 0) state = 'катион (+'+delta+')';
|
||
else state = 'анион ('+delta+')';
|
||
document.getElementById('p16-state').textContent = state;
|
||
/* draw */
|
||
const cx = 230, cy = 120;
|
||
let s = '';
|
||
/* электронные оболочки */
|
||
const shellRs = [50, 80, 110];
|
||
for(const r of shellRs) s += '<circle cx="'+cx+'" cy="'+cy+'" r="'+r+'" fill="none" stroke="#cbd5e1" stroke-width="1" stroke-dasharray="3 3"/>';
|
||
/* ядро */
|
||
s += '<circle cx="'+cx+'" cy="'+cy+'" r="22" fill="#fef3c7" stroke="#dc2626" stroke-width="2"/>';
|
||
s += '<text x="'+cx+'" y="'+(cy+5)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="800" fill="#dc2626">'+Z+'p</text>';
|
||
/* электроны на оболочках: 2 на K (50), 8 на L (80), остальное на M (110) */
|
||
let placed = 0;
|
||
const shellMax = [2, 8, 18];
|
||
for(let sh = 0; sh < 3 && placed < N; sh++){
|
||
const r = shellRs[sh];
|
||
const count = Math.min(shellMax[sh], N - placed);
|
||
for(let i = 0; i < count; i++){
|
||
const ang = 2 * Math.PI * i / count + sh * 0.3;
|
||
const ex = cx + r*Math.cos(ang);
|
||
const ey = cy + r*Math.sin(ang);
|
||
s += '<circle cx="'+ex.toFixed(1)+'" cy="'+ey.toFixed(1)+'" r="5" fill="#2563eb" stroke="#0f172a" stroke-width="0.8"/>';
|
||
s += '<text x="'+ex.toFixed(1)+'" y="'+(ey+3).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="9" font-weight="800" fill="#fff">−</text>';
|
||
}
|
||
placed += count;
|
||
}
|
||
/* пометка заряда */
|
||
if(delta !== 0){
|
||
const sign = delta > 0 ? '+' : '';
|
||
const col = delta > 0 ? '#dc2626' : '#2563eb';
|
||
s += '<text x="'+(cx+130)+'" y="'+(cy-90)+'" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="20" font-weight="900" fill="'+col+'">'+sign+delta+'</text>';
|
||
}
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p16-z').addEventListener('input', draw);
|
||
document.getElementById('p16-e').addEventListener('input', draw);
|
||
draw();
|
||
}
|
||
|
||
function _initP16_quiz(){
|
||
const QS = [
|
||
{q:'Na отдал 1 электрон. Какой ион?', opts:['Na<sup>+</sup>','Na<sup>−</sup>','Na<sup>2+</sup>','Na'], ans:0, why:'Потерял 1 электрон → катион +1.'},
|
||
{q:'Cl принял 1 электрон. Какой ион?', opts:['Cl<sup>+</sup>','Cl<sup>−</sup>','Cl<sup>2−</sup>','Cl'], ans:1, why:'Принял 1 → анион −1.'},
|
||
{q:'Ca отдал 2 электрона. Заряд иона?', opts:['+1','+2','−1','0'], ans:1, why:'2 потерянных электрона → +2.'},
|
||
{q:'O принял 2 электрона. Заряд иона?', opts:['+2','−2','−1','0'], ans:1, why:'2 принятых электрона → −2.'},
|
||
{q:'Сколько электронов у Na<sup>+</sup>? ($Z_{Na}$=11)', opts:['10','11','12','9'], ans:0, why:'Был 11, отдал 1, остался 10.'},
|
||
{q:'Сколько электронов у Cl<sup>−</sup>? ($Z_{Cl}$=17)', opts:['18','17','16','19'], ans:0, why:'Принял 1, стало 18.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p16-quiz'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p16-quiz-fb"></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p16-quiz-r').textContent = (i+1);
|
||
document.getElementById('p16-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p16-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p16-quiz'); bumpProgress('p16', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p16-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p16-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP16_dnd(){
|
||
const items = [
|
||
{id:'p', cat:'pos', html:'протон'},
|
||
{id:'na', cat:'pos', html:'ион Na<sup>+</sup>'},
|
||
{id:'ca', cat:'pos', html:'ион Ca<sup>2+</sup>'},
|
||
{id:'e', cat:'neg', html:'электрон'},
|
||
{id:'cl', cat:'neg', html:'ион Cl<sup>−</sup>'},
|
||
{id:'o', cat:'neg', html:'ион O<sup>2−</sup>'},
|
||
{id:'n', cat:'neu', html:'нейтрон'},
|
||
{id:'aH', cat:'neu', html:'атом водорода H'},
|
||
{id:'aHe',cat:'neu', html:'атом гелия He'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p16-dnd-pool', scopeSelector:'#sec-p16', cats:['pos','neg','neu'], items, columnLayout:false });
|
||
document.getElementById('p16-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p16-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Протон + катион, электрон + анион, нейтрон/атомы — нейтральные.'; addXp(15,'p16-dnd'); bumpProgress('p16', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Подсказка: нейтрон и сами атомы — нейтральные, ионы — заряжены.'; }
|
||
});
|
||
document.getElementById('p16-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p16-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP16_mcq(){
|
||
const QS = [
|
||
{q:'Что находится в ядре атома?', opts:['электроны','протоны и нейтроны','только протоны','только нейтроны'], ans:1, why:'Ядро = протоны + нейтроны.'},
|
||
{q:'Какой заряд у протона?', opts:['$-e$','$+e$','0','$+2e$'], ans:1, why:'Протон несёт элементарный + заряд.'},
|
||
{q:'Какой заряд у нейтрона?', opts:['$-e$','$+e$','0','$+2e$'], ans:2, why:'Нейтрон нейтрален.'},
|
||
{q:'В нейтральном атоме число электронов равно…', opts:['числу нейтронов','числу протонов','массовому числу','$Z+N$'], ans:1, why:'$Z$ электронов компенсируют $Z$ протонов.'},
|
||
{q:'Какой ион получится, если атом отдаст 2 электрона?', opts:['−2','−1','+1','+2'], ans:3, why:'2 потерянных электрона → заряд +2.'},
|
||
{q:'Что больше: атом или ядро?', opts:['ядро','атом','одинаково','зависит от элемента'], ans:1, why:'Атом примерно в 100 000 раз больше ядра.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p16-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p16-mcq-fb"></div><div class="actions"><button class="btn" id="p16-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p16-mcq-i').textContent = (i+1);
|
||
document.getElementById('p16-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p16-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p16-mcq'); bumpProgress('p16', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p16-mcq-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p16-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден ('+ok+'/'+QS.length+').'; addXp(15,'p16-mcq-bonus'); bumpProgress('p16', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p16-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 2 · WAVE 3 — §17, §18
|
||
====================================================================== */
|
||
|
||
/* ======== §17 — Электрическое поле. Напряжение ======== */
|
||
function build_p17(){
|
||
const box = document.getElementById('p17-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Что такое электрическое поле', '§ 17.1',
|
||
'<p>Заряды действуют друг на друга <b>на расстоянии</b>, без прямого контакта. Как же передаётся это взаимодействие?</p>'
|
||
+'<p>Ответ: вокруг каждого заряда существует <b>электрическое поле</b> — особый вид материи. Поле — посредник.</p>'
|
||
+'<p>Когда мы помещаем в это поле другой заряд, поле действует на него с некоторой <b>силой</b>:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>от $+q$ поле «отталкивает» другие $+q$ и «притягивает» $-q$;</li>'
|
||
+'<li>от $-q$ — наоборот.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('rule', 'Линии электрического поля', '§ 17.2',
|
||
'<p>Поле наглядно изображают линиями со стрелками. Они показывают направление силы, которая действовала бы на <b>пробный положительный</b> заряд.</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Линии выходят из <b>$+q$</b> и входят в <b>$-q$</b>.</li>'
|
||
+'<li>Не пересекаются.</li>'
|
||
+'<li>Чем гуще линии — тем сильнее поле.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('example', 'Напряжение', '§ 17.3',
|
||
'<p>Чтобы переместить заряд $q$ внутри поля, поле совершает (или над ним совершают) <b>работу</b>. Эта работа зависит от того, между какими двумя точками идёт перемещение.</p>'
|
||
+'<p><b>Электрическое напряжение</b> $U$ между точками A и B — это работа поля по переносу единичного $+q$ из A в B:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$U_{AB} = \\dfrac{A}{q}$$</p>'
|
||
+'<p>Подробно — в § 18.</p>'
|
||
);
|
||
|
||
/* IV1 — линии поля точечного заряда */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Линии электрического поля</div></div>'
|
||
+'<div class="wg-help">Выбери знак заряда — увидь, как направлены линии поля.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Знак заряда: <select id="p17-sig" class="tinp" style="width:auto;padding:6px 10px"><option value="1">$+q$ (отталкивает)</option><option value="-1">$-q$ (притягивает)</option></select></label>'
|
||
+'<label>Сила поля: <b id="p17-sv">средняя</b><input type="range" id="p17-s" min="40" max="120" step="10" value="80"></label>'
|
||
+'</div>'
|
||
+'<svg id="p17-sim" viewBox="0 0 460 240" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «линии поля» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Куда направлены линии?</div></div>'
|
||
+'<div class="wg-help">Свойства линий поля.</div>'
|
||
+'<div id="p17-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p17-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p17-quiz-r">1</b> / 5</span><span>Правильно: <b id="p17-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD факты */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Правда или ложь?</div></div>'
|
||
+'<div class="wg-help">Утверждения о поле и напряжении.</div>'
|
||
+'<div id="p17-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Правда</h5><div class="drop-items" data-cat="t"></div></div>'
|
||
+'<div class="drop-box"><h5>Ложь</h5><div class="drop-items" data-cat="f"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p17-dnd-check">Проверить</button><button class="btn" id="p17-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p17-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
|
||
+'<div id="p17-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p17-mcq-i">1</b> / 6</span><span>Правильно: <b id="p17-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="p17-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p17-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p17-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — Field Visualizer (Phase 2.2) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Силовые линии — карта поля</div></div>'
|
||
+'<div class="wg-help">Перетаскивай заряды. Силовые линии рисуются live: выходят из + и заходят в −. Густота линий = напряжённость $E$.</div>'
|
||
+'<div class="p8-sandbox" id="p17-iv6-sandbox" style="height:320px"></div>'
|
||
+'<div style="margin-top:10px;display:flex;gap:10px;flex-wrap:wrap">'
|
||
+'<button class="btn" id="p17-iv6-add-pos">+ Заряд</button>'
|
||
+'<button class="btn" id="p17-iv6-add-neg">− Заряд</button>'
|
||
+'<button class="btn" id="p17-iv6-clear">Сброс</button>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p17') + readButton('p17');
|
||
renderMath(box);
|
||
wireReadBtn('p17');
|
||
_initP17_iv6();
|
||
_initp17_iv5();
|
||
|
||
_initP17_field();
|
||
_initP17_quiz();
|
||
_initP17_dnd();
|
||
_initP17_mcq();
|
||
}
|
||
|
||
function _initP17_field(){
|
||
const svg = document.getElementById('p17-sim'); if(!svg) return;
|
||
function draw(){
|
||
const sig = +document.getElementById('p17-sig').value;
|
||
const scale = +document.getElementById('p17-s').value;
|
||
document.getElementById('p17-sv').textContent = scale < 60 ? 'слабая' : scale < 100 ? 'средняя' : 'сильная';
|
||
const cx = 230, cy = 120;
|
||
let s = '';
|
||
s += window.PHYS.fieldLinesPointCharge(cx, cy, sig, scale, 14);
|
||
s += window.PHYS.chargeMark(cx, cy, sig, 22, sig > 0 ? '+q' : '−q');
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p17-sig').addEventListener('change', draw);
|
||
document.getElementById('p17-s').addEventListener('input', draw);
|
||
draw();
|
||
}
|
||
|
||
function _initP17_quiz(){
|
||
const QS = [
|
||
{sit:'Линии поля около +q идут…', opts:['наружу','внутрь','параллельно','по кругу'], ans:0, why:'От + наружу.'},
|
||
{sit:'Линии поля около −q идут…', opts:['наружу','внутрь','параллельно','по кругу'], ans:1, why:'К − внутрь.'},
|
||
{sit:'Чем гуще линии, тем поле…', opts:['слабее','сильнее','не меняется','исчезает'], ans:1, why:'Густота показывает силу поля.'},
|
||
{sit:'Линии поля могут пересекаться?', opts:['да','нет','только в вакууме','только у проводников'], ans:1, why:'В каждой точке поле имеет одно направление.'},
|
||
{sit:'Поле двух одинаковых +q посередине между ними…', opts:['большое','нулевое','перпендикулярное','непрерывное'], ans:1, why:'Силы от двух зарядов равны и противоположны — компенсируются.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p17-quiz'); if(!wrap) return;
|
||
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
html += '</div><div class="feedback" id="p17-quiz-fb"></div>';
|
||
wrap.innerHTML = html;
|
||
document.getElementById('p17-quiz-r').textContent = (i+1);
|
||
document.getElementById('p17-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p17-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p17-quiz'); bumpProgress('p17', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p17-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p17-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP17_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'t', html:'Электрическое поле — особый вид материи'},
|
||
{id:'b', cat:'t', html:'Поле существует вокруг любого заряда'},
|
||
{id:'c', cat:'t', html:'$U_{AB} = A/q$ — определение напряжения'},
|
||
{id:'d', cat:'t', html:'Линии поля начинаются на + и кончаются на −'},
|
||
{id:'e', cat:'f', html:'Поле — это вакуум вокруг заряда'},
|
||
{id:'f', cat:'f', html:'Линии поля могут пересекаться'},
|
||
{id:'g', cat:'f', html:'Напряжение — это сила, действующая на заряд'},
|
||
{id:'h', cat:'f', html:'Поле существует только в вакууме'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p17-dnd-pool', scopeSelector:'#sec-p17', cats:['t','f'], items, columnLayout:false });
|
||
document.getElementById('p17-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p17-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Поле — материя; напряжение — работа на ед. заряда.'; addXp(15,'p17-dnd'); bumpProgress('p17', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p17-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p17-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP17_mcq(){
|
||
const QS = [
|
||
{q:'Через что заряды взаимодействуют?', opts:['напрямую','через эл. поле','через гравитацию','через воздух'], ans:1, why:'Поле — посредник взаимодействия.'},
|
||
{q:'Откуда выходят линии поля?', opts:['из −','из +','из любого','ниоткуда'], ans:1, why:'Линии начинаются на +.'},
|
||
{q:'Что показывают линии поля?', opts:['массу','направление силы на +q','скорость','температуру'], ans:1, why:'Линии — направление силы на пробный +.'},
|
||
{q:'Куда направлена сила на $-q$ в поле, идущем направо?', opts:['направо','налево','вверх','никуда'], ans:1, why:'На −q сила направлена против поля.'},
|
||
{q:'$U_{AB}$ — это…', opts:['сила поля','энергия заряда','работа поля на ед. заряд','скорость заряда'], ans:2, why:'$U = A/q$ — определение.'},
|
||
{q:'Если убрать заряд-источник, поле…', opts:['останется','исчезнет','инвертируется','усилится'], ans:1, why:'Поле существует только пока есть его источник.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p17-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p17-mcq-fb"></div><div class="actions"><button class="btn" id="p17-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p17-mcq-i').textContent = (i+1);
|
||
document.getElementById('p17-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p17-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p17-mcq'); bumpProgress('p17', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p17-mcq-ok').textContent = ok;
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p17-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p17-mcq-bonus'); bumpProgress('p17', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p17-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §18 — A = qU ======== */
|
||
function build_p18(){
|
||
const box = document.getElementById('p18-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Формула $A = qU$', '§ 18.1',
|
||
'<p>Если перенести заряд $q$ через разность потенциалов $U$, поле совершит работу:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$A = q \\, U$$</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>$A$ — работа, Дж;</li>'
|
||
+'<li>$q$ — заряд, Кл;</li>'
|
||
+'<li>$U$ — напряжение, В.</li>'
|
||
+'</ul>'
|
||
+'<p>Если $A > 0$ — поле «помогает» движению заряда; $A < 0$ — заряд движется «против» поля.</p>'
|
||
);
|
||
h += makeCard('rule', 'Что такое 1 Вольт', '§ 18.2',
|
||
'<p>1 Вольт — это такое напряжение, при котором поле совершает работу 1 Джоуль на каждый 1 Кулон переносимого заряда:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$1 \\text{ В} = \\dfrac{1 \\text{ Дж}}{1 \\text{ Кл}}$$</p>'
|
||
+'<p>Один из величайших физиков Алессандро Вольта изобрёл первый источник тока — гальванический элемент. В его честь и названа единица.</p>'
|
||
);
|
||
h += makeCard('example', 'Напряжения в быту', '§ 18.3',
|
||
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><tbody>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Батарейка</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>1{,}5 В</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Крона</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>9 В</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Автомобильный аккумулятор</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>12 В</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Зарядка для телефона</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>5 В</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">Розетка</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>220 В</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">ЛЭП высокого напряжения</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>10 000 — 750 000 В</code></td></tr>'
|
||
+'<tr><td style="padding:5px">Молния</td><td style="padding:5px;text-align:right"><code>$10^8$ В</code></td></tr>'
|
||
+'</tbody></table>'
|
||
);
|
||
|
||
/* IV1 — калькулятор A=qU */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Калькулятор $A = qU$</div></div>'
|
||
+'<div class="wg-help">Меняй $q$ и $U$ — увидь работу поля.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$q$, мКл (10<sup>−3</sup> Кл): <b id="p18-qv">1.0</b><input type="range" id="p18-q" min="0.1" max="10" step="0.1" value="1"></label>'
|
||
+'<label>$U$, В: <b id="p18-uv">220</b><input type="range" id="p18-u" min="1" max="500" step="1" value="220"></label>'
|
||
+'</div>'
|
||
+'<svg id="p18-sim" viewBox="0 0 460 140" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$A = q U$ = <b id="p18-a">0.22</b> Дж</span>'
|
||
+'<span style="font-size:.84rem;color:var(--muted)">Этой энергии хватит, чтобы <b id="p18-anal">поднять груз 22 г на 1 м</b>.</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «дано / найди» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Что найти?</div></div>'
|
||
+'<div class="wg-help">По формуле $A = qU$ найди недостающую величину.</div>'
|
||
+'<div id="p18-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p18-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p18-quiz-r">1</b> / 5</span><span>Правильно: <b id="p18-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «напряжения по возрастанию» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Расставь напряжения по возрастанию</div></div>'
|
||
+'<div class="wg-help">От самого маленького к самому большому.</div>'
|
||
+'<div id="p18-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>1. Меньше</h5><div class="drop-items" data-cat="r1"></div></div>'
|
||
+'<div class="drop-box"><h5>2</h5><div class="drop-items" data-cat="r2"></div></div>'
|
||
+'<div class="drop-box"><h5>3</h5><div class="drop-items" data-cat="r3"></div></div>'
|
||
+'<div class="drop-box"><h5>4</h5><div class="drop-items" data-cat="r4"></div></div>'
|
||
+'<div class="drop-box"><h5>5. Больше</h5><div class="drop-items" data-cat="r5"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p18-dnd-check">Проверить</button><button class="btn" id="p18-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p18-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — расчётные задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 задач</div></div>'
|
||
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
|
||
+'<div id="p18-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p18-task-i">1</b> / 5</span><span>Правильно: <b id="p18-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.18) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §18</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.18 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p18') + readButton('p18');
|
||
renderMath(box);
|
||
wireReadBtn('p18');
|
||
|
||
_initP18_calc();
|
||
_initP18_quiz();
|
||
_initP18_dnd();
|
||
_initP18_tasks();
|
||
}
|
||
|
||
function _initP18_calc(){
|
||
const svg = document.getElementById('p18-sim'); if(!svg) return;
|
||
function update(){
|
||
const qmC = +document.getElementById('p18-q').value;
|
||
const U = +document.getElementById('p18-u').value;
|
||
const q = qmC * 1e-3; /* мКл → Кл */
|
||
const A = q * U;
|
||
document.getElementById('p18-qv').textContent = qmC.toFixed(1);
|
||
document.getElementById('p18-uv').textContent = U;
|
||
document.getElementById('p18-a').textContent = A.toFixed(3);
|
||
/* аналогия: поднять груз на 1 м, m = A/(g*1) */
|
||
const g = 9.8;
|
||
const massG = (A/g) * 1000;
|
||
document.getElementById('p18-anal').textContent = 'поднять груз '+massG.toFixed(0)+' г на 1 м';
|
||
/* sim */
|
||
let s = '';
|
||
/* батарея */
|
||
s += window.PHYS.batteryEMF(80, 70, U+' В', 'h');
|
||
/* стрелка переноса заряда */
|
||
s += '<text x="160" y="60" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#dc2626">q = '+qmC.toFixed(1)+' мКл</text>';
|
||
s += window.PHYS.drawArrow(180, 100, 320, 100, '#10b981', 2.5, 11);
|
||
s += '<text x="250" y="120" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" fill="#0f172a">A = qU = '+A.toFixed(3)+' Дж</text>';
|
||
/* итог "лампа" */
|
||
s += window.PHYS.lightbulbSymbol(360, 80, 22);
|
||
s += '<text x="360" y="125" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" fill="#475569">энергия</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p18-q').addEventListener('input', update);
|
||
document.getElementById('p18-u').addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
function _initP18_quiz(){
|
||
const QS = [
|
||
{q:'Заряд $q = 2$ Кл прошёл напряжение $U = 5$ В. Найди $A$ (Дж).', ans:10, tol:0.1, why:'$A = qU = 2 \\cdot 5 = 10$ Дж.'},
|
||
{q:'$A = 240$ Дж, $U = 12$ В. Какой заряд прошёл (Кл)?', ans:20, tol:0.5, why:'$q = A/U = 240/12 = 20$ Кл.'},
|
||
{q:'$A = 6$ Дж, $q = 30$ мКл $= 0{,}03$ Кл. Найди $U$ (В).', ans:200, tol:2, why:'$U = A/q = 6/0{,}03 = 200$ В.'},
|
||
{q:'Поле перенесло $q = 0{,}5$ Кл через $U = 220$ В. Найди $A$ (Дж).', ans:110, tol:1, why:'$A = 0{,}5 \\cdot 220 = 110$ Дж.'},
|
||
{q:'$A = 4{,}5$ Дж, $q = 3$ Кл. Найди $U$ (В).', ans:1.5, tol:0.05, why:'$U = 4{,}5/3 = 1{,}5$ В — это батарейка.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const t = QS[i]; const wrap = document.getElementById('p18-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p18-quiz-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p18-quiz-go">Ответ</button></div>'
|
||
+'<div class="feedback" id="p18-quiz-fb"></div>';
|
||
document.getElementById('p18-quiz-r').textContent = (i+1);
|
||
document.getElementById('p18-quiz-ok').textContent = ok;
|
||
document.getElementById('p18-quiz-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p18-quiz-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p18-quiz-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(3,'p18-quiz'); bumpProgress('p18', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p18-quiz-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
});
|
||
renderMath(wrap);
|
||
}
|
||
document.getElementById('p18-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP18_dnd(){
|
||
const items = [
|
||
{id:'bat', cat:'r1', html:'батарейка ($1{,}5$ В)'},
|
||
{id:'kr', cat:'r2', html:'аккумулятор авто ($12$ В)'},
|
||
{id:'sock',cat:'r3', html:'розетка ($220$ В)'},
|
||
{id:'lep', cat:'r4', html:'ЛЭП ($10^5$ В)'},
|
||
{id:'lit', cat:'r5', html:'молния ($10^8$ В)'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p18-dnd-pool', scopeSelector:'#sec-p18', cats:['r1','r2','r3','r4','r5'], items, columnLayout:false });
|
||
document.getElementById('p18-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p18-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Диапазон напряжений в природе огромен — от вольта до миллиардов.'; addXp(15,'p18-dnd'); bumpProgress('p18', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p18-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p18-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP18_tasks(){
|
||
const TASKS = [
|
||
{q:'Электрон ($q = 1{,}6 \\cdot 10^{-19}$ Кл) прошёл $U = 1$ В. Найди $A$ в эВ (это и есть 1 эВ). Введи в Джоулях, в формате $a \\cdot 10^{-19}$, введи $a$.', ans:1.6, tol:0.05, why:'$A = qU = 1{,}6\\cdot10^{-19} \\cdot 1 = 1{,}6\\cdot10^{-19}$ Дж = 1 эВ.'},
|
||
{q:'$U = 220$ В, $q = 5$ Кл. Сколько Дж энергии передало поле?', ans:1100, tol:5, why:'$A = 5 \\cdot 220 = 1100$ Дж.'},
|
||
{q:'В лампе работа $A = 60$ Дж за 1 с при $U = 220$ В. Какой заряд прошёл (в Кл, округли до сотых)?', ans:0.27, tol:0.02, why:'$q = A/U = 60/220 \\approx 0{,}273$ Кл.'},
|
||
{q:'Заряд $q = 2$ мКл переместился через $U = 100$ В. Найди $A$ в мДж.', ans:200, tol:5, why:'$A = qU = 2\\cdot10^{-3} \\cdot 100 = 0{,}2$ Дж = $200$ мДж.'},
|
||
{q:'$A = 1$ Дж, $q = 1$ Кл. Найди $U$.', ans:1, tol:0.05, why:'$U = A/q = 1/1 = 1$ В — определение единицы.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p18-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p18-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p18-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p18-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p18-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p18-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p18-task-fb"></div>';
|
||
document.getElementById('p18-task-i').textContent = (i+1);
|
||
document.getElementById('p18-task-ok').textContent = ok;
|
||
document.getElementById('p18-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p18-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p18-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p18-task'); bumpProgress('p18', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p18-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p18-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы ('+ok+'/'+TASKS.length+').'; addXp(15,'p18-task-bonus'); bumpProgress('p18', 15); }, 600); }
|
||
});
|
||
document.getElementById('p18-task-hint').addEventListener('click', ()=>{ document.getElementById('p18-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p18-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 3 · WAVE 1 — §19, §20
|
||
====================================================================== */
|
||
|
||
/* ======== §19 — Электрический ток. Источники тока ======== */
|
||
function build_p19(){
|
||
const box = document.getElementById('p19-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Что такое электрический ток', '§ 19.1',
|
||
'<p><b>Электрический ток</b> — упорядоченное (направленное) движение свободных заряженных частиц.</p>'
|
||
+'<p>В проводе у каждой точки много электронов, движущихся хаотически. Если приложить эл. поле — все они «сдвигаются» в одну сторону. Это и есть ток.</p>'
|
||
+'<p>Для существования тока нужно:</p>'
|
||
+'<ol style="padding-left:20px;margin:6px 0">'
|
||
+'<li><b>свободные носители заряда</b> (электроны в металле, ионы в растворе);</li>'
|
||
+'<li><b>электрическое поле</b>, заставляющее их двигаться упорядоченно.</li>'
|
||
+'</ol>'
|
||
);
|
||
h += makeCard('rule', 'Источники тока', '§ 19.2',
|
||
'<p><b>Источник тока</b> создаёт и поддерживает эл. поле в цепи. Внутри него «<b>сторонние силы</b>» (химические, механические, световые) переносят заряды против поля — от одного электрода к другому.</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li><b>Гальванический элемент (батарейка)</b> — химическая энергия → электрическая.</li>'
|
||
+'<li><b>Аккумулятор</b> — то же, но с обратимой реакцией (заряжается).</li>'
|
||
+'<li><b>Генератор</b> — механическая → электрическая (на электростанции).</li>'
|
||
+'<li><b>Фотоэлемент</b> — световая → электрическая.</li>'
|
||
+'<li><b>Термоэлемент</b> — тепловая → электрическая.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('example', 'Простейшая батарейка', '§ 19.3',
|
||
'<p>Два разных металла (например, медь и цинк) опущенные в раствор кислоты, дают электрический ток. Цинк отдаёт электроны в раствор и становится «−». Медь принимает электроны и становится «+».</p>'
|
||
+'<p>Так устроен <b>гальванический элемент</b> — изобретение Алессандро Вольта (1799 г.). Это была первая в истории батарейка!</p>'
|
||
);
|
||
|
||
/* IV1 — анимация работы батарейки */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Как работает батарейка</div></div>'
|
||
+'<div class="wg-help">Включи цепь — увидь, как электроны «бегут» по проводу от $-$ к $+$, а внутри батарейки «насос» переносит их в обратную сторону.</div>'
|
||
+'<svg id="p19-sim" viewBox="0 0 460 220" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="actions" style="margin-top:10px"><button class="btn primary" id="p19-on">Замкнуть цепь</button><button class="btn" id="p19-reset">Сброс</button></div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина источников */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Какая энергия превращается в электрическую?</div></div>'
|
||
+'<div class="wg-help">Определи тип источника по принципу работы.</div>'
|
||
+'<div id="p19-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p19-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p19-quiz-r">1</b> / 5</span><span>Правильно: <b id="p19-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «можно/нельзя получить ток» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Есть ли в этой системе ток?</div></div>'
|
||
+'<div class="wg-help">Распредели ситуации.</div>'
|
||
+'<div id="p19-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Есть ток</h5><div class="drop-items" data-cat="y"></div></div>'
|
||
+'<div class="drop-box"><h5>Нет тока</h5><div class="drop-items" data-cat="n"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p19-dnd-check">Проверить</button><button class="btn" id="p19-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p19-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p19-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p19-mcq-i">1</b> / 6</span><span>Правильно: <b id="p19-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="p19-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p19-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p19-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.19) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §19</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.19 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p19') + readButton('p19');
|
||
renderMath(box);
|
||
wireReadBtn('p19');
|
||
_initp19_iv5();
|
||
|
||
_initP19_sim();
|
||
_initP19_quiz();
|
||
_initP19_dnd();
|
||
_initP19_mcq();
|
||
}
|
||
|
||
function _initP19_sim(){
|
||
_killSim('p19sim');
|
||
const svg = document.getElementById('p19-sim'); if(!svg) return;
|
||
let on = false;
|
||
const N = 14;
|
||
const electrons = [];
|
||
/* Путь: батарея (40,110) → провод вверх → горизонталь → вниз → лампа → возврат */
|
||
/* Замкнутый контур по часовой стрелке (электроны двигаются ПРОТИВ тока — против часовой) */
|
||
/* Точки контура */
|
||
const path = [
|
||
{x:80, y:170}, /* − батареи (низ) */
|
||
{x:80, y:60}, /* левый верхний угол */
|
||
{x:200, y:60}, /* перед лампой */
|
||
{x:230, y:90}, /* в лампу */
|
||
{x:260, y:60}, /* выход лампы */
|
||
{x:380, y:60}, /* правый верхний угол */
|
||
{x:380, y:170}, /* + батареи (низ) */
|
||
{x:80, y:170} /* возврат через батарею */
|
||
];
|
||
/* Длина пути */
|
||
function pathLen(){
|
||
let L = 0;
|
||
for(let i=0;i<path.length-1;i++){ L += Math.hypot(path[i+1].x-path[i].x, path[i+1].y-path[i].y); }
|
||
return L;
|
||
}
|
||
const totalLen = pathLen();
|
||
for(let i = 0; i < N; i++) electrons.push({ t: i * (totalLen/N) });
|
||
function posAt(t){
|
||
let rem = ((t % totalLen) + totalLen) % totalLen;
|
||
for(let i=0;i<path.length-1;i++){
|
||
const seg = Math.hypot(path[i+1].x-path[i].x, path[i+1].y-path[i].y);
|
||
if(rem <= seg){
|
||
const k = rem/seg;
|
||
return { x: path[i].x + (path[i+1].x-path[i].x)*k, y: path[i].y + (path[i+1].y-path[i].y)*k };
|
||
}
|
||
rem -= seg;
|
||
}
|
||
return path[0];
|
||
}
|
||
function tick(){
|
||
if(!_isVisible('p19')){ _SIMS.p19sim.raf = requestAnimationFrame(tick); return; }
|
||
if(on) for(const e of electrons) e.t += 1.4;
|
||
let s = '';
|
||
/* провода */
|
||
for(let i=0;i<path.length-1;i++){
|
||
s += '<line x1="'+path[i].x+'" y1="'+path[i].y+'" x2="'+path[i+1].x+'" y2="'+path[i+1].y+'" stroke="#374151" stroke-width="3"/>';
|
||
}
|
||
/* батарея слева */
|
||
s += '<rect x="40" y="115" width="80" height="60" fill="#e0f2fe" stroke="#0f172a" stroke-width="2" rx="4"/>';
|
||
s += '<text x="80" y="135" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#0f172a">источник</text>';
|
||
s += '<text x="55" y="170" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#dc2626">+</text>';
|
||
s += '<text x="100" y="170" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#2563eb">−</text>';
|
||
/* стрелка тока I (внутри цепи) */
|
||
if(on){
|
||
s += '<text x="230" y="40" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#d97706">I →</text>';
|
||
}
|
||
/* лампа в центре */
|
||
s += window.PHYS.lightbulbSymbol(230, 90, 18);
|
||
if(on){
|
||
/* свечение */
|
||
s += '<circle cx="230" cy="90" r="28" fill="#fde047" opacity="0.45"/>';
|
||
s += '<circle cx="230" cy="90" r="40" fill="#fbbf24" opacity="0.18"/>';
|
||
}
|
||
/* электроны двигаются против тока — то есть против хода path */
|
||
for(const e of electrons){
|
||
const p = posAt(-e.t);
|
||
s += '<circle cx="'+p.x.toFixed(1)+'" cy="'+p.y.toFixed(1)+'" r="4.5" fill="#2563eb" stroke="#0f172a" stroke-width="0.6"/>';
|
||
s += '<text x="'+p.x.toFixed(1)+'" y="'+(p.y+3).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="9" font-weight="800" fill="#fff">−</text>';
|
||
}
|
||
svg.innerHTML = s;
|
||
_SIMS.p19sim.raf = requestAnimationFrame(tick);
|
||
}
|
||
_SIMS.p19sim = { raf: 0 };
|
||
_SIMS.p19sim.raf = requestAnimationFrame(tick);
|
||
document.getElementById('p19-on').addEventListener('click', ()=>{
|
||
on = !on;
|
||
document.getElementById('p19-on').textContent = on ? 'Разомкнуть' : 'Замкнуть цепь';
|
||
});
|
||
document.getElementById('p19-reset').addEventListener('click', ()=>{
|
||
on = false; document.getElementById('p19-on').textContent = 'Замкнуть цепь';
|
||
for(let i=0;i<N;i++) electrons[i].t = i * (totalLen/N);
|
||
});
|
||
}
|
||
|
||
function _initP19_quiz(){
|
||
const QS = [
|
||
{sit:'Гальванический элемент', ans:'C', why:'Химическая (реакция в электролите) → электрическая.'},
|
||
{sit:'Гидроэлектростанция (плотина)', ans:'M', why:'Механическая (вращение турбины) → электрическая.'},
|
||
{sit:'Солнечная батарея', ans:'L', why:'Световая (фотоны) → электрическая.'},
|
||
{sit:'Термопара', ans:'T', why:'Тепловая → электрическая.'},
|
||
{sit:'Аккумулятор автомобиля', ans:'C', why:'Химическая, как и батарейка.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p19-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px">'
|
||
+'<button class="btn" data-pick="C" style="padding:10px"><b>Химическая</b></button>'
|
||
+'<button class="btn" data-pick="M" style="padding:10px"><b>Механическая</b></button>'
|
||
+'<button class="btn" data-pick="L" style="padding:10px"><b>Световая</b></button>'
|
||
+'<button class="btn" data-pick="T" style="padding:10px"><b>Тепловая</b></button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p19-quiz-fb"></div>';
|
||
document.getElementById('p19-quiz-r').textContent = (i+1);
|
||
document.getElementById('p19-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p19-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p19-quiz'); bumpProgress('p19', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p19-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p19-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP19_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'y', html:'медный провод + батарейка + лампа'},
|
||
{id:'b', cat:'y', html:'раствор соли + 2 угольных электрода + батарейка'},
|
||
{id:'c', cat:'y', html:'аккумулятор автомобиля при стартере'},
|
||
{id:'d', cat:'y', html:'солнечная панель в светлый день'},
|
||
{id:'e', cat:'n', html:'стеклянный стакан + батарейка'},
|
||
{id:'f', cat:'n', html:'разомкнутый ключ + батарейка'},
|
||
{id:'g', cat:'n', html:'сухое дерево + батарейка'},
|
||
{id:'h', cat:'n', html:'медный провод без источника'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p19-dnd-pool', scopeSelector:'#sec-p19', cats:['y','n'], items, columnLayout:false });
|
||
document.getElementById('p19-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p19-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Нужны: проводник + источник + замкнутая цепь.'; addXp(15,'p19-dnd'); bumpProgress('p19', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Без источника или с разомкнутой цепью тока нет.'; }
|
||
});
|
||
document.getElementById('p19-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p19-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP19_mcq(){
|
||
const QS = [
|
||
{q:'Что такое электрический ток?', opts:['хаос. движение','упорядоченное движение зарядов','нагрев тела','сила поля'], ans:1, why:'Ток = направленное движение свободных зарядов.'},
|
||
{q:'Что нужно для тока?', opts:['только поле','только проводник','свободные носители + поле','магнит'], ans:2, why:'Носители + поле.'},
|
||
{q:'В батарейке энергия…', opts:['световая → эл.','химическая → эл.','механическая → эл.','тепловая → эл.'], ans:1, why:'Химическая реакция переносит заряды.'},
|
||
{q:'Зачем нужен источник тока в цепи?', opts:['греть провод','создавать и поддерживать поле','охлаждать','тратить заряд'], ans:1, why:'Источник поддерживает разность потенциалов.'},
|
||
{q:'Что переносит заряды внутри источника против поля?', opts:['внешние силы','сторонние силы','гравитация','магнетизм'], ans:1, why:'Это и есть «сторонние силы».'},
|
||
{q:'Куда «бегут» свободные электроны в цепи (от куда к куда)?', opts:['от + к −','от − к +','туда-сюда','стоят на месте'], ans:1, why:'Электроны двигаются от − к + по внешней цепи (против тока).'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p19-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p19-mcq-fb"></div><div class="actions"><button class="btn" id="p19-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p19-mcq-i').textContent = (i+1);
|
||
document.getElementById('p19-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p19-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p19-mcq'); bumpProgress('p19', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p19-mcq-ok').textContent = ok;
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p19-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p19-mcq-bonus'); bumpProgress('p19', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p19-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §20 — Сила и направление тока ======== */
|
||
function build_p20(){
|
||
const box = document.getElementById('p20-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Сила тока', '§ 20.1',
|
||
'<p><b>Сила тока</b> $I$ показывает, сколько заряда проходит через поперечное сечение проводника за единицу времени:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$I = \\dfrac{q}{t}$$</p>'
|
||
+'<p>Единица измерения — <b>Ампер (А)</b>. <b>1 А</b> — это $1$ Кл, проходящий за $1$ с (это очень много электронов: $\\approx 6\\cdot 10^{18}$ за секунду!).</p>'
|
||
+'<p>Названа в честь французского физика Андре-Мари Ампера.</p>'
|
||
);
|
||
h += makeCard('rule', 'Направление тока', '§ 20.2',
|
||
'<p>Исторически за направление тока приняли направление движения <b>положительных зарядов</b> — от «+» к «−» во внешней цепи.</p>'
|
||
+'<p>Однако в металлах реально двигаются <b>электроны</b> — от «−» к «+», то есть <b>против</b> направления тока.</p>'
|
||
+'<p>Это «договорённость» — она сформировалась до открытия электрона. Менять её уже поздно.</p>'
|
||
);
|
||
h += makeCard('example', 'Типичные токи', '§ 20.3',
|
||
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><tbody>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">наушники</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>~1 мА</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">светодиод</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>~10 мА</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">лампочка карманного фонаря</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>~0,3 А</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">лампа 60 Вт в розетке</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>~0,27 А</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">чайник электрический</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>~10 А</code></td></tr>'
|
||
+'<tr><td style="padding:5px;border-bottom:1px dashed var(--border)">стартер автомобиля</td><td style="padding:5px;text-align:right;border-bottom:1px dashed var(--border)"><code>~200 А</code></td></tr>'
|
||
+'<tr><td style="padding:5px">молния</td><td style="padding:5px;text-align:right"><code>$\\sim 10^4 - 10^5$ А</code></td></tr>'
|
||
+'</tbody></table>'
|
||
);
|
||
|
||
/* IV1 — симуляция тока с регулировкой */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Поток электронов в проводе</div></div>'
|
||
+'<div class="wg-help">Меняй $I$ — увидь, как меняется скорость потока электронов в проводе. Лампа загорается сильнее при большем токе.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$I$, А: <b id="p20-iv">0.3</b><input type="range" id="p20-i" min="0" max="3" step="0.1" value="0.3"></label>'
|
||
+'</div>'
|
||
+'<svg id="p20-sim" viewBox="0 0 460 180" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>За 1 с пройдёт <b id="p20-q1">0.3</b> Кл</span><span>Это <b id="p20-ne">1.9×10<sup>18</sup></b> электронов</span></div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «по формуле» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Найди по формуле $I = q/t$</div></div>'
|
||
+'<div class="wg-help">Числовые вопросы.</div>'
|
||
+'<div id="p20-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p20-quiz-next">Следующая</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p20-quiz-r">1</b> / 5</span><span>Правильно: <b id="p20-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «токи по возрастанию» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Расставь по возрастанию тока</div></div>'
|
||
+'<div class="wg-help">От самого слабого тока к самому большому.</div>'
|
||
+'<div id="p20-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>1. Меньше</h5><div class="drop-items" data-cat="r1"></div></div>'
|
||
+'<div class="drop-box"><h5>2</h5><div class="drop-items" data-cat="r2"></div></div>'
|
||
+'<div class="drop-box"><h5>3</h5><div class="drop-items" data-cat="r3"></div></div>'
|
||
+'<div class="drop-box"><h5>4</h5><div class="drop-items" data-cat="r4"></div></div>'
|
||
+'<div class="drop-box"><h5>5. Больше</h5><div class="drop-items" data-cat="r5"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p20-dnd-check">Проверить</button><button class="btn" id="p20-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p20-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — расчётные задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 задач</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p20-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p20-task-i">1</b> / 5</span><span>Правильно: <b id="p20-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.20) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §20</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.20 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p20') + readButton('p20');
|
||
renderMath(box);
|
||
wireReadBtn('p20');
|
||
|
||
_initP20_sim();
|
||
_initP20_quiz();
|
||
_initP20_dnd();
|
||
_initP20_tasks();
|
||
}
|
||
|
||
function _initP20_sim(){
|
||
_killSim('p20sim');
|
||
const svg = document.getElementById('p20-sim'); if(!svg) return;
|
||
const N = 22;
|
||
const electrons = [];
|
||
for(let i=0;i<N;i++) electrons.push({ x: 60 + i*16, y: 90 });
|
||
let I = 0.3;
|
||
function tick(){
|
||
if(!_isVisible('p20')){ _SIMS.p20sim.raf = requestAnimationFrame(tick); return; }
|
||
/* скорость пропорциональна I */
|
||
const v = I * 1.5;
|
||
for(const e of electrons){
|
||
e.x -= v; /* электроны двигаются справа налево (против тока, которое идёт слева направо) */
|
||
if(e.x < 60) e.x += (400 - 60);
|
||
}
|
||
let s = '';
|
||
/* провод */
|
||
s += '<rect x="60" y="80" width="340" height="20" fill="#cbd5e1" stroke="#0f172a" stroke-width="2" rx="3"/>';
|
||
/* стрелки тока I (направление + → −, слева направо для удобства) */
|
||
if(I > 0){
|
||
s += '<text x="230" y="60" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#d97706">I →</text>';
|
||
s += window.PHYS.drawArrow(190, 70, 270, 70, '#d97706', 2.2, 9);
|
||
}
|
||
/* электроны */
|
||
for(const e of electrons){
|
||
s += '<circle cx="'+e.x.toFixed(1)+'" cy="'+e.y+'" r="4" fill="#2563eb" stroke="#0f172a" stroke-width="0.5"/>';
|
||
}
|
||
/* подпись о направлении электронов */
|
||
if(I > 0){
|
||
s += '<text x="230" y="135" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" fill="#2563eb">электроны ← (против тока)</text>';
|
||
}
|
||
/* лампа справа */
|
||
s += window.PHYS.lightbulbSymbol(420, 90, 16);
|
||
/* свечение зависит от I */
|
||
if(I > 0){
|
||
const glow = Math.min(1, I/2);
|
||
s += '<circle cx="420" cy="90" r="'+(20+I*10).toFixed(0)+'" fill="#fde047" opacity="'+(glow*0.4).toFixed(2)+'"/>';
|
||
s += '<circle cx="420" cy="90" r="'+(34+I*15).toFixed(0)+'" fill="#fbbf24" opacity="'+(glow*0.15).toFixed(2)+'"/>';
|
||
}
|
||
svg.innerHTML = s;
|
||
_SIMS.p20sim.raf = requestAnimationFrame(tick);
|
||
}
|
||
_SIMS.p20sim = { raf: 0 };
|
||
_SIMS.p20sim.raf = requestAnimationFrame(tick);
|
||
function update(){
|
||
I = +document.getElementById('p20-i').value;
|
||
document.getElementById('p20-iv').textContent = I.toFixed(1);
|
||
document.getElementById('p20-q1').textContent = I.toFixed(1);
|
||
const Ne = I / E_CHARGE;
|
||
document.getElementById('p20-ne').innerHTML = (Ne/1e18).toFixed(2)+'×10<sup>18</sup>';
|
||
}
|
||
document.getElementById('p20-i').addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
function _initP20_quiz(){
|
||
const QS = [
|
||
{q:'$q = 6$ Кл прошло за $t = 2$ с. Найди $I$ (А).', ans:3, tol:0.05, why:'$I = 6/2 = 3$ А.'},
|
||
{q:'$I = 0{,}5$ А, $t = 10$ с. Найди $q$ (Кл).', ans:5, tol:0.05, why:'$q = It = 0{,}5 \\cdot 10 = 5$ Кл.'},
|
||
{q:'$q = 60$ Кл, $I = 2$ А. Найди $t$ (с).', ans:30, tol:0.5, why:'$t = q/I = 60/2 = 30$ с.'},
|
||
{q:'За 1 минуту прошёл заряд $q = 30$ Кл. Найди $I$ (А).', ans:0.5, tol:0.05, why:'$I = 30/60 = 0{,}5$ А.'},
|
||
{q:'$I = 0{,}1$ А течёт 5 мин. Какой заряд (Кл)?', ans:30, tol:0.5, why:'$t = 300$ с, $q = 0{,}1 \\cdot 300 = 30$ Кл.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const t = QS[i]; const wrap = document.getElementById('p20-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p20-quiz-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p20-quiz-go">Ответ</button></div>'
|
||
+'<div class="feedback" id="p20-quiz-fb"></div>';
|
||
document.getElementById('p20-quiz-r').textContent = (i+1);
|
||
document.getElementById('p20-quiz-ok').textContent = ok;
|
||
document.getElementById('p20-quiz-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p20-quiz-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p20-quiz-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(3,'p20-quiz'); bumpProgress('p20', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p20-quiz-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
});
|
||
renderMath(wrap);
|
||
}
|
||
document.getElementById('p20-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP20_dnd(){
|
||
const items = [
|
||
{id:'h', cat:'r1', html:'наушники ($1$ мА)'},
|
||
{id:'l', cat:'r2', html:'светодиод ($10$ мА)'},
|
||
{id:'f', cat:'r3', html:'лампа в розетке ($0{,}3$ А)'},
|
||
{id:'k', cat:'r4', html:'чайник ($10$ А)'},
|
||
{id:'s', cat:'r5', html:'стартер ($200$ А)'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p20-dnd-pool', scopeSelector:'#sec-p20', cats:['r1','r2','r3','r4','r5'], items, columnLayout:false });
|
||
document.getElementById('p20-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p20-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Бытовые токи — от миллиампер до 100+ А.'; addXp(15,'p20-dnd'); bumpProgress('p20', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p20-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p20-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP20_tasks(){
|
||
const TASKS = [
|
||
{q:'Через лампу за 0,5 с прошёл заряд 0,15 Кл. Найди ток (А).', ans:0.3, tol:0.02, why:'$I = q/t = 0{,}15/0{,}5 = 0{,}3$ А.'},
|
||
{q:'$I = 2$ А течёт 10 минут. Сколько Кл пройдёт?', ans:1200, tol:10, why:'$t = 600$ с, $q = 2 \\cdot 600 = 1200$ Кл.'},
|
||
{q:'Сколько электронов проходит через сечение провода за 1 с при $I = 1$ А? Ответ в формате $a \\cdot 10^{18}$, введи $a$.', ans:6.25, tol:0.05, why:'$N = I \\cdot 1/e = 1/(1{,}6\\cdot10^{-19}) = 6{,}25 \\cdot 10^{18}$.'},
|
||
{q:'Через спираль чайника за 30 секунд прошло 300 Кл. Найди ток (А).', ans:10, tol:0.1, why:'$I = 300/30 = 10$ А.'},
|
||
{q:'Светодиод работает на токе $I = 20$ мА = $0{,}02$ А. Сколько Кл пройдёт за час?', ans:72, tol:1, why:'$t = 3600$ с, $q = 0{,}02 \\cdot 3600 = 72$ Кл.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p20-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p20-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p20-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p20-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p20-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p20-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p20-task-fb"></div>';
|
||
document.getElementById('p20-task-i').textContent = (i+1);
|
||
document.getElementById('p20-task-ok').textContent = ok;
|
||
document.getElementById('p20-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p20-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p20-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p20-task'); bumpProgress('p20', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p20-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p20-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p20-task-bonus'); bumpProgress('p20', 15); }, 600); }
|
||
});
|
||
document.getElementById('p20-task-hint').addEventListener('click', ()=>{ document.getElementById('p20-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p20-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 3 · WAVE 2 — §21, §22
|
||
====================================================================== */
|
||
|
||
/* ======== §21 — Эл. цепь. Амперметр и вольтметр ======== */
|
||
function build_p21(){
|
||
const box = document.getElementById('p21-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Элементы цепи', '§ 21.1',
|
||
'<p>Простейшая электрическая цепь состоит из:</p>'
|
||
+'<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>'
|
||
+'<p>На схемах элементы рисуют условными значками — это <b>принципиальная схема</b>.</p>'
|
||
);
|
||
h += makeCard('rule', 'Амперметр и вольтметр', '§ 21.2',
|
||
'<p><b>Амперметр</b> измеряет силу тока. Подключается <b>последовательно</b> с измеряемым участком — чтобы весь ток шёл через него.</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Имеет очень маленькое сопротивление, чтобы почти не «съедать» напряжение.</li>'
|
||
+'<li>Нельзя включать параллельно — сгорит!</li>'
|
||
+'</ul>'
|
||
+'<p><b>Вольтметр</b> измеряет напряжение. Подключается <b>параллельно</b> участку — чтобы измерить разность потенциалов на его концах.</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Имеет очень большое сопротивление, чтобы почти не отбирать ток.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('example', 'Простейшая принципиальная схема', '§ 21.3',
|
||
'<p>Батарея $\\varepsilon$ — лампа $L$ — амперметр $A$ — ключ $K$ — обратно к батарее. Это всё в одной «петле» — <b>последовательная цепь</b>.</p>'
|
||
+'<p>Параллельно лампе подключён вольтметр $V$ — он измеряет напряжение именно на ней.</p>'
|
||
);
|
||
|
||
/* IV1 — конструктор цепи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Простейшая электрическая цепь</div></div>'
|
||
+'<div class="wg-help">Включи ключ — увидь, как через лампу пошёл ток. Амперметр и вольтметр показывают свои значения.</div>'
|
||
+'<svg id="p21-sim" viewBox="0 0 460 260" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="actions" style="margin-top:10px"><button class="btn primary" id="p21-key">Замкнуть ключ</button><button class="btn" id="p21-reset">Разомкнуть</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Амперметр: <b id="p21-amp">0 А</b></span><span>Вольтметр: <b id="p21-volt">0 В</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «куда включать прибор?» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Как включать прибор?</div></div>'
|
||
+'<div class="wg-help">Определи правильное подключение.</div>'
|
||
+'<div id="p21-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p21-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p21-quiz-r">1</b> / 6</span><span>Правильно: <b id="p21-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «правильно/неправильно» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Что правильно?</div></div>'
|
||
+'<div class="wg-help">Распредели утверждения.</div>'
|
||
+'<div id="p21-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Правильно</h5><div class="drop-items" data-cat="t"></div></div>'
|
||
+'<div class="drop-box"><h5>Неправильно</h5><div class="drop-items" data-cat="f"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p21-dnd-check">Проверить</button><button class="btn" id="p21-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p21-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p21-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p21-mcq-i">1</b> / 6</span><span>Правильно: <b id="p21-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="p21-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p21-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p21-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.21) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §21</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.21 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p21') + readButton('p21');
|
||
renderMath(box);
|
||
wireReadBtn('p21');
|
||
_initp21_iv5();
|
||
|
||
_initP21_sim();
|
||
_initP21_quiz();
|
||
_initP21_dnd();
|
||
_initP21_mcq();
|
||
}
|
||
|
||
function _initP21_sim(){
|
||
const svg = document.getElementById('p21-sim'); if(!svg) return;
|
||
let closed = false;
|
||
function draw(){
|
||
let s = '';
|
||
/* схема: батарея слева внизу, по проводам идём: справа от батареи вверх → амперметр → вправо → лампа → вниз → обратно к батарее. Вольтметр параллельно лампе. */
|
||
/* батарея */
|
||
s += window.PHYS.batteryEMF(80, 200, '4,5 В', 'h');
|
||
/* провода */
|
||
s += window.PHYS.wire(80, 180, 80, 80); /* левый верт. */
|
||
s += window.PHYS.wire(80, 80, 180, 80); /* верх к ам-ру */
|
||
s += window.PHYS.wire(220, 80, 280, 80); /* ам-р к лампе */
|
||
s += window.PHYS.wire(310, 80, 380, 80); /* после лампы */
|
||
s += window.PHYS.wire(380, 80, 380, 200); /* правый верт. */
|
||
s += window.PHYS.wire(380, 200, 80, 200);/* низ (через батарею) */
|
||
/* амперметр (последовательно) */
|
||
s += window.PHYS.ammeterSymbol(200, 80, 18);
|
||
/* лампа */
|
||
s += window.PHYS.lightbulbSymbol(295, 80, 18);
|
||
if(closed){
|
||
s += '<circle cx="295" cy="80" r="28" fill="#fde047" opacity="0.45"/>';
|
||
s += '<circle cx="295" cy="80" r="40" fill="#fbbf24" opacity="0.18"/>';
|
||
}
|
||
/* вольтметр (параллельно лампе) */
|
||
s += window.PHYS.wire(295, 100, 295, 140);
|
||
s += window.PHYS.wire(295, 140, 250, 140);
|
||
s += window.PHYS.wire(250, 140, 250, 170);
|
||
s += window.PHYS.wire(340, 140, 340, 170);
|
||
s += window.PHYS.wire(295, 140, 340, 140);
|
||
s += window.PHYS.voltmeterSymbol(295, 155, 18);
|
||
/* ключ */
|
||
s += '<line x1="160" y1="200" x2="200" y2="200" stroke="#0f172a" stroke-width="2.5"/>';
|
||
s += '<circle cx="160" cy="200" r="3" fill="#0f172a"/>';
|
||
s += '<circle cx="200" cy="200" r="3" fill="#0f172a"/>';
|
||
if(closed){
|
||
s += '<line x1="160" y1="200" x2="200" y2="200" stroke="#dc2626" stroke-width="3"/>';
|
||
} else {
|
||
s += '<line x1="160" y1="200" x2="195" y2="185" stroke="#0f172a" stroke-width="2.5"/>';
|
||
}
|
||
s += '<text x="180" y="225" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" fill="#475569">ключ</text>';
|
||
svg.innerHTML = s;
|
||
document.getElementById('p21-amp').textContent = closed ? '0,5 А' : '0 А';
|
||
document.getElementById('p21-volt').textContent = closed ? '4,5 В' : '0 В';
|
||
}
|
||
document.getElementById('p21-key').addEventListener('click', ()=>{ closed = !closed; document.getElementById('p21-key').textContent = closed ? 'Разомкнуть' : 'Замкнуть ключ'; draw(); });
|
||
document.getElementById('p21-reset').addEventListener('click', ()=>{ closed = false; document.getElementById('p21-key').textContent = 'Замкнуть ключ'; draw(); });
|
||
draw();
|
||
}
|
||
|
||
function _initP21_quiz(){
|
||
const QS = [
|
||
{q:'Как включить <b>амперметр</b> для измерения тока через лампу?', opts:['параллельно лампе','последовательно с лампой','между + и − батареи напрямую','произвольно'], ans:1, why:'Амперметр включается в разрыв цепи (последовательно).'},
|
||
{q:'Как включить <b>вольтметр</b> для измерения напряжения на лампе?', opts:['параллельно лампе','последовательно с лампой','до батареи','после ключа'], ans:0, why:'Вольтметр меряет разность потенциалов — параллельно.'},
|
||
{q:'У амперметра сопротивление…', opts:['очень малое','очень большое','среднее','равно лампе'], ans:0, why:'Чтобы почти не влиять на ток.'},
|
||
{q:'У вольтметра сопротивление…', opts:['очень малое','очень большое','среднее','нулевое'], ans:1, why:'Чтобы не отбирать ток у цепи.'},
|
||
{q:'Если подключить амперметр <b>параллельно</b> лампе…', opts:['прибор покажет ток','прибор сгорит — короткое замыкание','напряжение увеличится','ничего не изменится'], ans:1, why:'Через малое R амперметра потечёт огромный ток.'},
|
||
{q:'Если подключить вольтметр <b>последовательно</b> с лампой…', opts:['ток будет нормальным','ток будет почти нулевой, лампа не загорится','прибор сгорит','лампа станет ярче'], ans:1, why:'Большое R вольтметра ограничит ток до неощутимого.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p21-quiz'); if(!wrap) return;
|
||
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
html += '</div><div class="feedback" id="p21-quiz-fb"></div>';
|
||
wrap.innerHTML = html;
|
||
document.getElementById('p21-quiz-r').textContent = (i+1);
|
||
document.getElementById('p21-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p21-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p21-quiz'); bumpProgress('p21', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p21-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p21-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP21_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'t', html:'амперметр последовательно с лампой'},
|
||
{id:'b', cat:'t', html:'вольтметр параллельно лампе'},
|
||
{id:'c', cat:'t', html:'амперметр имеет малое $R$'},
|
||
{id:'d', cat:'t', html:'вольтметр имеет большое $R$'},
|
||
{id:'e', cat:'f', html:'амперметр параллельно батарее'},
|
||
{id:'f', cat:'f', html:'вольтметр в разрыв цепи'},
|
||
{id:'g', cat:'f', html:'амперметр имеет большое $R$'},
|
||
{id:'h', cat:'f', html:'вольтметр меряет силу тока'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p21-dnd-pool', scopeSelector:'#sec-p21', cats:['t','f'], items, columnLayout:false });
|
||
document.getElementById('p21-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p21-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. A последовательно (мал. R), V параллельно (бол. R).'; addXp(15,'p21-dnd'); bumpProgress('p21', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p21-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p21-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP21_mcq(){
|
||
const QS = [
|
||
{q:'Что такое замкнутая цепь?', opts:['разрыв провода','круговое соединение элементов','один провод','лампа без батареи'], ans:1, why:'Цепь — петля, по которой может пройти ток.'},
|
||
{q:'Что произойдёт, если разомкнуть ключ?', opts:['ток усилится','ток исчезнет','напряжение упадёт','ток пойдёт по новому пути'], ans:1, why:'Цепь разорвана — тока нет.'},
|
||
{q:'Какой элемент схемы рисуется как круг с буквой A?', opts:['батарея','амперметр','вольтметр','резистор'], ans:1, why:'A — амперметр.'},
|
||
{q:'А с буквой V?', opts:['батарея','вольтметр','лампа','ключ'], ans:1, why:'V — вольтметр.'},
|
||
{q:'Все потребители в одной «петле» — это…', opts:['последовательное соединение','параллельное','смешанное','короткое замыкание'], ans:0, why:'В одной петле — последовательно.'},
|
||
{q:'Почему амперметр НЕ имеет большого $R$?', opts:['чтобы не сгореть','чтобы не уменьшать ток в цепи','чтобы было дёшево','чтобы измерять напряжение'], ans:1, why:'Большое R снизило бы ток, измерение было бы неточным.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p21-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p21-mcq-fb"></div><div class="actions"><button class="btn" id="p21-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p21-mcq-i').textContent = (i+1);
|
||
document.getElementById('p21-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p21-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p21-mcq'); bumpProgress('p21', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p21-mcq-ok').textContent = ok;
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p21-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p21-mcq-bonus'); bumpProgress('p21', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p21-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §22 — Закон Ома I = U/R ======== */
|
||
function build_p22(){
|
||
const box = document.getElementById('p22-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Связь $I$ и $U$', '§ 22.1',
|
||
'<p>Опыт: подключаем резистор к источнику и меняем напряжение. Что будет с током?</p>'
|
||
+'<p>Ток <b>пропорционален</b> напряжению: увеличили $U$ в 2 раза — $I$ тоже в 2 раза. Это и есть <b>закон Ома</b>:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$I = \\dfrac{U}{R}$$</p>'
|
||
+'<p>$R$ — <b>сопротивление</b> участка, измеряется в <b>Омах</b> (Ом). Закон открыт немецким физиком Георгом Симоном Омом в 1826 г.</p>'
|
||
);
|
||
h += makeCard('rule', 'Из закона Ома', '§ 22.2',
|
||
'<p>Закон можно «перевернуть» тремя способами:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$I = \\dfrac{U}{R}, \\quad U = IR, \\quad R = \\dfrac{U}{I}$$</p>'
|
||
+'<p>Эта связка — <b>основа всей электротехники</b>. Зная любые две величины — найдём третью.</p>'
|
||
+'<p><b>1 Ом</b> — это сопротивление участка, на котором при напряжении 1 В идёт ток 1 А.</p>'
|
||
);
|
||
h += makeCard('example', 'ВАХ — вольт-амперная характеристика', '§ 22.3',
|
||
'<p>Если на графике отложить $U$ по горизонтали, а $I$ по вертикали, получится <b>ВАХ</b>:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>для металла — прямая через 0;</li>'
|
||
+'<li>наклон прямой определяет $R$: круче — меньше $R$;</li>'
|
||
+'<li>для лампы с раскалённой нитью ВАХ слегка изогнута (нить нагревается, $R$ растёт).</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — ВАХ-плоттер */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">ВАХ-плоттер</div></div>'
|
||
+'<div class="wg-help">Меняй $R$ — увидь, как меняется наклон прямой $I(U)$. Чем меньше $R$, тем круче растёт ток.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$R$, Ом: <b id="p22-rv">10</b><input type="range" id="p22-r" min="2" max="50" step="1" value="10"></label>'
|
||
+'</div>'
|
||
+'<svg id="p22-sim" viewBox="0 0 460 240" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'</div>';
|
||
|
||
/* IV2 — калькулятор */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Калькулятор закона Ома</div></div>'
|
||
+'<div class="wg-help">Введи две величины — узнай третью.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$U$, В: <b id="p22-uv">12</b><input type="range" id="p22-u" min="1" max="220" step="1" value="12"></label>'
|
||
+'<label>$R$, Ом: <b id="p22-rv2">10</b><input type="range" id="p22-r2" min="1" max="100" step="1" value="10"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="margin-top:8px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$I = U/R$ = <b id="p22-icur">1,2</b> А</span>'
|
||
+'<span style="font-size:.84rem;color:var(--muted)">Для $U = 220$ В и $R = 100$ Ом ток будет 2,2 А — это <b id="p22-bulb">средняя лампа накаливания</b>.</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — викторина по графику */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Какой $R$ больше?</div></div>'
|
||
+'<div class="wg-help">По наклону ВАХ оцени сопротивление.</div>'
|
||
+'<div id="p22-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p22-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p22-quiz-r">1</b> / 5</span><span>Правильно: <b id="p22-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 задач</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p22-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p22-task-i">1</b> / 6</span><span>Правильно: <b id="p22-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — Ohm's Law (Phase 2.2) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Закон Ома: $I = U/R$</div></div>'
|
||
+'<div class="wg-help">Двигай напряжение $U$ и сопротивление $R$. Ток $I = U/R$ обновляется в реальном времени. Лампочка светится ярче с ростом тока.</div>'
|
||
+'<div class="p8-sandbox" id="p22-iv6-sandbox" style="height:220px"></div>'
|
||
+'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px">'
|
||
+'<div class="p8-scrubber"><span class="p8-scrubber-label">U</span><input type="range" id="p22-iv6-u" min="0.5" max="12" step="0.1" value="6"><span class="p8-scrubber-value"><span id="p22-iv6-u-val">6.0</span><span class="p8-unit">В</span></span></div>'
|
||
+'<div class="p8-scrubber"><span class="p8-scrubber-label">R</span><input type="range" id="p22-iv6-r" min="1" max="100" step="1" value="12"><span class="p8-scrubber-value"><span id="p22-iv6-r-val">12</span><span class="p8-unit">Ом</span></span></div>'
|
||
+'</div>'
|
||
+'<div style="margin-top:8px"><div class="p8-readout"><span class="p8-readout-label">I = U/R</span><span class="p8-readout-value" id="p22-iv6-i">0.50</span><span class="p8-readout-unit">А</span></div></div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p22') + readButton('p22');
|
||
renderMath(box);
|
||
wireReadBtn('p22');
|
||
_initP22_iv6();
|
||
|
||
_initP22_vah();
|
||
_initP22_calc();
|
||
_initP22_quiz();
|
||
_initP22_tasks();
|
||
}
|
||
|
||
function _initP22_vah(){
|
||
const svg = document.getElementById('p22-sim'); if(!svg) return;
|
||
function draw(){
|
||
const R = +document.getElementById('p22-r').value;
|
||
document.getElementById('p22-rv').textContent = R;
|
||
const W = 460, H = 240, pad = 38;
|
||
const Umax = 12, Imax = 2;
|
||
const toX = u => pad + (W-2*pad) * u / Umax;
|
||
const toY = i => H - pad - (H-2*pad) * i / Imax;
|
||
let s = '';
|
||
/* оси */
|
||
s += '<line x1="'+pad+'" y1="'+(H-pad)+'" x2="'+(W-pad)+'" y2="'+(H-pad)+'" stroke="#0f172a" stroke-width="1.5"/>';
|
||
s += '<line x1="'+pad+'" y1="'+pad+'" x2="'+pad+'" y2="'+(H-pad)+'" stroke="#0f172a" stroke-width="1.5"/>';
|
||
/* сетка */
|
||
for(let u = 2; u <= 10; u+=2){
|
||
s += '<line x1="'+toX(u)+'" y1="'+pad+'" x2="'+toX(u)+'" y2="'+(H-pad)+'" stroke="#e5e7eb" stroke-width="1"/>';
|
||
s += '<text x="'+toX(u)+'" y="'+(H-pad+14)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="10" fill="#475569">'+u+'</text>';
|
||
}
|
||
for(let i = 0.5; i <= 1.5; i+=0.5){
|
||
s += '<line x1="'+pad+'" y1="'+toY(i)+'" x2="'+(W-pad)+'" y2="'+toY(i)+'" stroke="#e5e7eb" stroke-width="1"/>';
|
||
s += '<text x="'+(pad-6)+'" y="'+(toY(i)+3)+'" text-anchor="end" font-family="JetBrains Mono,monospace" font-size="10" fill="#475569">'+i+'</text>';
|
||
}
|
||
/* подписи осей */
|
||
s += '<text x="'+(W-pad+4)+'" y="'+(H-pad+4)+'" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">U, В</text>';
|
||
s += '<text x="'+(pad-4)+'" y="'+(pad-6)+'" text-anchor="end" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">I, А</text>';
|
||
/* прямая I = U/R */
|
||
const x0 = toX(0), y0 = toY(0);
|
||
const uMaxVisible = Math.min(Umax, Imax * R);
|
||
const x1 = toX(uMaxVisible);
|
||
const y1 = toY(uMaxVisible / R);
|
||
s += '<line x1="'+x0+'" y1="'+y0+'" x2="'+x1+'" y2="'+y1+'" stroke="#d97706" stroke-width="3"/>';
|
||
/* подпись наклона */
|
||
s += '<text x="'+(W/2)+'" y="'+(pad+18)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#d97706">I = U / '+R+' Ом</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p22-r').addEventListener('input', draw);
|
||
draw();
|
||
}
|
||
|
||
function _initP22_calc(){
|
||
function update(){
|
||
const U = +document.getElementById('p22-u').value;
|
||
const R = +document.getElementById('p22-r2').value;
|
||
document.getElementById('p22-uv').textContent = U;
|
||
document.getElementById('p22-rv2').textContent = R;
|
||
const I = U/R;
|
||
document.getElementById('p22-icur').textContent = I.toFixed(2);
|
||
let analogy = 'мало';
|
||
if(I > 5) analogy = 'мощный нагреватель';
|
||
else if(I > 1) analogy = 'средняя лампа накаливания';
|
||
else if(I > 0.2) analogy = 'светодиодная лампа';
|
||
else analogy = 'светодиод';
|
||
document.getElementById('p22-bulb').textContent = analogy;
|
||
}
|
||
document.getElementById('p22-u').addEventListener('input', update);
|
||
document.getElementById('p22-r2').addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
function _initP22_quiz(){
|
||
const QS = [
|
||
{q:'У какого резистора $R$ больше: ВАХ круче или ВАХ положе?', opts:['круче','положе','одинаково','зависит от U'], ans:1, why:'$R$ = $U/I$, при том же $U$ положая прямая даёт меньший $I$ → больше $R$.'},
|
||
{q:'Если $U$ постоянно, а $R$ удвоить, что станет с $I$?', opts:['удвоится','уменьшится в 2 раза','не изменится','исчезнет'], ans:1, why:'$I = U/R$, $R$ ↑ → $I$ ↓.'},
|
||
{q:'Если $R$ постоянно, а $U$ утроить, что с $I$?', opts:['удвоится','утроится','уменьшится в 3 раза','не изменится'], ans:1, why:'Прямая пропорция.'},
|
||
{q:'При $U = 6$ В через резистор течёт $I = 0{,}5$ А. Чему равно $R$?', opts:['3 Ом','12 Ом','6 Ом','0,5 Ом'], ans:1, why:'$R = U/I = 6/0{,}5 = 12$ Ом.'},
|
||
{q:'Закон Ома справедлив для…', opts:['только газов','любых веществ','металлических проводников','только сверхпроводников'], ans:2, why:'Для металлов точно, для других — с оговорками.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p22-quiz'); if(!wrap) return;
|
||
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
html += '</div><div class="feedback" id="p22-quiz-fb"></div>';
|
||
wrap.innerHTML = html;
|
||
document.getElementById('p22-quiz-r').textContent = (i+1);
|
||
document.getElementById('p22-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p22-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p22-quiz'); bumpProgress('p22', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p22-quiz-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
});
|
||
});
|
||
renderMath(wrap);
|
||
}
|
||
document.getElementById('p22-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP22_tasks(){
|
||
const TASKS = [
|
||
{q:'$U = 12$ В, $R = 4$ Ом. Найди $I$ (А).', ans:3, tol:0.05, why:'$I = 12/4 = 3$ А.'},
|
||
{q:'$I = 0{,}5$ А, $R = 220$ Ом. Найди $U$ (В).', ans:110, tol:1, why:'$U = IR = 0{,}5 \\cdot 220 = 110$ В.'},
|
||
{q:'$U = 220$ В, $I = 2$ А. Найди $R$ (Ом).', ans:110, tol:1, why:'$R = 220/2 = 110$ Ом.'},
|
||
{q:'Лампа $R = 240$ Ом подключена к 220 В. Какой ток (А, до сотых)?', ans:0.92, tol:0.02, why:'$I = 220/240 \\approx 0{,}917$ А.'},
|
||
{q:'$U$ возросло с 5 до 15 В на том же $R$. Во сколько раз возрос ток?', ans:3, tol:0.05, why:'$I$ пропорционально $U$.'},
|
||
{q:'При $U = 1{,}5$ В через светодиод течёт 20 мА. Найди $R$ (Ом).', ans:75, tol:1, why:'$R = 1{,}5/0{,}02 = 75$ Ом.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p22-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p22-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p22-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p22-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p22-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p22-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p22-task-fb"></div>';
|
||
document.getElementById('p22-task-i').textContent = (i+1);
|
||
document.getElementById('p22-task-ok').textContent = ok;
|
||
document.getElementById('p22-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p22-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p22-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p22-task'); bumpProgress('p22', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p22-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p22-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p22-task-bonus'); bumpProgress('p22', 15); }, 600); }
|
||
});
|
||
document.getElementById('p22-task-hint').addEventListener('click', ()=>{ document.getElementById('p22-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p22-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 3 · WAVE 3 — §23, §24, §25
|
||
====================================================================== */
|
||
|
||
const MAT_RHO = [
|
||
{name:'серебро', rho:0.016},
|
||
{name:'медь', rho:0.017},
|
||
{name:'алюминий',rho:0.028},
|
||
{name:'железо', rho:0.10},
|
||
{name:'нихром', rho:1.1},
|
||
{name:'константан', rho:0.5}
|
||
];
|
||
|
||
/* ======== §23 — R = ρl/S ======== */
|
||
function build_p23(){
|
||
const box = document.getElementById('p23-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Формула сопротивления', '§ 23.1',
|
||
'<p>Сопротивление проводника зависит от трёх параметров:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$R = \\dfrac{\\rho \\, l}{S}$$</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>$\\rho$ — <b>удельное сопротивление</b>, Ом·мм²/м. Свойство материала.</li>'
|
||
+'<li>$l$ — длина проводника, м.</li>'
|
||
+'<li>$S$ — площадь поперечного сечения, мм².</li>'
|
||
+'</ul>'
|
||
+'<p>Чем длиннее — тем больше $R$. Чем толще (больше $S$) — тем меньше $R$. Чем «хуже» материал — тем больше $\\rho$.</p>'
|
||
);
|
||
h += makeCard('rule', 'Таблица $\\rho$', '§ 23.2',
|
||
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><thead><tr style="background:rgba(15,23,42,.04)"><th style="padding:6px;text-align:left">Материал</th><th style="padding:6px;text-align:right">$\\rho$, $\\dfrac{\\text{Ом}\\cdot\\text{мм}^2}{\\text{м}}$</th></tr></thead><tbody>'
|
||
+ MAT_RHO.map(m=>'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">'+m.name+'</td><td style="padding:6px;text-align:right;border-bottom:1px dashed var(--border)"><code>'+m.rho+'</code></td></tr>').join('')
|
||
+'</tbody></table>'
|
||
+'<p style="margin-top:8px">Для проводов берут медь или алюминий (малое $\\rho$). Для нагревательных спиралей — нихром (большое $\\rho$ → много тепла при том же токе).</p>'
|
||
);
|
||
h += makeCard('example', 'Где это применяется', '§ 23.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Электропровода — медные, толстые → малое $R$ → малые потери.</li>'
|
||
+'<li>Нагревательная спираль чайника — длинная и тонкая из нихрома.</li>'
|
||
+'<li>Линии электропередачи — толстые алюминиевые провода (медь была бы дороже).</li>'
|
||
+'<li>Удлинители — чем длиннее, тем больше $R$ → больше потерь.</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — калькулятор R = ρl/S */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Калькулятор $R = \\rho l / S$</div></div>'
|
||
+'<div class="wg-help">Выбери материал, длину и сечение — увидь $R$.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Материал: <select id="p23-mat" class="tinp" style="width:auto;padding:6px 10px;font-size:.92rem">'
|
||
+ MAT_RHO.map(m=>'<option value="'+m.rho+'">'+m.name+' ($\\rho='+m.rho+'$)</option>').join('')
|
||
+'</select></label>'
|
||
+'<label>$l$, м: <b id="p23-lv">10</b><input type="range" id="p23-l" min="0.1" max="100" step="0.5" value="10"></label>'
|
||
+'<label>$S$, мм²: <b id="p23-sv">1.0</b><input type="range" id="p23-s" min="0.1" max="10" step="0.1" value="1"></label>'
|
||
+'</div>'
|
||
+'<svg id="p23-sim" viewBox="0 0 460 140" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$R = \\rho l / S$ = <b id="p23-rv2">0.17</b> Ом</span>'
|
||
+'<span style="font-size:.84rem;color:var(--muted)">При $U = 12$ В: $I = U/R = $ <b id="p23-i12">71</b> А.</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — «больше/меньше R?» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">У какого провода $R$ больше?</div></div>'
|
||
+'<div class="wg-help">Сравни два варианта.</div>'
|
||
+'<div id="p23-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p23-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p23-quiz-r">1</b> / 6</span><span>Правильно: <b id="p23-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «как изменится R» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Как изменится $R$?</div></div>'
|
||
+'<div class="wg-help">При изменении параметра.</div>'
|
||
+'<div id="p23-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>$R$ растёт</h5><div class="drop-items" data-cat="up"></div></div>'
|
||
+'<div class="drop-box"><h5>$R$ падает</h5><div class="drop-items" data-cat="dn"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p23-dnd-check">Проверить</button><button class="btn" id="p23-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p23-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 задач</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p23-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p23-task-i">1</b> / 5</span><span>Правильно: <b id="p23-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.23) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §23</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.23 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p23') + readButton('p23');
|
||
renderMath(box);
|
||
wireReadBtn('p23');
|
||
|
||
_initP23_calc();
|
||
_initP23_quiz();
|
||
_initP23_dnd();
|
||
_initP23_tasks();
|
||
}
|
||
|
||
function _initP23_calc(){
|
||
const svg = document.getElementById('p23-sim'); if(!svg) return;
|
||
function update(){
|
||
const rho = +document.getElementById('p23-mat').value;
|
||
const l = +document.getElementById('p23-l').value;
|
||
const S = +document.getElementById('p23-s').value;
|
||
document.getElementById('p23-lv').textContent = l.toFixed(1);
|
||
document.getElementById('p23-sv').textContent = S.toFixed(1);
|
||
const R = rho * l / S;
|
||
document.getElementById('p23-rv2').textContent = R.toFixed(2);
|
||
document.getElementById('p23-i12').textContent = (12/R).toFixed(1);
|
||
/* SVG: провод */
|
||
let s = '';
|
||
const lenPx = 60 + Math.min(330, l*3);
|
||
const wPx = 6 + Math.min(40, S*4);
|
||
const cy = 70;
|
||
const xS = 30;
|
||
s += '<rect x="'+xS+'" y="'+(cy-wPx/2)+'" width="'+lenPx+'" height="'+wPx+'" fill="#cbd5e1" stroke="#0f172a" stroke-width="1.6" rx="3"/>';
|
||
/* подписи */
|
||
s += '<text x="'+(xS+lenPx/2)+'" y="'+(cy+wPx/2+18)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="11" fill="#475569">l = '+l.toFixed(1)+' м</text>';
|
||
s += '<text x="'+(xS+lenPx+12)+'" y="'+(cy+4)+'" font-family="JetBrains Mono,monospace" font-size="11" fill="#475569">S = '+S.toFixed(1)+' мм²</text>';
|
||
/* формула */
|
||
s += '<text x="'+(xS)+'" y="120" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#0f172a">R = '+rho+' · '+l.toFixed(1)+' / '+S.toFixed(1)+' = '+R.toFixed(2)+' Ом</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p23-mat').addEventListener('change', update);
|
||
document.getElementById('p23-l').addEventListener('input', update);
|
||
document.getElementById('p23-s').addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
function _initP23_quiz(){
|
||
const QS = [
|
||
{A:'медный провод 10 м', B:'медный провод 20 м', ans:'B', why:'Длиннее — больше $R$.'},
|
||
{A:'медный провод $S = 1$ мм²', B:'медный провод $S = 2$ мм²', ans:'A', why:'Толще — меньше $R$.'},
|
||
{A:'нихромовый провод 1 м', B:'медный провод 1 м', ans:'A', why:'Нихром в 65 раз хуже меди по $\\rho$.'},
|
||
{A:'железный провод', B:'медный провод (тот же)', ans:'A', why:'Железо хуже меди.'},
|
||
{A:'алюминиевый провод 50 м', B:'медный провод 50 м', ans:'A', why:'У алюминия $\\rho$ больше.'},
|
||
{A:'тонкий нихром', B:'толстая медь', ans:'A', why:'Тонкий и нихром — двойное «увеличение R».'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p23-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:8px">'
|
||
+'<button class="btn" data-pick="A" style="padding:14px;text-align:left"><b>A.</b> '+q.A+'</button>'
|
||
+'<button class="btn" data-pick="B" style="padding:14px;text-align:left"><b>B.</b> '+q.B+'</button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p23-quiz-fb"></div>';
|
||
document.getElementById('p23-quiz-r').textContent = (i+1);
|
||
document.getElementById('p23-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p23-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p23-quiz'); bumpProgress('p23', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p23-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p23-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP23_dnd(){
|
||
const items = [
|
||
{id:'lup', cat:'up', html:'увеличили длину $l$'},
|
||
{id:'sdn', cat:'up', html:'уменьшили сечение $S$'},
|
||
{id:'mb', cat:'up', html:'заменили медь на нихром'},
|
||
{id:'cd', cat:'up', html:'заменили серебро на железо'},
|
||
{id:'ldn', cat:'dn', html:'укоротили провод'},
|
||
{id:'sup', cat:'dn', html:'утолстили провод'},
|
||
{id:'mw', cat:'dn', html:'заменили нихром на медь'},
|
||
{id:'cs', cat:'dn', html:'заменили железо на серебро'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p23-dnd-pool', scopeSelector:'#sec-p23', cats:['up','dn'], items, columnLayout:false });
|
||
document.getElementById('p23-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p23-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. $R$ пропорционально $\\rho l$ и обратно $S$.'; addXp(15,'p23-dnd'); bumpProgress('p23', 20); renderMath(fb); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p23-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p23-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP23_tasks(){
|
||
const TASKS = [
|
||
{q:'Медь, $l = 100$ м, $S = 1$ мм². Найди $R$ (Ом).', ans:1.7, tol:0.05, why:'$R = 0{,}017 \\cdot 100 / 1 = 1{,}7$ Ом.'},
|
||
{q:'Нихромовая спираль, $l = 5$ м, $S = 0{,}5$ мм². Найди $R$ (Ом).', ans:11, tol:0.3, why:'$R = 1{,}1 \\cdot 5 / 0{,}5 = 11$ Ом.'},
|
||
{q:'$R = 4$ Ом, $\\rho = 0{,}4$, $l = 2$ м. Найди $S$ (мм²).', ans:0.2, tol:0.02, why:'$S = \\rho l / R = 0{,}4 \\cdot 2 / 4 = 0{,}2$ мм².'},
|
||
{q:'Два медных провода: один длиннее в 3 раза, тоньше в 2 раза. Во сколько раз $R$ больше?', ans:6, tol:0.1, why:'$R$ ∝ $l/S$: $3 \\cdot 2 = 6$ раз.'},
|
||
{q:'Алюминиевый провод, $l = 20$ м, $S = 4$ мм². Найди $R$ (Ом).', ans:0.14, tol:0.01, why:'$R = 0{,}028 \\cdot 20 / 4 = 0{,}14$ Ом.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p23-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p23-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p23-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p23-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p23-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p23-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p23-task-fb"></div>';
|
||
document.getElementById('p23-task-i').textContent = (i+1);
|
||
document.getElementById('p23-task-ok').textContent = ok;
|
||
document.getElementById('p23-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p23-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p23-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p23-task'); bumpProgress('p23', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p23-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p23-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p23-task-bonus'); bumpProgress('p23', 15); }, 600); }
|
||
});
|
||
document.getElementById('p23-task-hint').addEventListener('click', ()=>{ document.getElementById('p23-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p23-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §24 — Последовательное соединение. Реостат ======== */
|
||
function build_p24(){
|
||
const box = document.getElementById('p24-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Правила последовательного соединения', '§ 24.1',
|
||
'<p>Если резисторы соединены <b>один за другим</b> (в одну «петлю»), это <b>последовательное</b> соединение.</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Ток одинаков: $I = I_1 = I_2$ (одна и та же река через все «пороги»).</li>'
|
||
+'<li>Напряжения складываются: $U = U_1 + U_2$.</li>'
|
||
+'<li>Сопротивления складываются: $R = R_1 + R_2$.</li>'
|
||
+'</ul>'
|
||
+'<p>Если один из резисторов вышел из строя — <b>вся цепь обесточена</b>.</p>'
|
||
);
|
||
h += makeCard('rule', 'Реостат', '§ 24.2',
|
||
'<p><b>Реостат</b> — переменный резистор. Состоит из проволочного резистивного элемента и подвижного контакта (движка).</p>'
|
||
+'<p>Сдвигая движок, мы изменяем длину $l$ включённой части провода. Так как $R = \\rho l/S$, меняется и сопротивление.</p>'
|
||
+'<p>Реостат используют для:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>регулировки силы тока (например, яркости лампы);</li>'
|
||
+'<li>защиты от перегрузки (последовательно с прибором);</li>'
|
||
+'<li>«старой» школы — регуляторов громкости в радиоприёмниках.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('example', 'Гирлянда — последовательная цепь', '§ 24.3',
|
||
'<p>В старых ёлочных гирляндах все лампочки соединены последовательно. Каждой достаётся $220/N$ Вольт, где $N$ — число лампочек.</p>'
|
||
+'<p>Минус: если перегорит одна — погаснут все! Поэтому современные гирлянды чаще делают по секциям с шунтирующими элементами.</p>'
|
||
);
|
||
|
||
/* IV1 — реостат-симулятор */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Реостат регулирует яркость</div></div>'
|
||
+'<div class="wg-help">Двигай движок реостата — увидь, как меняется ток и яркость лампы. Это последовательная цепь.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Положение движка (доля включённой проволоки): <b id="p24-pv">50%</b><input type="range" id="p24-p" min="0" max="100" step="5" value="50"></label>'
|
||
+'</div>'
|
||
+'<svg id="p24-sim" viewBox="0 0 460 220" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$R_{реост}$ = <b id="p24-rr">10</b> Ом, $R_{лампы} = 12$ Ом, $R_{общ}$ = <b id="p24-rt">22</b> Ом</span>'
|
||
+'<span>$I = U/R$ при $U = 12$ В: <b id="p24-it">0.55</b> А</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — калькулятор */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Калькулятор последовательной цепи</div></div>'
|
||
+'<div class="wg-help">Подбирай $R_1$, $R_2$ и $U$ — найди ток и напряжения на каждом.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$U$, В: <b id="p24-uv">12</b><input type="range" id="p24-u" min="1" max="100" step="1" value="12"></label>'
|
||
+'<label>$R_1$, Ом: <b id="p24-r1v">4</b><input type="range" id="p24-r1" min="1" max="50" step="1" value="4"></label>'
|
||
+'<label>$R_2$, Ом: <b id="p24-r2v">8</b><input type="range" id="p24-r2" min="1" max="50" step="1" value="8"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="margin-top:8px;flex-direction:column;align-items:flex-start;gap:3px">'
|
||
+'<span>$R$ = $R_1+R_2$ = <b id="p24-rs">12</b> Ом</span>'
|
||
+'<span>$I = U/R$ = <b id="p24-is">1</b> А</span>'
|
||
+'<span>$U_1 = I R_1$ = <b id="p24-u1">4</b> В</span>'
|
||
+'<span>$U_2 = I R_2$ = <b id="p24-u2">8</b> В</span>'
|
||
+'<span style="font-size:.84rem;color:var(--muted)">Проверка: $U_1+U_2$ = <b id="p24-check">12</b> В</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «верно/неверно» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Правила послед. соединения</div></div>'
|
||
+'<div id="p24-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Верно</h5><div class="drop-items" data-cat="t"></div></div>'
|
||
+'<div class="drop-box"><h5>Неверно</h5><div class="drop-items" data-cat="f"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p24-dnd-check">Проверить</button><button class="btn" id="p24-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p24-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 задач</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p24-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p24-task-i">1</b> / 5</span><span>Правильно: <b id="p24-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.24) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §24</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.24 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p24') + readButton('p24');
|
||
renderMath(box);
|
||
wireReadBtn('p24');
|
||
|
||
_initP24_rheostat();
|
||
_initP24_calc();
|
||
_initP24_dnd();
|
||
_initP24_tasks();
|
||
}
|
||
|
||
function _initP24_rheostat(){
|
||
const svg = document.getElementById('p24-sim'); if(!svg) return;
|
||
function draw(){
|
||
const p = +document.getElementById('p24-p').value;
|
||
document.getElementById('p24-pv').textContent = p+'%';
|
||
const Rrh = 20 * p / 100; /* 0..20 Ом */
|
||
const Rlamp = 12;
|
||
const Rtot = Rrh + Rlamp;
|
||
const I = 12 / Rtot;
|
||
document.getElementById('p24-rr').textContent = Rrh.toFixed(0);
|
||
document.getElementById('p24-rt').textContent = Rtot.toFixed(0);
|
||
document.getElementById('p24-it').textContent = I.toFixed(2);
|
||
/* SVG */
|
||
let s = '';
|
||
/* батарея */
|
||
s += window.PHYS.batteryEMF(60, 170, '12 В', 'h');
|
||
/* провод снизу */
|
||
s += window.PHYS.wire(60, 150, 60, 70);
|
||
s += window.PHYS.wire(60, 70, 130, 70);
|
||
/* реостат — длинная зигзаг полоска */
|
||
s += '<rect x="130" y="60" width="180" height="20" fill="#fde68a" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
|
||
/* зона до движка (включена) — затемнить */
|
||
s += '<rect x="130" y="60" width="'+(p*1.8)+'" height="20" fill="#d97706" opacity="0.4"/>';
|
||
/* движок */
|
||
s += '<line x1="'+(130+p*1.8)+'" y1="50" x2="'+(130+p*1.8)+'" y2="80" stroke="#0f172a" stroke-width="3"/>';
|
||
s += '<polygon points="'+(130+p*1.8-6)+',50 '+(130+p*1.8+6)+',50 '+(130+p*1.8)+',58" fill="#0f172a"/>';
|
||
s += '<text x="220" y="100" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" fill="#475569">реостат '+Rrh.toFixed(0)+' Ом</text>';
|
||
/* провод к лампе */
|
||
s += window.PHYS.wire(310, 70, 360, 70);
|
||
/* лампа */
|
||
s += window.PHYS.lightbulbSymbol(380, 70, 18);
|
||
/* яркость зависит от тока */
|
||
const glow = Math.min(1, I / 1.2);
|
||
s += '<circle cx="380" cy="70" r="'+(24+I*12).toFixed(0)+'" fill="#fde047" opacity="'+(glow*0.5).toFixed(2)+'"/>';
|
||
s += '<circle cx="380" cy="70" r="'+(36+I*18).toFixed(0)+'" fill="#fbbf24" opacity="'+(glow*0.18).toFixed(2)+'"/>';
|
||
/* провод вниз и обратно */
|
||
s += window.PHYS.wire(380, 90, 380, 170);
|
||
s += window.PHYS.wire(380, 170, 100, 170);
|
||
/* I-метка */
|
||
s += '<text x="220" y="195" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#d97706">I = '+I.toFixed(2)+' А</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p24-p').addEventListener('input', draw);
|
||
draw();
|
||
}
|
||
|
||
function _initP24_calc(){
|
||
function update(){
|
||
const U = +document.getElementById('p24-u').value;
|
||
const R1 = +document.getElementById('p24-r1').value;
|
||
const R2 = +document.getElementById('p24-r2').value;
|
||
document.getElementById('p24-uv').textContent = U;
|
||
document.getElementById('p24-r1v').textContent = R1;
|
||
document.getElementById('p24-r2v').textContent = R2;
|
||
const R = R1+R2;
|
||
const I = U/R;
|
||
const U1 = I*R1;
|
||
const U2 = I*R2;
|
||
document.getElementById('p24-rs').textContent = R;
|
||
document.getElementById('p24-is').textContent = I.toFixed(2);
|
||
document.getElementById('p24-u1').textContent = U1.toFixed(2);
|
||
document.getElementById('p24-u2').textContent = U2.toFixed(2);
|
||
document.getElementById('p24-check').textContent = (U1+U2).toFixed(2);
|
||
}
|
||
['p24-u','p24-r1','p24-r2'].forEach(id => document.getElementById(id).addEventListener('input', update));
|
||
update();
|
||
}
|
||
|
||
function _initP24_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'t', html:'$I = I_1 = I_2$'},
|
||
{id:'b', cat:'t', html:'$U = U_1 + U_2$'},
|
||
{id:'c', cat:'t', html:'$R = R_1 + R_2$'},
|
||
{id:'d', cat:'t', html:'обрыв одного $\\to$ нет тока во всей цепи'},
|
||
{id:'e', cat:'f', html:'$U = U_1 = U_2$'},
|
||
{id:'f', cat:'f', html:'$I = I_1 + I_2$'},
|
||
{id:'g', cat:'f', html:'$1/R = 1/R_1 + 1/R_2$'},
|
||
{id:'h', cat:'f', html:'обрыв одного $\\to$ ток продолжает идти'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p24-dnd-pool', scopeSelector:'#sec-p24', cats:['t','f'], items, columnLayout:false });
|
||
document.getElementById('p24-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p24-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Послед.: одно $I$, складываются $U$ и $R$.'; addXp(15,'p24-dnd'); bumpProgress('p24', 20); renderMath(fb); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'. Эти правила — для параллельного соединения.'; renderMath(fb); }
|
||
});
|
||
document.getElementById('p24-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p24-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP24_tasks(){
|
||
const TASKS = [
|
||
{q:'$R_1 = 4$, $R_2 = 6$ Ом последовательно, $U = 20$ В. Найди $I$ (А).', ans:2, tol:0.05, why:'$R = 10$, $I = 20/10 = 2$ А.'},
|
||
{q:'$R_1 = 3$, $R_2 = 5$ Ом, $I = 2$ А. Найди $U_2$ (В).', ans:10, tol:0.5, why:'$U_2 = I R_2 = 2 \\cdot 5 = 10$ В.'},
|
||
{q:'Три одинаковых лампы $R = 50$ Ом каждая, последовательно, $U = 90$ В. Найди $I$ (А).', ans:0.6, tol:0.02, why:'$R = 150$, $I = 90/150 = 0{,}6$ А.'},
|
||
{q:'$R_1 = 5$, $R_2 = ?$ последовательно. $U = 30$ В, $I = 2$ А. Найди $R_2$ (Ом).', ans:10, tol:0.5, why:'$R = 30/2 = 15$, $R_2 = 15 - 5 = 10$ Ом.'},
|
||
{q:'Реостат $R = 0..50$ Ом + лампа $R_л = 10$ Ом, $U = 12$ В. При каком положении реостата (Ом) ток будет $0{,}2$ А?', ans:50, tol:1, why:'$R_{общ} = U/I = 60$, $R_{реост} = 60 - 10 = 50$ Ом.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p24-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p24-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p24-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p24-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p24-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p24-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p24-task-fb"></div>';
|
||
document.getElementById('p24-task-i').textContent = (i+1);
|
||
document.getElementById('p24-task-ok').textContent = ok;
|
||
document.getElementById('p24-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p24-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p24-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p24-task'); bumpProgress('p24', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p24-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p24-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p24-task-bonus'); bumpProgress('p24', 15); }, 600); }
|
||
});
|
||
document.getElementById('p24-task-hint').addEventListener('click', ()=>{ document.getElementById('p24-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p24-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §25 — Параллельное соединение ======== */
|
||
function build_p25(){
|
||
const box = document.getElementById('p25-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Правила параллельного соединения', '§ 25.1',
|
||
'<p>Если резисторы соединены <b>«бок о бок»</b>, между двумя одинаковыми узлами — это <b>параллельное</b> соединение.</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Напряжение одинаковое: $U = U_1 = U_2$ (один и тот же «перепад высоты» на всех ветках).</li>'
|
||
+'<li>Токи складываются: $I = I_1 + I_2$.</li>'
|
||
+'<li>Сопротивления через обратные величины: $\\dfrac{1}{R} = \\dfrac{1}{R_1} + \\dfrac{1}{R_2}$.</li>'
|
||
+'</ul>'
|
||
+'<p>Поломка одного резистора <b>не отключает</b> остальные.</p>'
|
||
);
|
||
h += makeCard('rule', 'Полезные формулы', '§ 25.2',
|
||
'<p>Для двух резисторов:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$R = \\dfrac{R_1 R_2}{R_1 + R_2}$$</p>'
|
||
+'<p>Для $N$ <b>одинаковых</b> резисторов по $R$:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$R_{общ} = \\dfrac{R}{N}$$</p>'
|
||
+'<p>Общее $R$ <b>меньше</b> любого из частных. Это потому, что параллельные «ветви» дают много путей току.</p>'
|
||
);
|
||
h += makeCard('example', 'Где встречается', '§ 25.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>В розетках дома: все приборы (свет, ТВ, чайник) подключены параллельно. Поэтому каждый получает 220 В.</li>'
|
||
+'<li>Поломка лампы не выключает остальные.</li>'
|
||
+'<li>В машине фары, магнитола, освещение салона — все параллельно через аккумулятор.</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — конструктор параллельной цепи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Параллельная цепь — 2 ветви</div></div>'
|
||
+'<div class="wg-help">Меняй $R_1$ и $R_2$ — увидь токи в каждой ветви и общий $R$.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$R_1$, Ом: <b id="p25-r1v">6</b><input type="range" id="p25-r1" min="1" max="40" step="1" value="6"></label>'
|
||
+'<label>$R_2$, Ом: <b id="p25-r2v">12</b><input type="range" id="p25-r2" min="1" max="40" step="1" value="12"></label>'
|
||
+'</div>'
|
||
+'<svg id="p25-sim" viewBox="0 0 460 220" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:3px">'
|
||
+'<span>$R_{общ} = R_1 R_2 / (R_1+R_2)$ = <b id="p25-rt">4</b> Ом</span>'
|
||
+'<span>При $U = 12$ В: $I_1 = U/R_1 = $ <b id="p25-i1">2</b> А</span>'
|
||
+'<span>$I_2 = U/R_2 = $ <b id="p25-i2">1</b> А</span>'
|
||
+'<span>Общий ток $I = I_1 + I_2$ = <b id="p25-it2">3</b> А</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «послед. или паралл.» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Какое соединение?</div></div>'
|
||
+'<div class="wg-help">По описанию определи тип соединения.</div>'
|
||
+'<div id="p25-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p25-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p25-quiz-r">1</b> / 6</span><span>Правильно: <b id="p25-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD формулы */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">К какому соединению относится?</div></div>'
|
||
+'<div class="wg-help">Распредели формулы.</div>'
|
||
+'<div id="p25-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Последовательно</h5><div class="drop-items" data-cat="ser"></div></div>'
|
||
+'<div class="drop-box"><h5>Параллельно</h5><div class="drop-items" data-cat="par"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p25-dnd-check">Проверить</button><button class="btn" id="p25-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p25-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 задач</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p25-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p25-task-i">1</b> / 6</span><span>Правильно: <b id="p25-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — Parallel resistors (Phase 2.2) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Параллельные резисторы: $1/R = 1/R_1 + 1/R_2$</div></div>'
|
||
+'<div class="wg-help">Двигай $R_1, R_2$ — наблюдай как ток делится между ветвями ($I = I_1 + I_2$) и какое получается общее $R$.</div>'
|
||
+'<div class="p8-sandbox" id="p25-iv6-sandbox" style="height:240px"></div>'
|
||
+'<div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:8px">'
|
||
+'<div class="p8-scrubber"><span class="p8-scrubber-label">R₁</span><input type="range" id="p25-iv6-r1" min="1" max="100" step="1" value="20"><span class="p8-scrubber-value"><span id="p25-iv6-r1-val">20</span><span class="p8-unit">Ом</span></span></div>'
|
||
+'<div class="p8-scrubber"><span class="p8-scrubber-label">R₂</span><input type="range" id="p25-iv6-r2" min="1" max="100" step="1" value="30"><span class="p8-scrubber-value"><span id="p25-iv6-r2-val">30</span><span class="p8-unit">Ом</span></span></div>'
|
||
+'</div>'
|
||
+'<div style="margin-top:8px;display:flex;gap:10px;flex-wrap:wrap">'
|
||
+'<div class="p8-readout"><span class="p8-readout-label">R_общ</span><span class="p8-readout-value" id="p25-iv6-r">12</span><span class="p8-readout-unit">Ом</span></div>'
|
||
+'<div class="p8-readout"><span class="p8-readout-label">I₁</span><span class="p8-readout-value" id="p25-iv6-i1">0.6</span><span class="p8-readout-unit">А</span></div>'
|
||
+'<div class="p8-readout"><span class="p8-readout-label">I₂</span><span class="p8-readout-value" id="p25-iv6-i2">0.4</span><span class="p8-readout-unit">А</span></div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p25') + readButton('p25');
|
||
renderMath(box);
|
||
wireReadBtn('p25');
|
||
_initP25_iv6();
|
||
|
||
_initP25_calc();
|
||
_initP25_quiz();
|
||
_initP25_dnd();
|
||
_initP25_tasks();
|
||
}
|
||
|
||
function _initP25_calc(){
|
||
const svg = document.getElementById('p25-sim'); if(!svg) return;
|
||
function update(){
|
||
const R1 = +document.getElementById('p25-r1').value;
|
||
const R2 = +document.getElementById('p25-r2').value;
|
||
document.getElementById('p25-r1v').textContent = R1;
|
||
document.getElementById('p25-r2v').textContent = R2;
|
||
const Rt = (R1*R2)/(R1+R2);
|
||
const U = 12;
|
||
const I1 = U/R1;
|
||
const I2 = U/R2;
|
||
document.getElementById('p25-rt').textContent = Rt.toFixed(2);
|
||
document.getElementById('p25-i1').textContent = I1.toFixed(2);
|
||
document.getElementById('p25-i2').textContent = I2.toFixed(2);
|
||
document.getElementById('p25-it2').textContent = (I1+I2).toFixed(2);
|
||
/* SVG */
|
||
let s = '';
|
||
/* батарея слева */
|
||
s += window.PHYS.batteryEMF(60, 110, '12 В', 'h');
|
||
/* провод вверх */
|
||
s += window.PHYS.wire(60, 92, 60, 60);
|
||
s += window.PHYS.wire(60, 60, 380, 60);
|
||
/* провод вниз */
|
||
s += window.PHYS.wire(60, 130, 60, 170);
|
||
s += window.PHYS.wire(60, 170, 380, 170);
|
||
/* развилка верх */
|
||
s += window.PHYS.wire(150, 60, 150, 80);
|
||
s += window.PHYS.wire(270, 60, 270, 80);
|
||
/* верхняя ветвь */
|
||
s += window.PHYS.resistor(190, 80, R1, 'h');
|
||
/* нижняя ветвь */
|
||
s += window.PHYS.wire(150, 130, 150, 150);
|
||
s += window.PHYS.wire(270, 130, 270, 150);
|
||
s += window.PHYS.resistor(190, 130, R2, 'h');
|
||
/* подписи токов */
|
||
s += '<text x="180" y="65" font-family="JetBrains Mono,monospace" font-size="11" fill="#d97706">I₁ = '+I1.toFixed(2)+' А</text>';
|
||
s += '<text x="180" y="170" font-family="JetBrains Mono,monospace" font-size="11" fill="#d97706">I₂ = '+I2.toFixed(2)+' А</text>';
|
||
/* провода к развилке снизу */
|
||
s += window.PHYS.wire(150, 100, 270, 100);
|
||
s += window.PHYS.wire(150, 150, 270, 150);
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p25-r1').addEventListener('input', update);
|
||
document.getElementById('p25-r2').addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
function _initP25_quiz(){
|
||
const QS = [
|
||
{sit:'Все лампы в гирлянде гаснут при поломке одной', ans:'S', why:'Это последовательное соединение.'},
|
||
{sit:'В розетке: ТВ и чайник работают независимо', ans:'P', why:'Параллельно — оба под 220 В.'},
|
||
{sit:'Лампа, амперметр, батарея — в одной петле', ans:'S', why:'Последовательно.'},
|
||
{sit:'Два резистора имеют одно и то же напряжение', ans:'P', why:'Параллельно — общее $U$.'},
|
||
{sit:'Через два резистора течёт один и тот же ток', ans:'S', why:'Последовательно — общее $I$.'},
|
||
{sit:'Общее $R$ меньше любого из $R_1$, $R_2$', ans:'P', why:'Параллельное соединение.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p25-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
|
||
+'<button class="btn" data-pick="S" style="padding:14px"><b>Последовательно</b></button>'
|
||
+'<button class="btn" data-pick="P" style="padding:14px"><b>Параллельно</b></button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p25-quiz-fb"></div>';
|
||
document.getElementById('p25-quiz-r').textContent = (i+1);
|
||
document.getElementById('p25-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p25-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p25-quiz'); bumpProgress('p25', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p25-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p25-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP25_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'ser', html:'$I = I_1 = I_2$'},
|
||
{id:'b', cat:'ser', html:'$U = U_1 + U_2$'},
|
||
{id:'c', cat:'ser', html:'$R = R_1 + R_2$'},
|
||
{id:'d', cat:'ser', html:'обрыв $\\to$ ничего не работает'},
|
||
{id:'e', cat:'par', html:'$U = U_1 = U_2$'},
|
||
{id:'f', cat:'par', html:'$I = I_1 + I_2$'},
|
||
{id:'g', cat:'par', html:'$1/R = 1/R_1 + 1/R_2$'},
|
||
{id:'h', cat:'par', html:'обрыв $\\to$ остальные работают'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p25-dnd-pool', scopeSelector:'#sec-p25', cats:['ser','par'], items, columnLayout:false });
|
||
document.getElementById('p25-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p25-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Главное отличие: послед.→общий I, паралл.→общее U.'; addXp(15,'p25-dnd'); bumpProgress('p25', 20); renderMath(fb); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; renderMath(fb); }
|
||
});
|
||
document.getElementById('p25-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p25-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP25_tasks(){
|
||
const TASKS = [
|
||
{q:'$R_1 = 6$, $R_2 = 12$ Ом параллельно. Найди $R_{общ}$ (Ом).', ans:4, tol:0.1, why:'$R = 6\\cdot12/(6+12) = 72/18 = 4$ Ом.'},
|
||
{q:'Два резистора по $R = 10$ Ом параллельно. $R_{общ}$ (Ом)?', ans:5, tol:0.1, why:'$R/2 = 5$ Ом.'},
|
||
{q:'$R_1 = R_2 = R_3 = 9$ Ом, все параллельно. $R_{общ}$ (Ом)?', ans:3, tol:0.1, why:'$R/N = 9/3 = 3$ Ом.'},
|
||
{q:'Параллельно $R_1 = 4$, $R_2 = 4$ Ом, $U = 12$ В. Найди ток в одной ветви (А).', ans:3, tol:0.1, why:'$I_1 = U/R_1 = 12/4 = 3$ А.'},
|
||
{q:'$R_1 = 6$, $R_2 = ?$ параллельно, $R_{общ} = 4$ Ом. Найди $R_2$.', ans:12, tol:0.3, why:'$1/4 = 1/6 + 1/R_2 \\Rightarrow 1/R_2 = 1/12 \\Rightarrow R_2 = 12$ Ом.'},
|
||
{q:'Параллельно к 220 В подключены утюг ($R = 44$ Ом) и лампа ($R = 220$ Ом). Какой общий ток (А)?', ans:6, tol:0.2, why:'$I_1 = 220/44 = 5$, $I_2 = 220/220 = 1$, $I = 6$ А.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p25-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p25-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p25-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p25-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p25-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p25-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p25-task-fb"></div>';
|
||
document.getElementById('p25-task-i').textContent = (i+1);
|
||
document.getElementById('p25-task-ok').textContent = ok;
|
||
document.getElementById('p25-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p25-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p25-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p25-task'); bumpProgress('p25', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p25-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p25-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p25-task-bonus'); bumpProgress('p25', 15); }, 600); }
|
||
});
|
||
document.getElementById('p25-task-hint').addEventListener('click', ()=>{ document.getElementById('p25-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p25-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 3 · WAVE 4 — §26, §27
|
||
====================================================================== */
|
||
|
||
/* ======== §26 — Работа и мощность тока. Джоуль-Ленц ======== */
|
||
function build_p26(){
|
||
const box = document.getElementById('p26-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Работа тока', '§ 26.1',
|
||
'<p>Электрическое поле, прогоняя заряд через проводник, совершает работу. За время $t$ через сечение проходит заряд $q = It$. На каждый кулон поле совершает работу $U$ Джоулей. Значит:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$A = U I t$$</p>'
|
||
+'<p>Это <b>работа электрического тока</b> — энергия, которую ток отдаёт прибору. Она превращается в тепло, свет, движение, звук — в зависимости от прибора.</p>'
|
||
);
|
||
h += makeCard('rule', 'Мощность тока', '§ 26.2',
|
||
'<p><b>Мощность</b> $P$ — работа за единицу времени:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$P = \\dfrac{A}{t} = U I$$</p>'
|
||
+'<p>Эквиваленты (используя закон Ома):</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$P = U I = I^2 R = \\dfrac{U^2}{R}$$</p>'
|
||
+'<p>Единица: 1 <b>Ватт</b> (Вт) — это 1 Дж/с. Названа в честь Джеймса Уатта.</p>'
|
||
);
|
||
h += makeCard('example', 'Закон Джоуля — Ленца', '§ 26.3',
|
||
'<p>В резисторе вся электрическая энергия превращается в <b>тепло</b>:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$Q = I^2 R t$$</p>'
|
||
+'<p>Это <b>закон Джоуля-Ленца</b>. Поэтому работают спирали чайника, утюга, кипятильника. Чем больше $I$ или $R$, тем больше тепла.</p>'
|
||
+'<p>В лампе накаливания нить нагревается до $\\sim 2500$ °C и светится. КПД у такой лампы низкий — 5%; остальное тепло.</p>'
|
||
);
|
||
|
||
/* IV1 — калькулятор P+анимация нагрева */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Мощность и нагрев</div></div>'
|
||
+'<div class="wg-help">Меняй $U$ и $R$ — увидь мощность и как нагревается резистор.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$U$, В: <b id="p26-uv">220</b><input type="range" id="p26-u" min="1" max="240" step="1" value="220"></label>'
|
||
+'<label>$R$, Ом: <b id="p26-rv">100</b><input type="range" id="p26-r" min="1" max="500" step="1" value="100"></label>'
|
||
+'</div>'
|
||
+'<svg id="p26-sim" viewBox="0 0 460 140" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
|
||
+'<span>$I = U/R$ = <b id="p26-ic">2.2</b> А</span>'
|
||
+'<span>$P = UI$ = <b id="p26-pc">484</b> Вт</span>'
|
||
+'<span>$Q$ за 1 минуту = <b id="p26-q1">29.0</b> кДж</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — выбор формулы */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Какую формулу использовать?</div></div>'
|
||
+'<div class="wg-help">Даны величины — выбери удобную формулу для $P$.</div>'
|
||
+'<div id="p26-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p26-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p26-quiz-r">1</b> / 5</span><span>Правильно: <b id="p26-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD мощности приборов */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Расставь приборы по мощности</div></div>'
|
||
+'<div class="wg-help">От самого «слабого» к самому «мощному».</div>'
|
||
+'<div id="p26-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>1. Меньше</h5><div class="drop-items" data-cat="r1"></div></div>'
|
||
+'<div class="drop-box"><h5>2</h5><div class="drop-items" data-cat="r2"></div></div>'
|
||
+'<div class="drop-box"><h5>3</h5><div class="drop-items" data-cat="r3"></div></div>'
|
||
+'<div class="drop-box"><h5>4</h5><div class="drop-items" data-cat="r4"></div></div>'
|
||
+'<div class="drop-box"><h5>5. Больше</h5><div class="drop-items" data-cat="r5"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p26-dnd-check">Проверить</button><button class="btn" id="p26-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p26-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 задач</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p26-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p26-task-i">1</b> / 6</span><span>Правильно: <b id="p26-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.26) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §26</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.26 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p26') + readButton('p26');
|
||
renderMath(box);
|
||
wireReadBtn('p26');
|
||
|
||
_initP26_sim();
|
||
_initP26_quiz();
|
||
_initP26_dnd();
|
||
_initP26_tasks();
|
||
}
|
||
|
||
function _initP26_sim(){
|
||
const svg = document.getElementById('p26-sim'); if(!svg) return;
|
||
function update(){
|
||
const U = +document.getElementById('p26-u').value;
|
||
const R = +document.getElementById('p26-r').value;
|
||
document.getElementById('p26-uv').textContent = U;
|
||
document.getElementById('p26-rv').textContent = R;
|
||
const I = U/R;
|
||
const P = U*I;
|
||
const Q1 = P * 60; /* за 1 мин */
|
||
document.getElementById('p26-ic').textContent = I.toFixed(2);
|
||
document.getElementById('p26-pc').textContent = P.toFixed(0);
|
||
document.getElementById('p26-q1').textContent = (Q1/1000).toFixed(1);
|
||
/* SVG: резистор + цвет нагрева */
|
||
let s = '';
|
||
s += window.PHYS.batteryEMF(60, 70, U+' В', 'h');
|
||
s += window.PHYS.wire(60, 52, 60, 30);
|
||
s += window.PHYS.wire(60, 30, 200, 30);
|
||
/* резистор */
|
||
const tCol = window.PHYS.tempColor(Math.min(150, P/8), 20, 150);
|
||
s += '<rect x="200" y="20" width="80" height="20" fill="'+tCol+'" stroke="#0f172a" stroke-width="1.8" rx="3"/>';
|
||
s += '<text x="240" y="34" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="'+(P>500?'#fff':'#0f172a')+'">R = '+R+' Ом</text>';
|
||
/* glow при высокой мощности */
|
||
if(P > 100){
|
||
const glow = Math.min(1, P/2000);
|
||
s += '<rect x="200" y="20" width="80" height="20" fill="#fbbf24" opacity="'+(glow*0.5).toFixed(2)+'" rx="3"/>';
|
||
}
|
||
s += window.PHYS.wire(280, 30, 400, 30);
|
||
s += window.PHYS.wire(400, 30, 400, 70);
|
||
s += window.PHYS.wire(80, 70, 400, 70);
|
||
/* подпись P */
|
||
s += '<text x="240" y="65" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="700" fill="#dc2626">P = '+P.toFixed(0)+' Вт</text>';
|
||
s += '<text x="240" y="100" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="11" fill="#475569">за 1 мин: Q = '+(Q1/1000).toFixed(1)+' кДж</text>';
|
||
s += '<text x="240" y="118" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" fill="#475569">'+(P<60 ? 'слабый разогрев' : P<500 ? 'тёплый' : P<1500 ? 'горячо' : 'опасно — может оплавиться')+'</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p26-u').addEventListener('input', update);
|
||
document.getElementById('p26-r').addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
function _initP26_quiz(){
|
||
const QS = [
|
||
{sit:'Дано $U = 220$ В, $I = 5$ А. Какая формула?', opts:['$P = UI$','$P = I^2R$','$P = U^2/R$','любая'], ans:0, why:'Когда дано $U$ и $I$ — прямой подсчёт через $UI$.'},
|
||
{sit:'Дано $I = 3$ А, $R = 50$ Ом. Какая?', opts:['$P = UI$','$P = I^2R$','$P = U^2/R$','нельзя'], ans:1, why:'Когда дано $I$ и $R$ — $I^2R$.'},
|
||
{sit:'Дано $U = 220$ В, $R = 100$ Ом. Какая?', opts:['$P = UI$','$P = I^2R$','$P = U^2/R$','нельзя'], ans:2, why:'$U^2/R$ удобнее.'},
|
||
{sit:'$P$ нагревательного прибора 1500 Вт при $U = 220$ В. Какой ток?', opts:['$I = P/U \\approx 6{,}8$ А','$I = U/R$','$I = UP$','нельзя'], ans:0, why:'$I = P/U = 1500/220 \\approx 6{,}82$ А.'},
|
||
{sit:'$Q$ за 10 с в резисторе $R$ при токе $I$. Какая формула?', opts:['$Q = It$','$Q = UI/t$','$Q = I^2 R t$','$Q = U^2/R$'], ans:2, why:'Закон Джоуля-Ленца.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p26-quiz'); if(!wrap) return;
|
||
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.sit+'</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
html += '</div><div class="feedback" id="p26-quiz-fb"></div>';
|
||
wrap.innerHTML = html;
|
||
document.getElementById('p26-quiz-r').textContent = (i+1);
|
||
document.getElementById('p26-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p26-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p26-quiz'); bumpProgress('p26', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p26-quiz-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
});
|
||
});
|
||
renderMath(wrap);
|
||
}
|
||
document.getElementById('p26-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP26_dnd(){
|
||
const items = [
|
||
{id:'led', cat:'r1', html:'светодиод (~0,1 Вт)'},
|
||
{id:'ph', cat:'r2', html:'телефон-зарядка (~5 Вт)'},
|
||
{id:'lamp',cat:'r3', html:'лампа накаливания (60 Вт)'},
|
||
{id:'ket', cat:'r4', html:'чайник (2000 Вт)'},
|
||
{id:'car', cat:'r5', html:'электромобиль (10 000 Вт)'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p26-dnd-pool', scopeSelector:'#sec-p26', cats:['r1','r2','r3','r4','r5'], items, columnLayout:false });
|
||
document.getElementById('p26-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p26-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. От мВт до кВт — огромный диапазон.'; addXp(15,'p26-dnd'); bumpProgress('p26', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p26-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p26-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP26_tasks(){
|
||
const TASKS = [
|
||
{q:'$U = 220$ В, $I = 0{,}5$ А. Найди $P$ (Вт).', ans:110, tol:1, why:'$P = UI = 220 \\cdot 0{,}5 = 110$ Вт.'},
|
||
{q:'Лампа 60 Вт работает 5 часов. Какая работа $A$ (Дж)?', ans:1080000, tol:5000, why:'$A = Pt = 60 \\cdot 18\\,000 = 1{,}08 \\cdot 10^6$ Дж.'},
|
||
{q:'$I = 2$ А, $R = 50$ Ом, $t = 60$ с. Сколько $Q$ выделится (кДж)?', ans:12, tol:0.3, why:'$Q = I^2 R t = 4 \\cdot 50 \\cdot 60 = 12\\,000$ Дж = $12$ кДж.'},
|
||
{q:'$P = 2000$ Вт работают 30 мин. Сколько $A$ в кВт·ч?', ans:1, tol:0.05, why:'$A = 2 \\cdot 0{,}5 = 1$ кВт·ч.'},
|
||
{q:'Чайник 1500 Вт, $U = 220$ В. Какой ток (А, до сотых)?', ans:6.82, tol:0.1, why:'$I = P/U = 1500/220 \\approx 6{,}82$ А.'},
|
||
{q:'$P = 100$ Вт, $R = 484$ Ом. Найди $U$ (В).', ans:220, tol:3, why:'$U = \\sqrt{PR} = \\sqrt{48\\,400} = 220$ В.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p26-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p26-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p26-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p26-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p26-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p26-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p26-task-fb"></div>';
|
||
document.getElementById('p26-task-i').textContent = (i+1);
|
||
document.getElementById('p26-task-ok').textContent = ok;
|
||
document.getElementById('p26-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p26-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p26-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p26-task'); bumpProgress('p26', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p26-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p26-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p26-task-bonus'); bumpProgress('p26', 15); }, 600); }
|
||
});
|
||
document.getElementById('p26-task-hint').addEventListener('click', ()=>{ document.getElementById('p26-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p26-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §27 — Электроэнергия. Безопасность ======== */
|
||
function build_p27(){
|
||
const box = document.getElementById('p27-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Энергия в быту: кВт·ч', '§ 27.1',
|
||
'<p>В квартире электросчётчик измеряет потреблённую энергию в <b>киловатт-часах (кВт·ч)</b>.</p>'
|
||
+'<p>$1$ кВт·ч — работа за 1 час прибором мощностью 1 кВт = 1000 Вт.</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$1 \\text{ кВт·ч} = 3{,}6 \\cdot 10^6 \\text{ Дж}$$</p>'
|
||
+'<p>Стоимость:</p>'
|
||
+'<p style="text-align:center;margin:8px 0">$$\\text{руб} = W (\\text{кВт·ч}) \\times \\text{тариф (руб/кВт·ч)}$$</p>'
|
||
);
|
||
h += makeCard('rule', 'Как сэкономить', '§ 27.2',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Светодиоды вместо ламп накаливания (60 Вт → 8 Вт при том же свете).</li>'
|
||
+'<li>Выключать приборы из розетки (не оставлять в режиме standby).</li>'
|
||
+'<li>Энергосберегающие чайники, мультиварки.</li>'
|
||
+'<li>Утеплять дом (меньше работает обогреватель).</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('example', 'Безопасность при работе с током', '§ 27.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Не трогать оголённые провода и розетки голыми руками.</li>'
|
||
+'<li>Не использовать электроприборы в ванной без УЗО.</li>'
|
||
+'<li>При коротком замыкании срабатывает <b>предохранитель</b> или <b>автомат</b> — отключает цепь.</li>'
|
||
+'<li><b>Заземление</b> отводит ток на землю при пробое корпуса прибора.</li>'
|
||
+'<li>Опасно для жизни: ток > $50$ мА (это $\\sim 12$ В через мокрую кожу).</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — счётчик электроэнергии за месяц */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Счёт за месяц</div></div>'
|
||
+'<div class="wg-help">Сколько часов в день работают приборы — узнай счёт за месяц (30 дней).</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Лампа $60$ Вт, ч/день: <b id="p27-h1">5</b><input type="range" id="p27-h1r" min="0" max="24" step="0.5" value="5"></label>'
|
||
+'<label>ТВ $100$ Вт, ч/день: <b id="p27-h2">4</b><input type="range" id="p27-h2r" min="0" max="24" step="0.5" value="4"></label>'
|
||
+'<label>Чайник $2000$ Вт, мин/день: <b id="p27-h3">10</b><input type="range" id="p27-h3r" min="0" max="60" step="5" value="10"></label>'
|
||
+'<label>Холодильник $150$ Вт, ч/день: <b id="p27-h4">24</b><input type="range" id="p27-h4r" min="0" max="24" step="1" value="24"></label>'
|
||
+'<label>Тариф, руб/(кВт·ч): <b id="p27-tar">0.25</b><input type="range" id="p27-tarr" min="0.1" max="2" step="0.05" value="0.25"></label>'
|
||
+'</div>'
|
||
+'<div class="score-display" style="margin-top:8px;flex-direction:column;align-items:flex-start;gap:3px">'
|
||
+'<span>За месяц израсходуется: <b id="p27-w">186</b> кВт·ч</span>'
|
||
+'<span>Стоимость: <b id="p27-cost">46.5</b> руб</span>'
|
||
+'<span style="font-size:.84rem;color:var(--muted)">Самый «прожорливый» прибор: <b id="p27-top">холодильник</b>.</span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «безопасно ли это?» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Безопасно или нет?</div></div>'
|
||
+'<div class="wg-help">Оцени ситуацию с точки зрения электробезопасности.</div>'
|
||
+'<div id="p27-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p27-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p27-quiz-r">1</b> / 6</span><span>Правильно: <b id="p27-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD энергосбережение */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Экономит или расходует энергию?</div></div>'
|
||
+'<div id="p27-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Экономит</h5><div class="drop-items" data-cat="save"></div></div>'
|
||
+'<div class="drop-box"><h5>Расходует</h5><div class="drop-items" data-cat="waste"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p27-dnd-check">Проверить</button><button class="btn" id="p27-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p27-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — задачи */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 5 задач</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p27-task"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p27-task-i">1</b> / 5</span><span>Правильно: <b id="p27-task-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.27) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §27</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.27 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p27') + readButton('p27');
|
||
renderMath(box);
|
||
wireReadBtn('p27');
|
||
|
||
_initP27_meter();
|
||
_initP27_quiz();
|
||
_initP27_dnd();
|
||
_initP27_tasks();
|
||
}
|
||
|
||
function _initP27_meter(){
|
||
function update(){
|
||
const h1 = +document.getElementById('p27-h1r').value;
|
||
const h2 = +document.getElementById('p27-h2r').value;
|
||
const h3 = +document.getElementById('p27-h3r').value;
|
||
const h4 = +document.getElementById('p27-h4r').value;
|
||
const tar = +document.getElementById('p27-tarr').value;
|
||
document.getElementById('p27-h1').textContent = h1.toFixed(1);
|
||
document.getElementById('p27-h2').textContent = h2.toFixed(1);
|
||
document.getElementById('p27-h3').textContent = h3.toFixed(0);
|
||
document.getElementById('p27-h4').textContent = h4.toFixed(0);
|
||
document.getElementById('p27-tar').textContent = tar.toFixed(2);
|
||
/* кВт·ч за день */
|
||
const w1 = 0.060 * h1;
|
||
const w2 = 0.100 * h2;
|
||
const w3 = 2.000 * (h3/60);
|
||
const w4 = 0.150 * h4;
|
||
const wDay = w1+w2+w3+w4;
|
||
const wMon = wDay * 30;
|
||
const cost = wMon * tar;
|
||
document.getElementById('p27-w').textContent = wMon.toFixed(1);
|
||
document.getElementById('p27-cost').textContent = cost.toFixed(2);
|
||
const all = [['лампа',w1],['ТВ',w2],['чайник',w3],['холодильник',w4]];
|
||
all.sort((a,b)=>b[1]-a[1]);
|
||
document.getElementById('p27-top').textContent = all[0][0];
|
||
}
|
||
['p27-h1r','p27-h2r','p27-h3r','p27-h4r','p27-tarr'].forEach(id => document.getElementById(id).addEventListener('input', update));
|
||
update();
|
||
}
|
||
|
||
function _initP27_quiz(){
|
||
const QS = [
|
||
{sit:'Менять лампочку в горячей люстре, не отключив выключатель.', ans:'N', why:'Опасно — можно получить удар током. Сначала выключить.'},
|
||
{sit:'Использовать электрочайник с заземлённой розеткой.', ans:'Y', why:'Заземление защищает в случае пробоя корпуса.'},
|
||
{sit:'Сушить волосы феном, стоя в ванной с водой.', ans:'N', why:'Очень опасно — вода резко увеличивает риск удара.'},
|
||
{sit:'Удлинитель с предохранителем для розеток.', ans:'Y', why:'Предохранитель сработает при перегрузке.'},
|
||
{sit:'Сэкономить — обмотать оголённый провод изолентой.', ans:'N', why:'Временный «костыль». Нужно заменить провод.'},
|
||
{sit:'Светодиодная лампа вместо лампы накаливания.', ans:'Y', why:'Безопаснее (меньше тепла) и экономичнее.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p27-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
|
||
+'<button class="btn" data-pick="Y" style="padding:14px"><b>Безопасно</b></button>'
|
||
+'<button class="btn" data-pick="N" style="padding:14px"><b>Опасно</b></button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p27-quiz-fb"></div>';
|
||
document.getElementById('p27-quiz-r').textContent = (i+1);
|
||
document.getElementById('p27-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p27-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p27-quiz'); bumpProgress('p27', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p27-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p27-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP27_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'save', html:'светодиодная лампа'},
|
||
{id:'b', cat:'save', html:'утеплитель на окнах'},
|
||
{id:'c', cat:'save', html:'выключать ТВ из розетки'},
|
||
{id:'d', cat:'save', html:'натуральный свет днём'},
|
||
{id:'e', cat:'waste', html:'лампа накаливания 100 Вт'},
|
||
{id:'f', cat:'waste', html:'оставлять зарядки в розетке'},
|
||
{id:'g', cat:'waste', html:'кипятить полный чайник для 1 чашки'},
|
||
{id:'h', cat:'waste', html:'обогреватель при открытой двери'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p27-dnd-pool', scopeSelector:'#sec-p27', cats:['save','waste'], items, columnLayout:false });
|
||
document.getElementById('p27-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p27-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Экономия = меньше счёт + меньше нагрузка на электростанции.'; addXp(15,'p27-dnd'); bumpProgress('p27', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p27-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p27-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP27_tasks(){
|
||
const TASKS = [
|
||
{q:'Чайник $P = 2$ кВт работает 30 мин. Сколько кВт·ч?', ans:1, tol:0.05, why:'$W = P \\tau = 2 \\cdot 0{,}5 = 1$ кВт·ч.'},
|
||
{q:'Лампа $60$ Вт горит 5 часов. Сколько кВт·ч?', ans:0.3, tol:0.02, why:'$W = 0{,}06 \\cdot 5 = 0{,}3$ кВт·ч.'},
|
||
{q:'Тариф $0{,}25$ руб/(кВт·ч). За месяц израсходовали 200 кВт·ч. Стоимость (руб)?', ans:50, tol:1, why:'$200 \\cdot 0{,}25 = 50$ руб.'},
|
||
{q:'Холодильник $150$ Вт работает 24 ч/день. Сколько кВт·ч за месяц (30 дней)?', ans:108, tol:2, why:'$W = 0{,}15 \\cdot 24 \\cdot 30 = 108$ кВт·ч.'},
|
||
{q:'Электрообогреватель 2 кВт работает 8 ч/день, тариф $0{,}3$ руб. Сколько за месяц (руб)?', ans:144, tol:3, why:'$W = 2 \\cdot 8 \\cdot 30 = 480$ кВт·ч, $480 \\cdot 0{,}3 = 144$ руб.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const t = TASKS[i]; const wrap = document.getElementById('p27-task'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Задача '+(i+1)+'.</b> '+t.q+'</div>'
|
||
+'<div class="boss-row"><input type="number" step="0.01" class="tinp" id="p27-task-inp" placeholder="число" style="width:140px">'
|
||
+'<button class="btn primary" id="p27-task-go">Ответ</button>'
|
||
+'<button class="btn" id="p27-task-hint">Подсказка</button>'
|
||
+'<button class="btn" id="p27-task-next">Следующая</button></div>'
|
||
+'<div class="boss-hint-txt" id="p27-task-hint-txt">'+t.why+'</div>'
|
||
+'<div class="feedback" id="p27-task-fb"></div>';
|
||
document.getElementById('p27-task-i').textContent = (i+1);
|
||
document.getElementById('p27-task-ok').textContent = ok;
|
||
document.getElementById('p27-task-go').addEventListener('click', ()=>{
|
||
const v = parseFloat((document.getElementById('p27-task-inp').value || '').replace(',','.'));
|
||
const fb = document.getElementById('p27-task-fb');
|
||
if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
|
||
done++;
|
||
if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно! '+t.why; addXp(4,'p27-task'); bumpProgress('p27', 6); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. Ответ: '+t.ans+'. '+t.why; }
|
||
document.getElementById('p27-task-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= TASKS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p27-task-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — расчёты сданы.'; addXp(15,'p27-task-bonus'); bumpProgress('p27', 15); }, 600); }
|
||
});
|
||
document.getElementById('p27-task-hint').addEventListener('click', ()=>{ document.getElementById('p27-task-hint-txt').classList.toggle('show'); });
|
||
document.getElementById('p27-task-next').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 4 · WAVE 1 — §28, §29
|
||
====================================================================== */
|
||
|
||
/* Хелпер: рисует магнитную полосу N-S */
|
||
function _drawMagnet(x, y, w, hMag, flipped){
|
||
const halfW = w/2;
|
||
const nCol = '#dc2626', sCol = '#2563eb';
|
||
const left = flipped ? sCol : nCol;
|
||
const right = flipped ? nCol : sCol;
|
||
const leftLab = flipped ? 'S' : 'N';
|
||
const rightLab = flipped ? 'N' : 'S';
|
||
let s = '';
|
||
s += '<rect x="'+x+'" y="'+y+'" width="'+halfW+'" height="'+hMag+'" fill="'+left+'" stroke="#0f172a" stroke-width="1.6"/>';
|
||
s += '<rect x="'+(x+halfW)+'" y="'+y+'" width="'+halfW+'" height="'+hMag+'" fill="'+right+'" stroke="#0f172a" stroke-width="1.6"/>';
|
||
s += '<text x="'+(x+halfW/2)+'" y="'+(y+hMag/2+5)+'" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="14" font-weight="900" fill="#fff">'+leftLab+'</text>';
|
||
s += '<text x="'+(x+halfW*1.5)+'" y="'+(y+hMag/2+5)+'" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="14" font-weight="900" fill="#fff">'+rightLab+'</text>';
|
||
return s;
|
||
}
|
||
|
||
/* ======== §28 — Постоянные магниты ======== */
|
||
function build_p28(){
|
||
const box = document.getElementById('p28-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Что такое магнит', '§ 28.1',
|
||
'<p><b>Постоянный магнит</b> — тело, обладающее магнитными свойствами длительное время. Чаще всего из железа, никеля, кобальта или сплавов (например, «магнитное железо» — ферриты).</p>'
|
||
+'<p>У любого магнита есть два <b>полюса</b>: <b>северный (N)</b> и <b>южный (S)</b>. Они расположены на противоположных концах.</p>'
|
||
+'<p><b>Сила взаимодействия</b> сосредоточена у полюсов — там магнит «прилипает» к железу сильнее всего.</p>'
|
||
);
|
||
h += makeCard('rule', 'Закон взаимодействия полюсов', '§ 28.2',
|
||
'<p>По аналогии с зарядами:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li><b>Одноимённые</b> полюсы (N-N или S-S) — <b>отталкиваются</b>.</li>'
|
||
+'<li><b>Разноимённые</b> (N-S) — <b>притягиваются</b>.</li>'
|
||
+'</ul>'
|
||
+'<p>В отличие от электрических зарядов, <b>нельзя получить</b> магнит только с одним полюсом. Если разрезать магнит пополам — получатся <b>два новых</b> магнита, у каждого свои N и S.</p>'
|
||
);
|
||
h += makeCard('example', 'Магнитное поле Земли', '§ 28.3',
|
||
'<p>Земля — гигантский магнит. Её магнитные полюсы расположены вблизи географических (но не точно на них).</p>'
|
||
+'<p><b>Важно</b>: «северный географический» близок к <b>южному магнитному</b> полюсу Земли. Поэтому северный конец стрелки компаса (он же N) притягивается к географическому северу.</p>'
|
||
+'<p>Магнитное поле Земли защищает нас от космических лучей и помогает ориентироваться компасу. Полюсы со временем «дрейфуют».</p>'
|
||
);
|
||
|
||
/* IV1 — взаимодействие двух магнитов */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Два магнита</div></div>'
|
||
+'<div class="wg-help">Переворачивай второй магнит — наблюдай притяжение/отталкивание.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Левый магнит: фиксированный N–S</label>'
|
||
+'<label>Правый магнит: <select id="p28-flip" class="tinp" style="width:auto;padding:6px 10px"><option value="0">N–S (как левый)</option><option value="1">S–N (перевёрнут)</option></select></label>'
|
||
+'</div>'
|
||
+'<svg id="p28-sim" viewBox="0 0 460 200" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Взаимодействие: <b id="p28-act">отталкиваются</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «как поведут себя?» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Притягиваются или отталкиваются?</div></div>'
|
||
+'<div class="wg-help">Соседствующие полюсы.</div>'
|
||
+'<div id="p28-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p28-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p28-quiz-r">1</b> / 5</span><span>Правильно: <b id="p28-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «факт о магнитах» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Правда или ложь?</div></div>'
|
||
+'<div id="p28-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Правда</h5><div class="drop-items" data-cat="t"></div></div>'
|
||
+'<div class="drop-box"><h5>Ложь</h5><div class="drop-items" data-cat="f"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p28-dnd-check">Проверить</button><button class="btn" id="p28-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p28-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p28-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p28-mcq-i">1</b> / 6</span><span>Правильно: <b id="p28-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="p28-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p28-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p28-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — Magnet polarity (Phase 2.2) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Магниты: разноимённые притягиваются</div></div>'
|
||
+'<div class="wg-help">Перетаскивай магниты. При сближении одноимённых полюсов (N-N или S-S) — отталкивание (зелёные стрелки). Разноимённых (N-S) — притяжение (красные стрелки).</div>'
|
||
+'<div class="p8-sandbox" id="p28-iv6-sandbox" style="height:240px"></div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p28') + readButton('p28');
|
||
renderMath(box);
|
||
wireReadBtn('p28');
|
||
_initP28_iv6();
|
||
_initp28_iv5();
|
||
|
||
_initP28_two();
|
||
_initP28_quiz();
|
||
_initP28_dnd();
|
||
_initP28_mcq();
|
||
}
|
||
|
||
function _initP28_two(){
|
||
const svg = document.getElementById('p28-sim'); if(!svg) return;
|
||
function draw(){
|
||
const flipped = +document.getElementById('p28-flip').value === 1;
|
||
let s = '';
|
||
/* левый магнит — фиксирован */
|
||
s += _drawMagnet(80, 70, 120, 60, false); /* N(left) S(right) */
|
||
/* правый магнит */
|
||
s += _drawMagnet(260, 70, 120, 60, flipped); /* зависит от флага */
|
||
/* Между магнитами: соседствуют правая половина левого (S) и левая половина правого */
|
||
/* левая половина правого: flipped ? N : S */
|
||
const rightInner = flipped ? 'N' : 'S';
|
||
/* левый внутр (правая половина левого) = S */
|
||
const leftInner = 'S';
|
||
const attract = leftInner !== rightInner;
|
||
/* стрелки силы */
|
||
if(attract){
|
||
/* притяжение — стрелки идут навстречу */
|
||
s += window.PHYS.drawArrow(190, 100, 230, 100, '#10b981', 2.5, 10);
|
||
s += window.PHYS.drawArrow(270, 100, 230, 100, '#10b981', 2.5, 10);
|
||
s += '<text x="230" y="155" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="14" font-weight="800" fill="#10b981">ПРИТЯГИВАЮТСЯ</text>';
|
||
} else {
|
||
/* отталкивание — стрелки расходятся */
|
||
s += window.PHYS.drawArrow(220, 100, 190, 100, '#dc2626', 2.5, 10);
|
||
s += window.PHYS.drawArrow(240, 100, 270, 100, '#dc2626', 2.5, 10);
|
||
s += '<text x="230" y="155" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="14" font-weight="800" fill="#dc2626">ОТТАЛКИВАЮТСЯ</text>';
|
||
}
|
||
svg.innerHTML = s;
|
||
document.getElementById('p28-act').textContent = attract ? 'притягиваются' : 'отталкиваются';
|
||
}
|
||
document.getElementById('p28-flip').addEventListener('change', draw);
|
||
draw();
|
||
}
|
||
|
||
function _initP28_quiz(){
|
||
const QS = [
|
||
{sit:'N подносим к N', ans:'R', why:'Одноимённые → отталкивание.'},
|
||
{sit:'N подносим к S', ans:'A', why:'Разноимённые → притяжение.'},
|
||
{sit:'S подносим к S', ans:'R', why:'Одноимённые → отталкивание.'},
|
||
{sit:'S подносим к N', ans:'A', why:'Разноимённые → притяжение.'},
|
||
{sit:'Полосовой магнит к стрелке компаса (северный конец)', ans:'A', why:'Северный конец стрелки притягивается к S полюсу магнита, отталкивается от N.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p28-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
|
||
+'<button class="btn" data-pick="A" style="padding:14px"><b>Притягиваются</b></button>'
|
||
+'<button class="btn" data-pick="R" style="padding:14px"><b>Отталкиваются</b></button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p28-quiz-fb"></div>';
|
||
document.getElementById('p28-quiz-r').textContent = (i+1);
|
||
document.getElementById('p28-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p28-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p28-quiz'); bumpProgress('p28', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p28-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p28-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP28_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'t', html:'у магнита 2 полюса: N и S'},
|
||
{id:'b', cat:'t', html:'N–S притягиваются'},
|
||
{id:'c', cat:'t', html:'разрезать магнит → 2 магнита'},
|
||
{id:'d', cat:'t', html:'Земля — гигантский магнит'},
|
||
{id:'e', cat:'f', html:'можно получить один полюс'},
|
||
{id:'f', cat:'f', html:'N–N притягиваются'},
|
||
{id:'g', cat:'f', html:'магнит работает только при подключении'},
|
||
{id:'h', cat:'f', html:'дерево — магнитный материал'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p28-dnd-pool', scopeSelector:'#sec-p28', cats:['t','f'], items, columnLayout:false });
|
||
document.getElementById('p28-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p28-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Магниты — это про железо, никель, кобальт.'; addXp(15,'p28-dnd'); bumpProgress('p28', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p28-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p28-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP28_mcq(){
|
||
const QS = [
|
||
{q:'Сколько полюсов у магнита?', opts:['1','2','3','много'], ans:1, why:'У любого магнита всегда 2 полюса.'},
|
||
{q:'Какие материалы притягиваются магнитом?', opts:['все','железо, никель, кобальт','медь','стекло'], ans:1, why:'Ферромагнетики.'},
|
||
{q:'Что произойдёт при разрезании магнита?', opts:['станет 2 разных магнита N и S','станет ничего','станут 2 полноценных магнита','полюса исчезнут'], ans:2, why:'Каждый «огрызок» снова имеет 2 полюса.'},
|
||
{q:'Северный географический полюс Земли — это магнитный…', opts:['северный','южный','никакой','нейтральный'], ans:1, why:'Север географический ≈ южный магнитный (так задумано в физике).'},
|
||
{q:'Что показывает северный конец компаса?', opts:['на N магнита','на N полюс магнита','на географический север','куда хочешь'], ans:2, why:'Стрелка компаса север «как бы» указывает на северный географический полюс.'},
|
||
{q:'Какая сила действует между магнитами?', opts:['гравитационная','электрическая','магнитная','ядерная'], ans:2, why:'Магнитная.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p28-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p28-mcq-fb"></div><div class="actions"><button class="btn" id="p28-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p28-mcq-i').textContent = (i+1);
|
||
document.getElementById('p28-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p28-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p28-mcq'); bumpProgress('p28', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p28-mcq-ok').textContent = ok;
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p28-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p28-mcq-bonus'); bumpProgress('p28', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p28-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §29 — Магнитное поле ======== */
|
||
function build_p29(){
|
||
const box = document.getElementById('p29-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Что такое магнитное поле', '§ 29.1',
|
||
'<p>Подобно тому как заряды создают электрическое поле, магниты создают вокруг себя <b>магнитное поле</b>.</p>'
|
||
+'<p>Силовая характеристика поля — <b>магнитная индукция</b> $\\vec B$. Единица измерения — <b>Тесла (Тл)</b>, в честь Никола Тесла.</p>'
|
||
+'<p>Магнитное поле обнаруживается по силе, действующей на:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>другие магниты и магнитные стрелки;</li>'
|
||
+'<li>железные предметы;</li>'
|
||
+'<li>проводники с током;</li>'
|
||
+'<li>движущиеся заряды.</li>'
|
||
+'</ul>'
|
||
);
|
||
h += makeCard('rule', 'Линии магнитной индукции', '§ 29.2',
|
||
'<p>Магнитное поле наглядно изображают <b>линиями магнитной индукции</b>:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>выходят из <b>N</b> и входят в <b>S</b> полюс магнита снаружи;</li>'
|
||
+'<li>внутри магнита идут от S к N — поэтому они <b>замкнуты</b>;</li>'
|
||
+'<li>не пересекаются;</li>'
|
||
+'<li>чем гуще линии, тем сильнее поле.</li>'
|
||
+'</ul>'
|
||
+'<p><b>Важное отличие от электрического поля:</b> линии магн. поля всегда замкнуты (нет «магнитных зарядов»).</p>'
|
||
);
|
||
h += makeCard('example', 'Опыт с железными опилками', '§ 29.3',
|
||
'<p>Если на стекло над магнитом насыпать железные опилки, они выстраиваются вдоль линий магнитной индукции. Получается «фотография» магнитного поля.</p>'
|
||
+'<p>Сейчас увидим, как это выглядит.</p>'
|
||
);
|
||
|
||
/* IV1 — линии магн. индукции */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Линии магнитного поля полосового магнита</div></div>'
|
||
+'<div class="wg-help">Линии выходят из N и входят в S — снаружи. Внутри магнита идут от S к N, замыкая контур.</div>'
|
||
+'<svg id="p29-sim" viewBox="0 0 460 280" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «где северный полюс» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Знаешь линии поля?</div></div>'
|
||
+'<div class="wg-help">Правда или ложь о линиях $\\vec B$.</div>'
|
||
+'<div id="p29-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p29-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p29-quiz-r">1</b> / 5</span><span>Правильно: <b id="p29-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD сравнение полей */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Электрическое vs магнитное поле</div></div>'
|
||
+'<div class="wg-help">К какому полю относится свойство?</div>'
|
||
+'<div id="p29-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Электрическое</h5><div class="drop-items" data-cat="e"></div></div>'
|
||
+'<div class="drop-box"><h5>Магнитное</h5><div class="drop-items" data-cat="m"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p29-dnd-check">Проверить</button><button class="btn" id="p29-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p29-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p29-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p29-mcq-i">1</b> / 6</span><span>Правильно: <b id="p29-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="p29-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p29-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p29-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.29) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §29</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.29 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p29') + readButton('p29');
|
||
renderMath(box);
|
||
wireReadBtn('p29');
|
||
_initp29_iv5();
|
||
|
||
_initP29_lines();
|
||
_initP29_quiz();
|
||
_initP29_dnd();
|
||
_initP29_mcq();
|
||
}
|
||
|
||
function _initP29_lines(){
|
||
const svg = document.getElementById('p29-sim'); if(!svg) return;
|
||
/* Полосовой магнит N(слева) S(справа), линии поля изгибаются.
|
||
Параметрически: серия эллиптических дуг разного размера, выходящих из N. */
|
||
const cx = 230, cy = 140;
|
||
const magW = 160, magH = 40;
|
||
let s = '';
|
||
/* нарисуем магнит */
|
||
s += _drawMagnet(cx - magW/2, cy - magH/2, magW, magH, false); /* N(left), S(right) */
|
||
/* линии: эллипсы между N(150,140) и S(310,140), радиус растёт */
|
||
for(let k = 0; k < 7; k++){
|
||
const ry = 30 + k*25;
|
||
/* нарисуем верхнюю и нижнюю половину эллипса как path */
|
||
const xN = cx - magW/2;
|
||
const xS = cx + magW/2;
|
||
/* верхняя половина: дуга от xN,cy через (cx,cy-ry) до xS,cy */
|
||
const cx1 = (xN+xS)/2;
|
||
/* стрелка на верхушке */
|
||
s += '<path d="M '+xN+' '+cy+' Q '+cx1+' '+(cy-ry)+' '+xS+' '+cy+'" fill="none" stroke="#7c3aed" stroke-width="1.4" opacity="0.7"/>';
|
||
s += '<path d="M '+xN+' '+cy+' Q '+cx1+' '+(cy+ry)+' '+xS+' '+cy+'" fill="none" stroke="#7c3aed" stroke-width="1.4" opacity="0.7"/>';
|
||
/* стрелка направления — посередине верхней дуги, направлена вправо */
|
||
if(k < 5){
|
||
s += window.PHYS.drawArrow(cx-6, cy - ry + 2, cx+6, cy - ry + 2, '#7c3aed', 1.5, 7);
|
||
s += window.PHYS.drawArrow(cx-6, cy + ry - 2, cx+6, cy + ry - 2, '#7c3aed', 1.5, 7);
|
||
}
|
||
}
|
||
/* пара прямых линий близко к оси (горизонтально между полюсами) */
|
||
s += '<line x1="'+(cx-magW/2-30)+'" y1="'+cy+'" x2="'+(cx-magW/2-4)+'" y2="'+cy+'" stroke="#7c3aed" stroke-width="1.6"/>';
|
||
s += '<line x1="'+(cx+magW/2+4)+'" y1="'+cy+'" x2="'+(cx+magW/2+30)+'" y2="'+cy+'" stroke="#7c3aed" stroke-width="1.6"/>';
|
||
/* подписи */
|
||
s += '<text x="230" y="40" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#7c3aed">линии магнитной индукции $\\vec B$</text>';
|
||
s += '<text x="60" y="270" font-family="Inter,sans-serif" font-size="11" fill="#475569">снаружи: N → S</text>';
|
||
s += '<text x="280" y="270" font-family="Inter,sans-serif" font-size="11" fill="#475569">внутри: S → N (замыкают)</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
|
||
function _initP29_quiz(){
|
||
const QS = [
|
||
{st:'Линии магнитного поля выходят из S и входят в N.', ans:'F', why:'Наоборот: из N в S.'},
|
||
{st:'Линии магнитного поля замкнуты.', ans:'T', why:'Внутри магнита они идут от S к N, замыкая контур.'},
|
||
{st:'Линии магнитного поля могут пересекаться.', ans:'F', why:'В каждой точке вектор $\\vec B$ имеет одно направление.'},
|
||
{st:'Чем гуще линии, тем сильнее поле.', ans:'T', why:'Густота показывает $|B|$.'},
|
||
{st:'Магнитное поле действует на неподвижный заряд.', ans:'F', why:'Только на движущийся заряд и на ток!'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p29-quiz'); if(!wrap) return;
|
||
wrap.innerHTML =
|
||
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">"'+q.st+'"</div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
|
||
+'<button class="btn" data-pick="T" style="padding:14px"><b>Правда</b></button>'
|
||
+'<button class="btn" data-pick="F" style="padding:14px"><b>Ложь</b></button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="p29-quiz-fb"></div>';
|
||
document.getElementById('p29-quiz-r').textContent = (i+1);
|
||
document.getElementById('p29-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
|
||
const fb = document.getElementById('p29-quiz-fb');
|
||
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p29-quiz'); bumpProgress('p29', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p29-quiz-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
});
|
||
});
|
||
renderMath(wrap);
|
||
}
|
||
document.getElementById('p29-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP29_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'e', html:'линии начинаются на +, кончаются на −'},
|
||
{id:'b', cat:'e', html:'действует на любой заряд'},
|
||
{id:'c', cat:'e', html:'источники — заряды'},
|
||
{id:'d', cat:'e', html:'$U = A/q$'},
|
||
{id:'e', cat:'m', html:'линии замкнуты (без начала и конца)'},
|
||
{id:'f', cat:'m', html:'действует на движ. заряды и ток'},
|
||
{id:'g', cat:'m', html:'источники — магниты и токи'},
|
||
{id:'h', cat:'m', html:'$\\vec B$ — индукция, [Тл]'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p29-dnd-pool', scopeSelector:'#sec-p29', cats:['e','m'], items, columnLayout:false });
|
||
document.getElementById('p29-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p29-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Эл. поле — открытые линии, магн. поле — замкнутые.'; addXp(15,'p29-dnd'); bumpProgress('p29', 20); renderMath(fb); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; renderMath(fb); }
|
||
});
|
||
document.getElementById('p29-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p29-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP29_mcq(){
|
||
const QS = [
|
||
{q:'Что обозначают $\\vec B$?', opts:['напряжённость','индукцию','потенциал','работу'], ans:1, why:'Магнитная индукция.'},
|
||
{q:'Единица измерения $|B|$?', opts:['Вольт','Ампер','Тесла','Ом'], ans:2, why:'Тесла (Тл).'},
|
||
{q:'Куда направлены линии вне магнита?', opts:['от N к S','от S к N','внутри по кругу','хаос'], ans:0, why:'Снаружи — от N к S.'},
|
||
{q:'Линии $\\vec B$ обладают свойством…', opts:['открытости','замкнутости','пересечения','исчезновения'], ans:1, why:'Магнитное поле — соленоидальное.'},
|
||
{q:'Что отклоняет стрелку компаса?', opts:['заряд','свет','магнитное поле Земли','гравитация'], ans:2, why:'Земля — гигантский магнит.'},
|
||
{q:'Как «увидеть» магнитное поле?', opts:['опилками','спиртом','краской','углём'], ans:0, why:'Железные опилки выстраиваются вдоль линий.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p29-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p29-mcq-fb"></div><div class="actions"><button class="btn" id="p29-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p29-mcq-i').textContent = (i+1);
|
||
document.getElementById('p29-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p29-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p29-mcq'); bumpProgress('p29', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p29-mcq-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p29-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p29-mcq-bonus'); bumpProgress('p29', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p29-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======================================================================
|
||
PHASE 4 · WAVE 2 — §30, §31, FINAL 2
|
||
====================================================================== */
|
||
|
||
/* ======== §30 — Магнитное поле тока. Опыт Эрстеда ======== */
|
||
function build_p30(){
|
||
const box = document.getElementById('p30-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Опыт Эрстеда', '§ 30.1',
|
||
'<p>В 1820 году датский физик Ханс Эрстед сделал революционное открытие. Он расположил магнитную стрелку под прямым проводником и включил ток.</p>'
|
||
+'<p>Стрелка <b>повернулась</b>! Это значило: вокруг проводника с током есть <b>магнитное поле</b>.</p>'
|
||
+'<p>До этого считалось, что электричество и магнетизм — совершенно независимы. Опыт Эрстеда показал: <b>это одно явление</b>.</p>'
|
||
);
|
||
h += makeCard('rule', 'Что говорит этот опыт', '§ 30.2',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Ток (движущиеся заряды) создаёт магнитное поле.</li>'
|
||
+'<li>Чем больше $I$, тем сильнее поле.</li>'
|
||
+'<li>Без тока (ключ разомкнут) — поля нет, стрелка стоит как обычно (по полю Земли).</li>'
|
||
+'<li>Если поменять направление тока — стрелка повернётся в обратную сторону.</li>'
|
||
+'</ul>'
|
||
+'<p>Это положило начало <b>электромагнетизму</b> — теории, объединяющей две силы природы.</p>'
|
||
);
|
||
h += makeCard('example', 'Применения', '§ 30.3',
|
||
'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>Электромагнит в реле, звонках, динамиках.</li>'
|
||
+'<li>Электродвигатели всех видов.</li>'
|
||
+'<li>Магнитные подвески поездов (маглев).</li>'
|
||
+'<li>МРТ-сканеры в медицине.</li>'
|
||
+'</ul>'
|
||
);
|
||
|
||
/* IV1 — опыт Эрстеда */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Опыт Эрстеда</div></div>'
|
||
+'<div class="wg-help">Включи ток — стрелка отклонится. Поменяй направление — стрелка повернётся в другую сторону.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>Ключ: <select id="p30-key" class="tinp" style="width:auto;padding:6px 10px"><option value="0">разомкнут (тока нет)</option><option value="1">замкнут</option></select></label>'
|
||
+'<label>Направление тока: <select id="p30-dir" class="tinp" style="width:auto;padding:6px 10px"><option value="1">→ (вправо)</option><option value="-1">← (влево)</option></select></label>'
|
||
+'</div>'
|
||
+'<svg id="p30-sim" viewBox="0 0 460 200" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Стрелка отклонена на: <b id="p30-ang">0°</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина «что произойдёт» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Что в опыте Эрстеда?</div></div>'
|
||
+'<div class="wg-help">Вопросы о значимости опыта.</div>'
|
||
+'<div id="p30-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p30-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p30-quiz-r">1</b> / 5</span><span>Правильно: <b id="p30-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «где есть магн. поле» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Есть ли магнитное поле?</div></div>'
|
||
+'<div class="wg-help">Распредели ситуации.</div>'
|
||
+'<div id="p30-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Есть поле</h5><div class="drop-items" data-cat="y"></div></div>'
|
||
+'<div class="drop-box"><h5>Нет поля</h5><div class="drop-items" data-cat="n"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p30-dnd-check">Проверить</button><button class="btn" id="p30-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p30-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p30-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p30-mcq-i">1</b> / 6</span><span>Правильно: <b id="p30-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="p30-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p30-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p30-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — Эрстед (Phase 2.2) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Опыт Эрстеда: ток отклоняет стрелку</div></div>'
|
||
+'<div class="wg-help">Включи ток в проводнике скрубером — стрелка компаса отклоняется. Направление поля вокруг провода определяется правилом правой руки.</div>'
|
||
+'<div class="p8-sandbox" id="p30-iv6-sandbox" style="height:240px"></div>'
|
||
+'<div style="margin-top:10px;display:flex;gap:14px;flex-wrap:wrap">'
|
||
+'<div class="p8-scrubber" style="flex:1;min-width:240px"><span class="p8-scrubber-label">Ток</span><input type="range" id="p30-iv6-i" min="-5" max="5" step="0.1" value="0"><span class="p8-scrubber-value"><span id="p30-iv6-i-val">0.0</span><span class="p8-unit">А</span></span></div>'
|
||
+'<div class="p8-readout"><span class="p8-readout-label">Угол</span><span class="p8-readout-value" id="p30-iv6-ang">0</span><span class="p8-readout-unit">°</span></div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p30') + readButton('p30');
|
||
renderMath(box);
|
||
wireReadBtn('p30');
|
||
_initP30_iv6();
|
||
_initp30_iv5();
|
||
|
||
_initP30_oersted();
|
||
_initP30_quiz();
|
||
_initP30_dnd();
|
||
_initP30_mcq();
|
||
}
|
||
|
||
function _initP30_oersted(){
|
||
const svg = document.getElementById('p30-sim'); if(!svg) return;
|
||
function draw(){
|
||
const key = +document.getElementById('p30-key').value === 1;
|
||
const dir = +document.getElementById('p30-dir').value;
|
||
let s = '';
|
||
/* провод горизонтальный */
|
||
s += '<line x1="60" y1="60" x2="400" y2="60" stroke="#374151" stroke-width="4" stroke-linecap="round"/>';
|
||
/* батарея слева, ключ */
|
||
s += window.PHYS.batteryEMF(60, 130, '6 В', 'h');
|
||
s += window.PHYS.wire(60, 112, 60, 60);
|
||
s += window.PHYS.wire(60, 148, 60, 170);
|
||
s += window.PHYS.wire(60, 170, 400, 170);
|
||
s += window.PHYS.wire(400, 170, 400, 60);
|
||
/* ключ на нижнем проводе */
|
||
s += '<circle cx="200" cy="170" r="3" fill="#0f172a"/>';
|
||
s += '<circle cx="240" cy="170" r="3" fill="#0f172a"/>';
|
||
if(key) s += '<line x1="200" y1="170" x2="240" y2="170" stroke="#0f172a" stroke-width="3"/>';
|
||
else s += '<line x1="200" y1="170" x2="235" y2="155" stroke="#0f172a" stroke-width="3"/>';
|
||
/* стрелка тока на проводе */
|
||
if(key){
|
||
if(dir > 0) s += window.PHYS.drawArrow(200, 50, 260, 50, '#d97706', 2.2, 10);
|
||
else s += window.PHYS.drawArrow(260, 50, 200, 50, '#d97706', 2.2, 10);
|
||
s += '<text x="230" y="40" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="12" font-weight="700" fill="#d97706">I</text>';
|
||
}
|
||
/* магнитная стрелка под проводом */
|
||
const cx = 230, cy = 100;
|
||
/* угол отклонения */
|
||
let angle = 0; /* 0 — стрелка вдоль провода (на запад/восток... условно вверх в нашем рисунке: будет указывать на N=верх) */
|
||
/* без тока: стрелка указывает «на север» — то есть направлена вверх (в нашей рисовке север = верх) */
|
||
/* с током: отклоняется перпендикулярно проводу.
|
||
Эрстед: если ток слева направо (запад → восток), стрелка отклоняется по часовой стрелке (вид сверху, стрелка кажется поворачивается вправо). */
|
||
if(key){
|
||
angle = dir > 0 ? 60 : -60; /* 60° от исходного направления */
|
||
}
|
||
/* нарисуем стрелку: длина 36, поворот на angle */
|
||
const rad = angle * Math.PI / 180;
|
||
/* без поворота стрелка идёт вверх (от cx,cy+18 до cx,cy-18) */
|
||
const lenH = 18;
|
||
const ex1 = cx + lenH * Math.sin(rad);
|
||
const ey1 = cy - lenH * Math.cos(rad); /* северный конец */
|
||
const ex2 = cx - lenH * Math.sin(rad);
|
||
const ey2 = cy + lenH * Math.cos(rad);
|
||
s += '<circle cx="'+cx+'" cy="'+cy+'" r="4" fill="#0f172a"/>';
|
||
s += '<line x1="'+cx+'" y1="'+cy+'" x2="'+ex1.toFixed(1)+'" y2="'+ey1.toFixed(1)+'" stroke="#dc2626" stroke-width="3"/>';
|
||
s += '<polygon points="'+ex1.toFixed(1)+','+ey1.toFixed(1)+' '+(ex1-4*Math.cos(rad)).toFixed(1)+','+(ey1-4*Math.sin(rad)).toFixed(1)+' '+(ex1+4*Math.cos(rad)).toFixed(1)+','+(ey1+4*Math.sin(rad)).toFixed(1)+'" fill="#dc2626"/>';
|
||
s += '<line x1="'+cx+'" y1="'+cy+'" x2="'+ex2.toFixed(1)+'" y2="'+ey2.toFixed(1)+'" stroke="#2563eb" stroke-width="3"/>';
|
||
/* подпись стрелки */
|
||
s += '<text x="'+(ex1+8*Math.sin(rad)).toFixed(1)+'" y="'+(ey1-2).toFixed(1)+'" font-family="Inter,sans-serif" font-size="11" font-weight="800" fill="#dc2626">N</text>';
|
||
/* отклонение */
|
||
document.getElementById('p30-ang').textContent = Math.abs(angle).toFixed(0)+'°';
|
||
svg.innerHTML = s;
|
||
}
|
||
document.getElementById('p30-key').addEventListener('change', draw);
|
||
document.getElementById('p30-dir').addEventListener('change', draw);
|
||
draw();
|
||
}
|
||
|
||
function _initP30_quiz(){
|
||
const QS = [
|
||
{q:'Что заметил Эрстед в опыте?', opts:['тёплый провод','отклонение стрелки около проводника с током','свечение проводника','ничего'], ans:1, why:'Магнитная стрелка отклонилась.'},
|
||
{q:'Что доказывает опыт?', opts:['ток нагревает','ток создаёт магн. поле','магнит проводит ток','ничего'], ans:1, why:'Ток создаёт магнитное поле.'},
|
||
{q:'В каком году провёл опыт?', opts:['1750','1820','1900','1950'], ans:1, why:'1820 год.'},
|
||
{q:'Что произойдёт, если поменять направление тока?', opts:['стрелка не среагирует','стрелка повернётся в противоположную сторону','стрелка сломается','стрелка сделает оборот'], ans:1, why:'Направление поля зависит от направления тока.'},
|
||
{q:'Без тока (ключ разомкнут) стрелка…', opts:['отклонена','указывает на север','вращается','не работает'], ans:1, why:'Под действием магнитного поля Земли указывает на N.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p30-quiz'); if(!wrap) return;
|
||
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
html += '</div><div class="feedback" id="p30-quiz-fb"></div>';
|
||
wrap.innerHTML = html;
|
||
document.getElementById('p30-quiz-r').textContent = (i+1);
|
||
document.getElementById('p30-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p30-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p30-quiz'); bumpProgress('p30', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p30-quiz-ok').textContent = ok;
|
||
});
|
||
});
|
||
}
|
||
document.getElementById('p30-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP30_dnd(){
|
||
const items = [
|
||
{id:'a', cat:'y', html:'постоянный магнит'},
|
||
{id:'b', cat:'y', html:'провод с током'},
|
||
{id:'c', cat:'y', html:'движущийся электрон'},
|
||
{id:'d', cat:'y', html:'катушка под током'},
|
||
{id:'e', cat:'n', html:'нейтральный кусок железа'},
|
||
{id:'f', cat:'n', html:'разомкнутая цепь'},
|
||
{id:'g', cat:'n', html:'покоящийся заряд'},
|
||
{id:'h', cat:'n', html:'батарейка без провода'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p30-dnd-pool', scopeSelector:'#sec-p30', cats:['y','n'], items, columnLayout:false });
|
||
document.getElementById('p30-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p30-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. Магн. поле создают: магниты, токи и движ. заряды.'; addXp(15,'p30-dnd'); bumpProgress('p30', 20); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p30-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p30-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP30_mcq(){
|
||
const QS = [
|
||
{q:'Кто открыл связь электричества и магнетизма?', opts:['Вольт','Ампер','Эрстед','Ом'], ans:2, why:'Х. Эрстед, 1820 г.'},
|
||
{q:'Какое поле создаёт ток?', opts:['электрическое','магнитное','гравитационное','тепловое'], ans:1, why:'Магнитное.'},
|
||
{q:'От чего зависит сила магн. поля у провода?', opts:['от U','от I','от R','от температуры'], ans:1, why:'Чем больше $I$, тем сильнее поле.'},
|
||
{q:'Как меняется поле, если ток развернуть?', opts:['исчезает','усиливается','меняет направление','удваивается'], ans:2, why:'Меняет знак (направление).'},
|
||
{q:'Применение опыта Эрстеда?', opts:['лампы','электромоторы','чайники','компасы'], ans:1, why:'Все электромоторы используют взаимод. тока и магн. поля.'},
|
||
{q:'Что объединил Эрстед?', opts:['теплоту и свет','электричество и магнетизм','гравитацию и свет','химию и физику'], ans:1, why:'Электричество ↔ магнетизм.'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p30-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p30-mcq-fb"></div><div class="actions"><button class="btn" id="p30-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p30-mcq-i').textContent = (i+1);
|
||
document.getElementById('p30-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p30-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p30-mcq'); bumpProgress('p30', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p30-mcq-ok').textContent = ok;
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p30-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p30-mcq-bonus'); bumpProgress('p30', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p30-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== §31 — Поле прямого провода и катушки. Электромагнит ======== */
|
||
function build_p31(){
|
||
const box = document.getElementById('p31-body');
|
||
let h = '';
|
||
|
||
h += makeCard('theory', 'Поле прямого провода', '§ 31.1',
|
||
'<p>Опыт с железными опилками показывает: линии магнитного поля вокруг прямого провода с током — <b>концентрические окружности</b> в плоскости, перпендикулярной проводу.</p>'
|
||
+'<p><b>Правило правой руки</b>: если большой палец правой руки направить вдоль тока, то остальные пальцы покажут направление линий $\\vec B$.</p>'
|
||
);
|
||
h += makeCard('rule', 'Катушка с током (соленоид)', '§ 31.2',
|
||
'<p>Если намотать провод спиралью и пропустить через него ток, получится <b>соленоид</b>. Его магнитное поле очень похоже на поле полосового магнита:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>один торец становится «N» полюсом, другой — «S»;</li>'
|
||
+'<li>линии $\\vec B$ выходят из N, входят в S, замыкаются;</li>'
|
||
+'<li>сила поля растёт с током $I$ и числом витков $N$: $|B| \\propto I N$.</li>'
|
||
+'</ul>'
|
||
+'<p>Направление полюсов снова определяется правилом правой руки: пальцы — по витку с током, большой палец — в сторону северного полюса.</p>'
|
||
);
|
||
h += makeCard('example', 'Электромагнит', '§ 31.3',
|
||
'<p>Если вставить внутрь катушки железный <b>сердечник</b>, поле резко усиливается (в 1000+ раз). Получается <b>электромагнит</b>.</p>'
|
||
+'<p>Его преимущества:</p>'
|
||
+'<ul style="padding-left:20px;margin:6px 0">'
|
||
+'<li>включается и выключается по желанию (через ключ);</li>'
|
||
+'<li>сила управляется током $I$;</li>'
|
||
+'<li>можно сделать очень сильным.</li>'
|
||
+'</ul>'
|
||
+'<p>Применения: дверные звонки, реле, грузоподъёмные краны, левитирующие поезда.</p>'
|
||
);
|
||
|
||
/* IV1 — электромагнит-конструктор */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Электромагнит-конструктор</div></div>'
|
||
+'<div class="wg-help">Меняй ток и число витков — увидь, сколько скрепок поднимает электромагнит.</div>'
|
||
+'<div class="sliders" style="margin-bottom:10px">'
|
||
+'<label>$I$, А: <b id="p31-iv">1.0</b><input type="range" id="p31-i" min="0" max="3" step="0.1" value="1"></label>'
|
||
+'<label>Число витков $N$: <b id="p31-nv">50</b><input type="range" id="p31-n" min="0" max="200" step="10" value="50"></label>'
|
||
+'<label>Сердечник: <select id="p31-core" class="tinp" style="width:auto;padding:6px 10px"><option value="1">воздух (без)</option><option value="500">железо</option></select></label>'
|
||
+'</div>'
|
||
+'<svg id="p31-sim" viewBox="0 0 460 220" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
|
||
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:3px">'
|
||
+'<span>$|B| \\propto I \\cdot N \\cdot \\mu$: <b id="p31-bval">50</b> у.е.</span>'
|
||
+'<span>Поднимет скрепок: <b id="p31-clips">2</b></span>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
/* IV2 — викторина правило правой руки */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Где северный полюс электромагнита?</div></div>'
|
||
+'<div class="wg-help">По направлению тока определи полюсы.</div>'
|
||
+'<div id="p31-quiz"></div>'
|
||
+'<div class="actions"><button class="btn" id="p31-quiz-next">Следующий</button></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p31-quiz-r">1</b> / 5</span><span>Правильно: <b id="p31-quiz-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV3 — DnD «что усилит поле» */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Что усилит поле электромагнита?</div></div>'
|
||
+'<div class="wg-help">Распредели действия.</div>'
|
||
+'<div id="p31-dnd-pool"></div>'
|
||
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
|
||
+'<div class="drop-box"><h5>Усилит</h5><div class="drop-items" data-cat="up"></div></div>'
|
||
+'<div class="drop-box"><h5>Ослабит</h5><div class="drop-items" data-cat="dn"></div></div>'
|
||
+'</div>'
|
||
+'<div class="actions"><button class="btn primary" id="p31-dnd-check">Проверить</button><button class="btn" id="p31-dnd-reset">Сброс</button></div>'
|
||
+'<div class="feedback" id="p31-dnd-fb"></div>'
|
||
+'</div>';
|
||
|
||
/* IV4 — MCQ */
|
||
h += '<div class="wg">'
|
||
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
|
||
+'<div class="wg-help">4+ — +15 XP.</div>'
|
||
+'<div id="p31-mcq"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p31-mcq-i">1</b> / 6</span><span>Правильно: <b id="p31-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="p31-tasks5"></div>'
|
||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p31-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p31-tasks5-ok">0</b></span></div>'
|
||
+'</div>';
|
||
|
||
/* IV6 — flagship интерактив (заглушка Phase 2, наполнение в Phase 2.31) */
|
||
h += '<div class="wg p8-iv6">'
|
||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-electric">IV-6</span><div class="wg-title">Новый интерактив §31</div></div>'
|
||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||
+'<div style="margin-top:8px;font-size:.86rem">Phase 2.31 — coming soon</div>'
|
||
+'</div>'
|
||
+'</div>';
|
||
|
||
box.innerHTML = h + secNavFor('p31') + readButton('p31');
|
||
renderMath(box);
|
||
wireReadBtn('p31');
|
||
_initp31_iv5();
|
||
|
||
_initP31_emagnet();
|
||
_initP31_quiz();
|
||
_initP31_dnd();
|
||
_initP31_mcq();
|
||
}
|
||
|
||
function _initP31_emagnet(){
|
||
const svg = document.getElementById('p31-sim'); if(!svg) return;
|
||
function update(){
|
||
const I = +document.getElementById('p31-i').value;
|
||
const N = +document.getElementById('p31-n').value;
|
||
const mu = +document.getElementById('p31-core').value;
|
||
document.getElementById('p31-iv').textContent = I.toFixed(1);
|
||
document.getElementById('p31-nv').textContent = N;
|
||
const B = I * N * mu / 100; /* условная единица */
|
||
document.getElementById('p31-bval').textContent = B.toFixed(0);
|
||
const clips = Math.floor(B / 25);
|
||
document.getElementById('p31-clips').textContent = clips;
|
||
/* SVG: катушка + сердечник + поднятые скрепки */
|
||
let s = '';
|
||
/* батарея */
|
||
s += window.PHYS.batteryEMF(50, 180, I.toFixed(1)+' А', 'h');
|
||
/* провода */
|
||
s += window.PHYS.wire(50, 162, 50, 100);
|
||
s += window.PHYS.wire(50, 100, 130, 100);
|
||
s += window.PHYS.wire(50, 198, 50, 200);
|
||
s += window.PHYS.wire(50, 200, 360, 200);
|
||
s += window.PHYS.wire(360, 200, 360, 100);
|
||
s += window.PHYS.wire(360, 100, 320, 100);
|
||
/* катушка — серия наклонных полудуг */
|
||
const wireCount = Math.max(3, Math.min(20, Math.floor(N/10)));
|
||
const coilX1 = 130, coilX2 = 320;
|
||
const coilSpan = coilX2 - coilX1;
|
||
const coilCy = 100;
|
||
/* стержень-сердечник (если железо — заметнее) */
|
||
if(mu > 1){
|
||
s += '<rect x="'+(coilX1-10)+'" y="'+(coilCy-12)+'" width="'+(coilSpan+20)+'" height="24" fill="#cbd5e1" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
|
||
}
|
||
for(let k=0; k<wireCount; k++){
|
||
const cx = coilX1 + (k+0.5) * coilSpan/wireCount;
|
||
s += '<ellipse cx="'+cx.toFixed(1)+'" cy="'+coilCy+'" rx="6" ry="18" fill="none" stroke="#d97706" stroke-width="2"/>';
|
||
}
|
||
/* N и S */
|
||
s += '<text x="'+(coilX1-22)+'" y="'+(coilCy+5)+'" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="16" font-weight="900" fill="#dc2626">N</text>';
|
||
s += '<text x="'+(coilX2+22)+'" y="'+(coilCy+5)+'" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="16" font-weight="900" fill="#2563eb">S</text>';
|
||
/* скрепки притянуты к N полюсу */
|
||
for(let k=0;k<clips && k<8;k++){
|
||
const yC = 130 + k*10;
|
||
s += '<path d="M '+(coilX1-30-k*4)+' '+yC+' Q '+(coilX1-15)+' '+(yC+3)+' '+(coilX1-15)+' '+yC+' Q '+(coilX1-15)+' '+(yC-3)+' '+(coilX1-30-k*4)+' '+yC+'" fill="none" stroke="#475569" stroke-width="2"/>';
|
||
}
|
||
/* подпись */
|
||
s += '<text x="'+(coilX1+coilSpan/2)+'" y="50" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#7c3aed">|B| = '+B.toFixed(0)+', клипс: '+clips+'</text>';
|
||
svg.innerHTML = s;
|
||
}
|
||
['p31-i','p31-n','p31-core'].forEach(id => document.getElementById(id).addEventListener('input', update));
|
||
document.getElementById('p31-core').addEventListener('change', update);
|
||
update();
|
||
}
|
||
|
||
function _initP31_quiz(){
|
||
const QS = [
|
||
{q:'Большой палец правой руки = ток. Куда направлены остальные пальцы?', opts:['от N','вдоль линий $\\vec B$','к S','перпендикулярно'], ans:1, why:'Правило правой руки: пальцы по $\\vec B$.'},
|
||
{q:'У катушки — какой полюс там, куда «выходят» линии?', opts:['N','S','оба','никакой'], ans:0, why:'Линии выходят из N.'},
|
||
{q:'Что усилит поле катушки сильнее всего?', opts:['+ток','+витки','+железный сердечник','любое'], ans:2, why:'Сердечник усиливает поле в сотни раз.'},
|
||
{q:'Электромагнит работает на постоянном…', opts:['напряжении','токе','тепле','магните'], ans:1, why:'Нужен постоянный ток.'},
|
||
{q:'Что произойдёт, если выключить ток?', opts:['поле остаётся','поле исчезает','поле растёт','полюса меняются'], ans:1, why:'Поле существует только при токе.'}
|
||
];
|
||
let i = 0, ok = 0;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p31-quiz'); if(!wrap) return;
|
||
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
html += '</div><div class="feedback" id="p31-quiz-fb"></div>';
|
||
wrap.innerHTML = html;
|
||
document.getElementById('p31-quiz-r').textContent = (i+1);
|
||
document.getElementById('p31-quiz-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p31-quiz-fb');
|
||
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(3,'p31-quiz'); bumpProgress('p31', 4); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p31-quiz-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
});
|
||
});
|
||
renderMath(wrap);
|
||
}
|
||
document.getElementById('p31-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
render();
|
||
}
|
||
|
||
function _initP31_dnd(){
|
||
const items = [
|
||
{id:'i', cat:'up', html:'увеличить ток $I$'},
|
||
{id:'n', cat:'up', html:'добавить витков'},
|
||
{id:'c', cat:'up', html:'вставить железный сердечник'},
|
||
{id:'t', cat:'up', html:'намотать туже'},
|
||
{id:'ki',cat:'dn', html:'уменьшить ток'},
|
||
{id:'nn',cat:'dn', html:'убрать половину витков'},
|
||
{id:'ne',cat:'dn', html:'вынуть сердечник'},
|
||
{id:'op',cat:'dn', html:'разомкнуть цепь'}
|
||
];
|
||
const dnd = setupSorter({ poolId:'p31-dnd-pool', scopeSelector:'#sec-p31', cats:['up','dn'], items, columnLayout:false });
|
||
document.getElementById('p31-dnd-check').addEventListener('click', ()=>{
|
||
const fb = document.getElementById('p31-dnd-fb');
|
||
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
|
||
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='✓ Идеально! +15 XP. $|B| \\propto I N$ + сердечник усиливает в сотни раз.'; addXp(15,'p31-dnd'); bumpProgress('p31', 20); renderMath(fb); }
|
||
else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wrong+'.'; }
|
||
});
|
||
document.getElementById('p31-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p31-dnd-fb'); fb.style.display='none'; });
|
||
}
|
||
|
||
function _initP31_mcq(){
|
||
const QS = [
|
||
{q:'Линии $\\vec B$ вокруг прямого провода — это…', opts:['прямые','окружности','эллипсы','зигзаги'], ans:1, why:'Концентрические окружности перпендикулярно проводу.'},
|
||
{q:'Что определяет правило правой руки?', opts:['знак заряда','направление $\\vec B$','напряжение','частоту'], ans:1, why:'Направление магнитного поля.'},
|
||
{q:'Соленоид с током похож на…', opts:['прямой магнит','полосовой магнит','подковообразный','ничего'], ans:1, why:'Поле как у полосового магнита.'},
|
||
{q:'Электромагнит = …', opts:['обычный магнит','катушка + сердечник','батарейка + лампа','любой провод'], ans:1, why:'Катушка с сердечником.'},
|
||
{q:'Зачем сердечник?', opts:['для красоты','для прочности','для усиления магнитного поля','чтобы катушка не сгорала'], ans:2, why:'Железо концентрирует магнитное поле — усиливает в сотни раз.'},
|
||
{q:'Где применяют электромагнит?', opts:['в МРТ','в кранах','в звонках, реле','везде перечисленное'], ans:3, why:'Все эти устройства!'}
|
||
];
|
||
let i = 0, ok = 0, done = 0, awarded = false;
|
||
function render(){
|
||
const q = QS[i]; const wrap = document.getElementById('p31-mcq'); if(!wrap) return;
|
||
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
|
||
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
|
||
h += '</div><div class="feedback" id="p31-mcq-fb"></div><div class="actions"><button class="btn" id="p31-mcq-next">Следующий</button></div>';
|
||
wrap.innerHTML = h;
|
||
document.getElementById('p31-mcq-i').textContent = (i+1);
|
||
document.getElementById('p31-mcq-ok').textContent = ok;
|
||
wrap.querySelectorAll('[data-k]').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{
|
||
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
|
||
const k = +btn.dataset.k; const fb = document.getElementById('p31-mcq-fb');
|
||
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ Верно. '+q.why; addXp(2,'p31-mcq'); bumpProgress('p31', 3); }
|
||
else { done++; fb.className='feedback fail'; fb.innerHTML='✗ Не то. '+q.why; }
|
||
document.getElementById('p31-mcq-ok').textContent = ok;
|
||
renderMath(wrap);
|
||
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p31-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p31-mcq-bonus'); bumpProgress('p31', 15); }, 600); }
|
||
});
|
||
});
|
||
const nb = document.getElementById('p31-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
|
||
renderMath(wrap);
|
||
}
|
||
render();
|
||
}
|
||
|
||
/* ======== ФИНАЛ ГЛАВЫ 2 — 10 интегрированных боссов ======== */
|
||
function build_final2(){
|
||
const box = document.getElementById('final2-body');
|
||
let h = '';
|
||
|
||
/* Шпаргалка */
|
||
h += '<div class="card" style="background:linear-gradient(135deg,var(--sec-acc-soft),var(--card));border:1.5px solid var(--sec-acc)">'
|
||
+'<div class="card-header"><div class="card-icon rule">'+ICONS.rule+'</div><div class="card-title">Шпаргалка главы 2</div></div>'
|
||
+'<div class="card-body" style="display:grid;grid-template-columns:1fr 1fr;gap:14px">'
|
||
+'<div><b>Заряд:</b> $q = Ne$, $e = 1{,}6\\cdot10^{-19}$ Кл</div>'
|
||
+'<div><b>Поле:</b> $\\vec E$, линии от + к −</div>'
|
||
+'<div><b>Напряжение:</b> $U = A/q$, $A = qU$</div>'
|
||
+'<div><b>Ток:</b> $I = q/t$, [А]</div>'
|
||
+'<div><b>Ом:</b> $I = U/R$</div>'
|
||
+'<div><b>Сопротивление:</b> $R = \\rho l/S$</div>'
|
||
+'<div><b>Последов.:</b> $R = R_1+R_2$, $I=$const, $U=U_1+U_2$</div>'
|
||
+'<div><b>Паралл.:</b> $1/R = 1/R_1+1/R_2$, $U=$const, $I=I_1+I_2$</div>'
|
||
+'<div><b>Мощность:</b> $P = UI = I^2R = U^2/R$</div>'
|
||
+'<div><b>Джоуль-Ленц:</b> $Q = I^2Rt$</div>'
|
||
+'<div><b>Энергия:</b> $W = Pt$ кВт·ч; $1$ кВт·ч $= 3{,}6\\cdot10^6$ Дж</div>'
|
||
+'<div><b>Магниты:</b> N, S; одноим. отталк., разноим. притяг.</div>'
|
||
+'</div></div>';
|
||
|
||
/* 10 интегрированных боссов */
|
||
const BOSSES = [
|
||
{n:1, title:'Закон Ома базовый', q:'$U = 36$ В, $R = 12$ Ом. Найди $I$ (А).', hint:'$I = U/R = 3$ А.', ans:3, tol:0.05, step:'0.01'},
|
||
{n:2, title:'Сопротивление провода', q:'Медь $l = 50$ м, $S = 0{,}5$ мм². Найди $R$ (Ом). ($\\rho = 0{,}017$)', hint:'$R = \\rho l/S = 0{,}017\\cdot50/0{,}5 = 1{,}7$ Ом.', ans:1.7, tol:0.05, step:'0.01'},
|
||
{n:3, title:'Послед. цепь', q:'$R_1 = 4$, $R_2 = 6$, $R_3 = 10$ Ом последовательно, $U = 40$ В. Найди $I$ (А).', hint:'$R = 20$, $I = 40/20 = 2$ А.', ans:2, tol:0.05, step:'0.01'},
|
||
{n:4, title:'Паралл. цепь', q:'Два резистора $R_1 = R_2 = 12$ Ом параллельно. Найди $R_{общ}$ (Ом).', hint:'$R/2 = 6$ Ом.', ans:6, tol:0.1, step:'0.1'},
|
||
{n:5, title:'Смешанная цепь', q:'$R_1 = 5$ Ом последовательно с параллельным блоком ($R_2 = R_3 = 10$ Ом каждый). $U = 20$ В. Найди общий $I$ (А).', hint:'$R_{пар} = 5$, $R = 10$, $I = 20/10 = 2$ А.', ans:2, tol:0.05, step:'0.01'},
|
||
{n:6, title:'Мощность', q:'Чайник 1100 Вт работает при $U = 220$ В. Найди $I$ (А) и $R$ (Ом). Введи $R$.', hint:'$I = P/U = 5$ А, $R = U/I = 44$ Ом.', ans:44, tol:1, step:'1'},
|
||
{n:7, title:'Джоуль-Ленц', q:'Спираль $R = 50$ Ом, $I = 4$ А, $t = 1$ мин. Сколько кДж выделится?', hint:'$Q = I^2Rt = 16\\cdot50\\cdot60 = 48\\,000$ Дж = $48$ кДж.', ans:48, tol:1, step:'1'},
|
||
{n:8, title:'кВт·ч за месяц', q:'Холодильник 200 Вт работает 24 ч/день, 30 дней. Сколько кВт·ч за месяц?', hint:'$W = 0{,}2 \\cdot 24 \\cdot 30 = 144$ кВт·ч.', ans:144, tol:2, step:'1'},
|
||
{n:9, title:'Стоимость энергии', q:'За месяц израсходовано 250 кВт·ч, тариф $0{,}25$ руб/(кВт·ч). Сколько руб?', hint:'$250 \\cdot 0{,}25 = 62{,}5$ руб.', ans:62.5, tol:0.5, step:'0.1'},
|
||
{n:10, title:'Магистр электромагнетизма', q:'Электромагнит с $N = 200$ витками и $I = 1{,}5$ А. Поле в 10 раз сильнее, чем при $N = 50$ и $I = 0{,}6$ А. Во сколько раз поле сильнее в обычной катушке без сердечника, чем с железным сердечником (предположим, сердечник усиливает в 500 раз)? Введи число.', hint:'Сердечник увеличивает поле в 500 раз. Без сердечника поле в 500 раз слабее.', ans:500, tol:5, step:'1'}
|
||
];
|
||
|
||
h += '<div class="card" style="margin-top:14px"><div class="card-header"><div class="card-icon example">'+ICONS.example+'</div><div class="card-title">10 боссов главы 2</div></div><div class="card-body">'
|
||
+'<div class="boss-overall-bar" style="background:linear-gradient(135deg,rgba(15,23,42,.04),rgba(217,119,6,.04));border-radius:11px;padding:12px;display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-bottom:14px">'
|
||
+'<span style="font-weight:700">Боссов побеждено: <b id="f2-won">0</b> / 10</span>'
|
||
+'<div style="flex:1;min-width:160px;height:8px;background:rgba(0,0,0,.08);border-radius:4px;overflow:hidden">'
|
||
+'<div id="f2-bar" style="height:100%;background:linear-gradient(90deg,var(--sec-acc),var(--sec-acc-d));width:0%;transition:width .4s"></div>'
|
||
+'</div></div>'
|
||
+'<div id="f2-bosses"></div>'
|
||
+'</div></div>';
|
||
|
||
box.innerHTML = h + secNavFor('final2') + readButton('final2');
|
||
renderMath(box);
|
||
wireReadBtn('final2');
|
||
|
||
_initFinal2_bosses(BOSSES);
|
||
}
|
||
|
||
function _initFinal2_bosses(BOSSES){
|
||
const KEY = 'physics8_ch2_bosses';
|
||
function loadState(){ try { return JSON.parse(localStorage.getItem(KEY) || '{}') || {}; } catch(e){ return {}; } }
|
||
function saveState(s){ try { localStorage.setItem(KEY, JSON.stringify(s)); } catch(e){} }
|
||
function updateBar(){
|
||
const s = loadState();
|
||
let won = 0; for(const k in s) if(s[k]) won++;
|
||
document.getElementById('f2-won').textContent = won;
|
||
document.getElementById('f2-bar').style.width = Math.round(won*100/BOSSES.length)+'%';
|
||
if(won >= BOSSES.length && !STATE.achievements.has('em_master')){
|
||
addXp(50, 'em-master');
|
||
achievement('em_master');
|
||
}
|
||
return won;
|
||
}
|
||
function renderAll(){
|
||
const cont = document.getElementById('f2-bosses');
|
||
const state = loadState();
|
||
let html = '';
|
||
BOSSES.forEach(b=>{
|
||
const solved = state[b.n];
|
||
html += '<div class="boss-card'+(solved?' solved':'')+'" id="f2-boss-'+b.n+'" style="border:2px solid '+(solved?'#10b981':'var(--border)')+';border-radius:12px;padding:14px;margin-bottom:10px;background:var(--card)">'
|
||
+'<div style="display:flex;gap:10px;align-items:center;margin-bottom:8px"><span style="font-family:Unbounded,sans-serif;font-size:.7rem;font-weight:800;padding:3px 8px;border-radius:99px;background:var(--sec-acc-soft);color:var(--sec-acc-d);text-transform:uppercase">Босс '+b.n+'</span><span style="font-weight:700">'+b.title+'</span></div>'
|
||
+'<div style="padding:10px 12px;background:rgba(15,23,42,.04);border-radius:8px;margin-bottom:8px;font-size:.94rem;line-height:1.5">'+b.q+'</div>'
|
||
+'<div class="boss-row">'
|
||
+'<input type="number" step="'+b.step+'" class="tinp" id="f2-b'+b.n+'-inp" placeholder="число" style="width:140px"'+(solved?' value="'+b.ans+'" disabled':'')+'>'
|
||
+'<button class="btn primary" id="f2-b'+b.n+'-go"'+(solved?' disabled':'')+'>Атаковать</button>'
|
||
+'<button class="btn" id="f2-b'+b.n+'-hint">Подсказка</button>'
|
||
+'</div>'
|
||
+'<div class="boss-hint-txt" id="f2-b'+b.n+'-ht" style="margin-top:8px;padding:9px 13px;background:rgba(245,158,11,.12);border-left:3px solid #f59e0b;border-radius:6px;font-size:.86rem;display:none;line-height:1.5">'+b.hint+'</div>'
|
||
+'<div class="feedback'+(solved?' ok':'')+'" id="f2-b'+b.n+'-fb" style="display:'+(solved?'block':'none')+'">'+(solved?'✓ Победа! +10 XP. Босс повержен.':'')+'</div>'
|
||
+'</div>';
|
||
});
|
||
cont.innerHTML = html;
|
||
BOSSES.forEach(b=>{
|
||
const go = document.getElementById('f2-b'+b.n+'-go');
|
||
const inp = document.getElementById('f2-b'+b.n+'-inp');
|
||
const fb = document.getElementById('f2-b'+b.n+'-fb');
|
||
const ht = document.getElementById('f2-b'+b.n+'-ht');
|
||
const hintBtn = document.getElementById('f2-b'+b.n+'-hint');
|
||
if(hintBtn) hintBtn.addEventListener('click', ()=>{ ht.style.display = ht.style.display==='block'?'none':'block'; });
|
||
if(!go || go.disabled) return;
|
||
go.addEventListener('click', ()=>{
|
||
const v = parseFloat((inp.value || '').replace(',','.'));
|
||
if(isNaN(v)){ fb.style.display='block'; fb.className='feedback fail'; fb.innerHTML='Введите число.'; return; }
|
||
if(Math.abs(v - b.ans) < b.tol){
|
||
fb.style.display='block'; fb.className='feedback ok'; fb.innerHTML='✓ Победа! +10 XP. '+b.hint;
|
||
go.disabled = true; inp.disabled = true;
|
||
document.getElementById('f2-boss-'+b.n).classList.add('solved');
|
||
const s = loadState();
|
||
if(!s[b.n]){ s[b.n]=true; saveState(s); addXp(10,'f2-boss-'+b.n); bumpProgress('final2', 12); }
|
||
updateBar();
|
||
renderMath(fb);
|
||
} else {
|
||
fb.style.display='block'; fb.className='feedback fail'; fb.innerHTML='✗ Не то. Перепроверь и попробуй снова.';
|
||
}
|
||
});
|
||
inp.addEventListener('keydown', e=>{ if(e.key === 'Enter') go.click(); });
|
||
});
|
||
renderMath(cont);
|
||
updateBar();
|
||
}
|
||
renderAll();
|
||
}
|
||
|
||
function init(){
|
||
loadProgress(); initTheme(); initSidebarToggle(); initSearch();
|
||
buildParaSelector(); refreshProgressUI(); loadServerReadState(); goTo(PARAS[0].id);
|
||
setTimeout(()=>achievement('start'), 600);
|
||
if(window.LS&&window.LS.xp){
|
||
window.LS.xp.load().then(function(s){ if(s&&s.xp>STATE.xp){ STATE.xp=s.xp; STATE.level=calcLevel(STATE.xp); saveProgress(); refreshProgressUI(); if(STATE.current) buildSidebar(STATE.current); } });
|
||
}
|
||
}
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
|
||
</script>
|
||
|
||
|
||
<script>
|
||
/* P8 hero meter — анимированный ток (Phase 2 electric) */
|
||
(function(){
|
||
function init(){
|
||
const el = document.getElementById('p8-meter-val');
|
||
if (!el || !window.P8Anim) return;
|
||
const targets = [0.5, 2.0, 1.2, 0.8, 1.5];
|
||
let i = 0;
|
||
function step(){
|
||
const from = parseFloat(el.textContent) || 0;
|
||
const to = targets[i % targets.length];
|
||
P8Anim.tween({
|
||
from, to, duration: 1200, easing: 'cubicInOut',
|
||
onUpdate: v => { el.textContent = v.toFixed(1); },
|
||
onComplete: () => { i++; setTimeout(step, 1500); }
|
||
});
|
||
}
|
||
setTimeout(step, 1200);
|
||
}
|
||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
||
else init();
|
||
})();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|