073cc3c06d
§21 Электрическая цепь: - 3 теории: элементы цепи, амперметр/вольтметр, схема - IV-1: интерактивная цепь с батареей, лампой, амперметром (последовательно), вольтметром (параллельно лампе) и ключом; при замыкании ключа лампа загорается и приборы показывают значения - IV-2: 6 вопросов «как включать прибор?» - IV-3: DnD 8 утверждений «правильно/неправильно» - IV-4: 6 MCQ §22 Закон Ома: - 3 теории: I=U/R, выводы (U=IR, R=U/I), ВАХ - IV-1: ВАХ-плоттер — slider R 2-50 Ом, динамическая прямая I(U) с подписью наклона - IV-2: калькулятор U+R → I с «бытовой аналогией» - IV-3: 5 концептуальных вопросов - IV-4: 6 числовых задач Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3217 lines
247 KiB
HTML
3217 lines
247 KiB
HTML
<!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">
|
||
<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/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(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>
|
||
|
||
<header class="hdr">
|
||
<div class="hdr-row">
|
||
<div>
|
||
<h1>Физика 8 · Глава 2</h1>
|
||
<div class="hdr-sub">Электризация · ток · закон Ома · магнитное поле</div>
|
||
</div>
|
||
<div class="hdr-side">
|
||
<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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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 пройдена!"
|
||
};
|
||
|
||
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:[["В разработке","Phase 3 Wave 3"]]},
|
||
p24:{title:"Шпаргалка § 24",rows:[["В разработке","Phase 3 Wave 3"]]},
|
||
p25:{title:"Шпаргалка § 25",rows:[["В разработке","Phase 3 Wave 3"]]},
|
||
p26:{title:"Шпаргалка § 26",rows:[["В разработке","Phase 3 Wave 4"]]},
|
||
p27:{title:"Шпаргалка § 27",rows:[["В разработке","Phase 3 Wave 4"]]},
|
||
p28:{title:"Шпаргалка § 28",rows:[["В разработке","Phase 4 Wave 1"]]},
|
||
p29:{title:"Шпаргалка § 29",rows:[["В разработке","Phase 4 Wave 1"]]},
|
||
p30:{title:"Шпаргалка § 30",rows:[["В разработке","Phase 4 Wave 2"]]},
|
||
p31:{title:"Шпаргалка § 31",rows:[["В разработке","Phase 4 Wave 2"]]},
|
||
final2:{title:"Шпаргалка ★",rows:[["В разработке","Phase 4 Wave 2"]]}
|
||
};
|
||
|
||
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:"Параграф § 23 будет реализован в Phase 3 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p24',html:"Параграф § 24 будет реализован в Phase 3 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p25',html:"Параграф § 25 будет реализован в Phase 3 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p26',html:"Параграф § 26 будет реализован в Phase 3 Wave 4. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p27',html:"Параграф § 27 будет реализован в Phase 3 Wave 4. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p28',html:"Параграф § 28 будет реализован в Phase 4 Wave 1. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p29',html:"Параграф § 29 будет реализован в Phase 4 Wave 1. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p30',html:"Параграф § 30 будет реализован в Phase 4 Wave 2. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'p31',html:"Параграф § 31 будет реализован в Phase 4 Wave 2. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
|
||
{sec:'final2',html:"Параграф ★ будет реализован в Phase 4 Wave 2. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."}
|
||
];
|
||
|
||
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: ()=>{ const box=document.getElementById('p23-body'); box.innerHTML = buildStub('p23', 'Единица сопротивления. Расчёт сопротивления', 'Phase 3 Wave 3') + secNavFor('p23') + readButton('p23'); renderMath(box); wireReadBtn('p23'); },
|
||
p24: ()=>{ const box=document.getElementById('p24-body'); box.innerHTML = buildStub('p24', 'Последовательное соединение проводников. Реостат', 'Phase 3 Wave 3') + secNavFor('p24') + readButton('p24'); renderMath(box); wireReadBtn('p24'); },
|
||
p25: ()=>{ const box=document.getElementById('p25-body'); box.innerHTML = buildStub('p25', 'Параллельное соединение проводников', 'Phase 3 Wave 3') + secNavFor('p25') + readButton('p25'); renderMath(box); wireReadBtn('p25'); },
|
||
p26: ()=>{ const box=document.getElementById('p26-body'); box.innerHTML = buildStub('p26', 'Работа и мощность электрического тока. Закон Джоуля — Ленца', 'Phase 3 Wave 4') + secNavFor('p26') + readButton('p26'); renderMath(box); wireReadBtn('p26'); },
|
||
p27: ()=>{ const box=document.getElementById('p27-body'); box.innerHTML = buildStub('p27', 'Использование и экономия электроэнергии. Безопасность', 'Phase 3 Wave 4') + secNavFor('p27') + readButton('p27'); renderMath(box); wireReadBtn('p27'); },
|
||
p28: ()=>{ const box=document.getElementById('p28-body'); box.innerHTML = buildStub('p28', 'Постоянные магниты', 'Phase 4 Wave 1') + secNavFor('p28') + readButton('p28'); renderMath(box); wireReadBtn('p28'); },
|
||
p29: ()=>{ const box=document.getElementById('p29-body'); box.innerHTML = buildStub('p29', 'Магнитное поле', 'Phase 4 Wave 1') + secNavFor('p29') + readButton('p29'); renderMath(box); wireReadBtn('p29'); },
|
||
p30: ()=>{ const box=document.getElementById('p30-body'); box.innerHTML = buildStub('p30', 'Магнитное поле тока', 'Phase 4 Wave 2') + secNavFor('p30') + readButton('p30'); renderMath(box); wireReadBtn('p30'); },
|
||
p31: ()=>{ const box=document.getElementById('p31-body'); box.innerHTML = buildStub('p31', 'Магнитное поле прямого проводника и катушки с током. Электромагнит', 'Phase 4 Wave 2') + secNavFor('p31') + readButton('p31'); renderMath(box); wireReadBtn('p31'); },
|
||
final2: ()=>{ const box=document.getElementById('final2-body'); box.innerHTML = buildStub('final2', 'Финал главы', 'Phase 4 Wave 2') + secNavFor('final2') + readButton('final2'); renderMath(box); wireReadBtn('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>';
|
||
|
||
box.innerHTML = h + secNavFor('p12') + readButton('p12');
|
||
renderMath(box);
|
||
wireReadBtn('p12');
|
||
|
||
_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>';
|
||
|
||
box.innerHTML = h + secNavFor('p13') + readButton('p13');
|
||
renderMath(box);
|
||
wireReadBtn('p13');
|
||
|
||
_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>';
|
||
|
||
box.innerHTML = h + secNavFor('p14') + readButton('p14');
|
||
renderMath(box);
|
||
wireReadBtn('p14');
|
||
|
||
_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>';
|
||
|
||
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>';
|
||
|
||
box.innerHTML = h + secNavFor('p16') + readButton('p16');
|
||
renderMath(box);
|
||
wireReadBtn('p16');
|
||
|
||
_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>';
|
||
|
||
box.innerHTML = h + secNavFor('p17') + readButton('p17');
|
||
renderMath(box);
|
||
wireReadBtn('p17');
|
||
|
||
_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>';
|
||
|
||
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>';
|
||
|
||
box.innerHTML = h + secNavFor('p19') + readButton('p19');
|
||
renderMath(box);
|
||
wireReadBtn('p19');
|
||
|
||
_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>';
|
||
|
||
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>';
|
||
|
||
box.innerHTML = h + secNavFor('p21') + readButton('p21');
|
||
renderMath(box);
|
||
wireReadBtn('p21');
|
||
|
||
_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>';
|
||
|
||
box.innerHTML = h + secNavFor('p22') + readButton('p22');
|
||
renderMath(box);
|
||
wireReadBtn('p22');
|
||
|
||
_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();
|
||
}
|
||
|
||
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>
|
||
|
||
</body>
|
||
</html>
|