Files
Learn_System/frontend/textbooks/algebra_10_ch3.html
T

1546 lines
106 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>Алгебра 10 · Глава 3 · Производная</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/alg10_svg.js?v=1" 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:#f0fdf4; --card:#fff; --card-soft:#f7fcf8; --text:#0f1f15; --muted:#4b6b58;
--border:#dcfce7; --sh:0 1px 3px rgba(0,0,0,.06); --sh2:0 4px 14px rgba(0,0,0,.08);
--pri:#059669; --pri2:#047857; --pri-soft:#d1fae5;
--acc:#10b981; --acc2:#059669; --acc-soft:#86efac;
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
}
.dark{--bg:#03180e; --card:#0a2418; --card-soft:#0e2c1e; --text:#dcfce7; --muted:#86b89e; --border:#1d4232}
*{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,#064e3b 0%,#059669 55%,#86efac 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(220,252,231,.2);min-height:130px}
.hdr::before{content:'ГЛАВА 3';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(5rem,15vw,11rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(220,252,231,.12);line-height:1;pointer-events:none;z-index:0}
.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::before{content:"f'(x)";position:absolute;right:-10px;top:-20px;font-size:clamp(2rem,8vw,5.5rem);font-weight:900;color:var(--pri);opacity:.10;line-height:1;pointer-events:none;font-family:'Unbounded',sans-serif}
.hero h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px}
.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)}
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(5,150,105,.32)}
.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(5,150,105,.18);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;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(170px,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(5,150,105,.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,#fff5e1,#fef3c7)}
.sec[id="sec-p18"] { --sec-acc:#059669; --sec-acc-d:#047857; --sec-acc-soft:#d1fae5; }
.sec[id="sec-p19"] { --sec-acc:#0d9488; --sec-acc-d:#0f766e; --sec-acc-soft:#ccfbf1; }
.sec[id="sec-p20"] { --sec-acc:#16a34a; --sec-acc-d:#15803d; --sec-acc-soft:#dcfce7; }
.sec[id="sec-p21"] { --sec-acc:#22c55e; --sec-acc-d:#16a34a; --sec-acc-soft:#dcfce7; }
.sec[id="sec-p22"] { --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#d1fae5; }
.sec[id="sec-final3"]{ --sec-acc:#059669; --sec-acc-d:#047857; --sec-acc-soft:#d1fae5; }
.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::before{content:attr(data-watermark);position:absolute;right:-20px;top:10%;font-family:'Unbounded',sans-serif;font-size:clamp(6rem,18vw,14rem);font-weight:900;color:transparent;-webkit-text-stroke:1.5px var(--sec-acc-soft,var(--pri-soft));line-height:1;pointer-events:none;z-index:0;opacity:.35}
.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.5rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));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(5,150,105,.06);position:relative;z-index:1}
.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.theory{background:#8b5cf6}.card-icon.rule{background:#ec4899}.card-icon.algo{background:#f59e0b}.card-icon.example{background:#10b981}
.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}
.wg{background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)));border:1.5px solid var(--sec-acc,var(--pri));border-radius:14px;padding:18px 20px;margin-bottom:18px;box-shadow:var(--sh2);position:relative;z-index:1}
.wg-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.wg-badge{padding:4px 9px;background:var(--sec-acc,var(--pri));color:#fff;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
.wg-title{font-family:'Unbounded',sans-serif;font-size:1.05rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));flex:1}
.wg-help{font-size:.88rem;color:var(--text);margin-bottom:12px;line-height:1.55;background:linear-gradient(135deg,var(--warn-bg,#fef3c7),var(--sec-acc-soft,var(--pri-soft)));border-left:4px solid var(--warn,#f59e0b);padding:9px 14px;border-radius:9px}
.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}
.btn:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
.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))}
.tinp{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);font-family:'JetBrains Mono',monospace}
.tinp:focus{outline:0;border-color:var(--sec-acc,var(--pri));box-shadow:0 0 0 3px var(--sec-acc-soft,var(--pri-soft))}
.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}
@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(5,150,105,.18);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}
.spoiler{border:1px solid var(--border);border-radius:10px;background:var(--card);margin:10px 0;overflow:hidden}
.spoiler summary{padding:8px 14px;background:var(--sec-acc-soft,var(--pri-soft));font-weight:700;cursor:pointer;font-size:.88rem;color:var(--sec-acc-d,var(--pri2));list-style:none;display:flex;align-items:center;gap:8px}
.spoiler summary::-webkit-details-marker{display:none}
.spoiler summary::before{content:'+';font-size:1.2rem;font-weight:900;color:var(--sec-acc,var(--pri));width:18px}
.spoiler[open] summary::before{content:'\2212'}
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
.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,#059669,#10b981);color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(5,150,105,.45);z-index:1002;display:none;align-items:center;gap:8px;max-width:340px}
.ach-popup.show{display:flex}
.score-display{display:flex;gap:14px;flex-wrap:wrap;align-items:center;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-bottom:12px}
.score-display b{color:var(--sec-acc-d,var(--pri2));font-size:1.15rem}
.hp-boss{height:14px;background:rgba(220,38,38,.12);border-radius:9px;overflow:hidden;border:1px solid #fecaca;margin:8px 0}
.hp-boss-fill{height:100%;background:linear-gradient(90deg,#dc2626,#f59e0b);border-radius:9px;transition:width .5s cubic-bezier(.4,0,.2,1)}
.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}
}
.boss-card{padding:16px;background:var(--card);border-radius:12px;border:2px solid var(--bad,#dc2626);margin-bottom:14px}
.boss-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.boss-title{font-family:'Unbounded',sans-serif;font-weight:800;color:#7f1d1d;font-size:1.04rem;flex:1}
.boss-stage{font-size:.85rem;color:var(--muted)}
.boss-q{font-size:1rem;line-height:1.55;padding:11px 13px;background:var(--card-soft);border-radius:8px;margin-bottom:9px;border-left:3px solid var(--bad,#dc2626)}
.svg-host{display:flex;justify-content:center;margin:12px 0}
.svg-host-row{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:12px 0}
.slider-ctrl{display:flex;align-items:center;gap:10px;background:var(--card);padding:10px 14px;border-radius:10px;border:1px solid var(--border);margin-bottom:12px;flex-wrap:wrap}
.slider-ctrl label{font-size:.86rem;font-weight:700;color:var(--text);min-width:80px}
.slider-ctrl input[type=range]{flex:1;min-width:180px;accent-color:var(--pri)}
.slider-ctrl .val{font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--pri);min-width:80px;text-align:right}
.formula-plate{margin:16px 0;border-radius:14px;overflow:hidden;border:1.5px solid var(--border);box-shadow:0 4px 16px rgba(0,0,0,.04);background:var(--card)}
.formula-plate-head{padding:14px 18px;text-align:center;border-bottom:1px solid var(--border);background:linear-gradient(180deg,rgba(5,150,105,.12),rgba(5,150,105,.06))}
.formula-plate-title{font-family:'Unbounded',sans-serif;font-size:1.02rem;font-weight:800;letter-spacing:.04em;margin-bottom:4px;text-transform:uppercase;color:#047857}
.formula-plate-sub{font-size:.84rem;font-style:italic;color:var(--muted);line-height:1.4}
.formula-plate-body{padding:14px 22px}
.formula-row{padding:9px 4px;font-size:1.08rem;text-align:center;line-height:1.5;border-bottom:1px dashed rgba(0,0,0,.05)}
.formula-row:last-child{border-bottom:0}
.formula-row.alt{color:#0891b2}
.formula-row.danger{color:#dc2626}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-row">
<div>
<h1>Алгебра 10 · Глава 3</h1>
<div class="hdr-sub">Производная функции · правила вычисления · касательная · исследование функций</div>
</div>
<div class="hdr-side">
<a href="/textbook/algebra-10" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К Алгебре 10</a>
<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>Когда автомобиль едет, спидометр показывает его <b>мгновенную скорость</b> — производную пути по времени. В математике <b>производная функции</b> $f'(x)$ показывает, как быстро $f$ растёт или падает в каждой точке. На графике производная — это <b>тангенс угла наклона касательной</b>.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p18')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 18</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-p18" class="sec" data-watermark="Δf/Δx"><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" data-watermark="(uv)'"><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" data-watermark="↗"><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" data-watermark="∪∩"><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" data-watermark="&#9733;"><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-final3" class="sec" data-watermark="&#9733;"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#059669,#86efac)">Финал главы</span><h2 class="sec-h">Итоги. 5 боссов главы 3</h2></div><div id="final3-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">Интерактивный учебник «Алгебра — 10 класс» · Глава 3 · Производная · 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>
<script>
'use strict';
const STATE = { current:'p18', progress:{p18:0,p19:0,p20:0,p21:0,p22:0,final3:0}, achievements:new Map(), xp:0, level:1 };
const TOTAL_PARAS = 6;
const _TB_SLUG = 'algebra-10-ch3';
function calcLevel(xp){ return Math.floor(Math.sqrt((xp||0)/100))+1; }
function _xpForLevel(lv){ return (lv-1)*(lv-1)*100; }
const ACH_LABELS = {
start:'Начало главы 3!',
p18_done:'Определение производной — освоено!',
p19_done:'Правила вычисления — знаешь!',
p20_done:'Касательная и монотонность — твои!',
p21_done:'Исследование функций — мастер!',
p22_done:'Наиб./наим. значения — освоены!',
ch3_done:'Глава 3 — Производная пройдена!',
deriv_master:'Магистр производных! +150 XP',
alg10_master:'&#9733; Алгебра 10 пройдена полностью!',
};
function loadProgress(){
try{
const s=localStorage.getItem('algebra10_ch3_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
const a=localStorage.getItem('algebra10_ch3_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('algebra10_xp')||0); STATE.level=calcLevel(STATE.xp);
}catch(e){}
}
function saveProgress(){
try{
localStorage.setItem('algebra10_ch3_progress', JSON.stringify(STATE.progress));
localStorage.setItem('algebra10_ch3_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
localStorage.setItem('algebra10_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);
if(STATE.progress[key]>=100){
if(key==='p18') achievement('p18_done');
else if(key==='p19') achievement('p19_done');
else if(key==='p20') achievement('p20_done');
else if(key==='p21') achievement('p21_done');
else if(key==='p22') achievement('p22_done');
else if(key==='final3') achievement('ch3_done');
}
}
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 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,'algebra10-ch3-'+(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);
}
const PARAS = [
{ id:'p18', num:'§ 18', name:'Определение производной', sub:'через предел' },
{ id:'p19', num:'§ 19', name:'Правила вычисления', sub:'сумма, произв., степень' },
{ id:'p20', num:'§ 20', name:'Касательная, монотонность', sub:'геом. смысл' },
{ id:'p21', num:'§ 21', name:'Исследование функций', sub:'экстремумы' },
{ id:'p22', num:'§ 22', name:'Наиб. и наим. значения', sub:'на отрезке' },
{ id:'final3', num:'&#9733;', name:'Финал главы', sub:'5 боссов', final:true },
];
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);
});
if(window.renderMathInElement) try{ renderMath(g); }catch(e){}
}
const BUILT=new Set();
const BUILDERS = { p18:()=>buildP18(), p19:()=>buildP19(), p20:()=>buildP20(), p21:()=>buildP21(), p22:()=>buildP22(), final3:()=>buildFinal3() };
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);
}
const SIDEBARS = {
p18:{title:'Шпаргалка §18',rows:[
['Опр.','$f\'(x_0) = \\lim\\limits_{\\Delta x \\to 0} \\dfrac{\\Delta f}{\\Delta x}$'],
['$\\Delta f$','$= f(x_0 + \\Delta x) - f(x_0)$'],
['$\\Delta x$','приращение аргумента'],
['$(x^2)\'$','$= 2x$'],
['$(kx+b)\'$','$= k$'],
['$(1/x)\'$','$= -1/x^2$'],
['$C\'$','$= 0$ (константа)'],
['Физ. смысл','мгновенная скорость'],
]},
p19:{title:'Шпаргалка §19',rows:[
['$(U+V)\'$','$= U\' + V\'$'],
['$(UV)\'$','$= U\'V + UV\'$'],
['$(U/V)\'$','$= (U\'V - UV\')/V^2$'],
['$(C\\cdot U)\'$','$= C \\cdot U\'$'],
['$(x^n)\'$','$= n \\cdot x^{n-1}$'],
['Пример','$(x^5)\' = 5x^4$'],
]},
p20:{title:'Шпаргалка §20',rows:[
['Геом. смысл','$f\'(x_0) = \\tg\\alpha$'],
['','угол $\\alpha$ — между касат. и осью x'],
['Касательная','$y = f(x_0) + f\'(x_0)(x - x_0)$'],
['$f\' > 0$ на $I$','$f$ возрастает на $I$'],
['$f\' < 0$ на $I$','$f$ убывает на $I$'],
['$f\' = 0$','критические точки'],
]},
p21:{title:'Шпаргалка §21',rows:[
['Крит. точка','где $f\'(x) = 0$ или $f\'$ не существует'],
['Точка max','$f\'$ меняет знак с + на −'],
['Точка min','$f\'$ меняет знак с − на +'],
['Перегиб','знак $f\'$ не меняется'],
['Алгоритм','5 шагов: $D$, $f\'$, нули, знаки, экстр.'],
]},
p22:{title:'Шпаргалка §22',rows:[
['На $[a;b]$','3 шага: $f\'$, крит. точки, значения'],
['Где искать','концы $a, b$ + крит. точки внутри'],
['Сравни','выбери наиб. и наим.'],
['Если нет крит. на $[a;b]$','берём только концы'],
]},
final3:{title:'Финал главы 3',rows:[
['Боссов','5 — все темы главы'],
['Босс 1','§18 определение, базовые формулы'],
['Босс 2','§19 правила (сумма, произв., степень)'],
['Босс 3','§20 касательная, монотонность'],
['Босс 4','§21 экстремумы'],
['Босс 5','§22 наиб./наим. + сборная'],
['Награда','+150 XP + «Магистр производных»'],
]},
};
const TIPS=[
{sec:'p18',html:'Производная — это <b>предел отношения</b> приращения функции к приращению аргумента. Геометрически — наклон секущей в пределе становится наклоном касательной.'},
{sec:'p19',html:'Самое полезное правило: <b>$(x^n)\' = n \\cdot x^{n-1}$</b>. Применяй ко всем степеням x, включая отрицательные и дробные.'},
{sec:'p20',html:'<b>Уравнение касательной</b> через точку $(x_0; f(x_0))$ с угловым коэффициентом $f\'(x_0)$: $y = f(x_0) + f\'(x_0)(x - x_0)$.'},
{sec:'p21',html:'<b>Алгоритм исследования:</b> найди $D(f)$ → вычисли $f\'(x)$ → найди нули $f\'$ (критические точки) → определи знаки $f\'$ между ними → выпиши экстремумы.'},
{sec:'p22',html:'Для отрезка <b>$[a; b]$</b> наиб. и наим. значения функции — среди значений в концах ($a$ и $b$) и в критических точках, лежащих внутри.'},
{sec:'final3',html:'5 интегрированных боссов проверяют синтез знаний всей главы. После победы — ачивка <b>«Магистр производных»</b> и +150 XP. А ещё — особая ачивка <b>«Алгебра 10 пройдена»</b>, если ты уже завершил Главы 1 и 2!'},
];
function buildSidebar(id){
const box=document.getElementById('sidebar-content');
const sb=SIDEBARS[id]||SIDEBARS.p18;
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?' — '+v:'')+'</div>'; });
html+='</div>';
const tip=TIPS.find(t=>t.sec===id)||TIPS[0];
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">Подсказка</h4><div class="sidecard-row" style="font-size:.84rem;line-height:1.55">'+tip.html+'</div></div>';
if(STATE.achievements.size>0){
html+='<div class="sidecard"><h4>Достижения</h4>';
[...STATE.achievements.values()].slice(-4).forEach(text=>{ html+='<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">&#10003; '+text+'</div>'; });
html+='</div>';
}
box.innerHTML=html;
if(window.renderMathInElement) try{ renderMath(box); }catch(e){}
}
function initTheme(){
const t=localStorage.getItem('algebra10_ch3_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('algebra10_ch3_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?'&#10003; Верно!':'&#10007; Неверно'); elm.style.display='block'; try{renderMath(elm);}catch(e){} }
const ICONS = {
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>',
};
function makeCard(kind, title, num, body){
const labels={theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример'};
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>';
}
function secNav(prev, next){
const NAMES={p18:'§18',p19:'§19',p20:'§20',p21:'§21',p22:'§22',final3:'Финал'};
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> '+NAMES[prev]+'</button>':'<span></span>';
h+=next?'<button class="btn primary" onclick="goTo(\''+next+'\')">'+NAMES[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 makeTrainer(opts){
let i=0, score=0;
const Q=opts.questions;
const parser = opts.parser || (v => parseFloat(String(v).replace(',','.')));
function show(){
if(i >= Q.length){
document.getElementById(opts.idPrefix+'-q').innerHTML = '<b>Готово!</b> Результат: '+score+' / '+Q.length;
if(opts.onComplete) opts.onComplete(score, Q.length);
return;
}
document.getElementById(opts.idPrefix+'-i').textContent = (i+1);
document.getElementById(opts.idPrefix+'-s').textContent = score;
document.getElementById(opts.idPrefix+'-q').innerHTML = Q[i].q;
document.getElementById(opts.idPrefix+'-ans').value = '';
renderMath(document.getElementById(opts.idPrefix+'-q'));
document.getElementById(opts.idPrefix+'-fb').style.display = 'none';
}
function go(){
if(i >= Q.length) return;
const fb = document.getElementById(opts.idPrefix+'-fb');
const raw = document.getElementById(opts.idPrefix+'-ans').value.trim();
if(raw === ''){ feedback(fb, false, '&#10007; Введи ответ.'); return; }
const expected = Q[i].a;
let ok = false;
if(typeof expected === 'function') ok = expected(raw);
else { const got = parser(raw); ok = !isNaN(got) && Math.abs(got - expected) < 1e-6; }
if(ok){ score++; feedback(fb, true, '&#10003; Верно! Дальше ▶'); }
else feedback(fb, false, '&#10007; Неверно. Правильно: <b>'+(Q[i].show||expected)+'</b>. Дальше ▶');
document.getElementById(opts.idPrefix+'-s').textContent = score;
i++; setTimeout(show, 1100);
}
document.getElementById(opts.idPrefix+'-go').addEventListener('click', go);
document.getElementById(opts.idPrefix+'-ans').addEventListener('keydown', e=>{ if(e.key==='Enter') go(); });
const restart = document.getElementById(opts.idPrefix+'-start');
if(restart) restart.addEventListener('click', ()=>{ i=0; score=0; show(); });
show();
}
function trainerHTML(idPrefix, total, placeholder){
return '<div class="score-display"><span>Задача <b id="'+idPrefix+'-i">1</b> / '+total+'</span><span>Очки: <b id="'+idPrefix+'-s">0</b> / '+total+'</span></div>'
+'<div id="'+idPrefix+'-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.05rem;margin-bottom:10px;text-align:center"></div>'
+'<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">'
+'<input type="text" id="'+idPrefix+'-ans" class="tinp" placeholder="'+(placeholder||'Ответ')+'" style="width:140px;text-align:center">'
+'<button class="btn primary" id="'+idPrefix+'-go">Проверить</button>'
+'<button class="btn" id="'+idPrefix+'-start">Заново</button>'
+'</div><div class="feedback" id="'+idPrefix+'-fb"></div>';
}
function makeBoss(paraId, bossDef){
const idP = paraId+'-boss';
const SKEY = 'algebra10_ch3_'+paraId+'_boss';
let st = {stage:0, defeated:false};
try{ const s=localStorage.getItem(SKEY); if(s) st=JSON.parse(s); }catch(e){}
const html = '<div class="boss-card" style="border-color:'+bossDef.color+'">'
+'<div class="boss-head">'
+'<svg viewBox="0 0 24 24" fill="none" stroke="'+bossDef.color+'" stroke-width="2.2" style="width:28px;height:28px"><polygon points="12,2 22,20 2,20"/></svg>'
+'<div class="boss-title" style="color:'+bossDef.color+'">'+bossDef.title+'</div>'
+'<div class="boss-stage" id="'+idP+'-stage">Этап 1 / '+bossDef.steps.length+'</div>'
+'</div>'
+'<div class="hp-boss" style="border-color:'+bossDef.color+'66;background:'+bossDef.color+'1a"><div class="hp-boss-fill" id="'+idP+'-fill" style="width:0%;background:linear-gradient(90deg,'+bossDef.color+',#f59e0b)"></div></div>'
+'<div class="boss-q" id="'+idP+'-q" style="border-color:'+bossDef.color+'"></div>'
+'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">'
+'<input type="text" id="'+idP+'-input" class="tinp" placeholder="Ответ" style="width:160px;text-align:center">'
+'<button class="btn primary" id="'+idP+'-go" style="background:'+bossDef.color+';border-color:'+bossDef.color+'">Атака</button>'
+'<button class="btn" id="'+idP+'-hint">Подсказка</button>'
+'<button class="btn" id="'+idP+'-restart">↻</button>'
+'</div>'
+'<div class="feedback" id="'+idP+'-fb"></div>'
+'</div>';
setTimeout(()=>{
function save(){ try{ localStorage.setItem(SKEY, JSON.stringify(st)); }catch(e){} }
function show(){
const stageEl=document.getElementById(idP+'-stage');
const fill=document.getElementById(idP+'-fill');
const q=document.getElementById(idP+'-q');
const fb=document.getElementById(idP+'-fb');
if(st.defeated){
stageEl.innerHTML='&#10003; Побеждён'; fill.style.width='100%';
q.innerHTML='<b style="color:'+bossDef.color+'">Босс повержен!</b>';
document.getElementById(idP+'-go').disabled=true;
document.getElementById(idP+'-go').style.opacity=.5;
return;
}
stageEl.textContent='Этап '+(st.stage+1)+' / '+bossDef.steps.length;
fill.style.width=(st.stage*100/bossDef.steps.length)+'%';
q.innerHTML=bossDef.steps[st.stage].q;
document.getElementById(idP+'-input').value='';
fb.style.display='none';
renderMath(q);
}
document.getElementById(idP+'-go').addEventListener('click',()=>{
if(st.defeated) return;
const step=bossDef.steps[st.stage];
const val=document.getElementById(idP+'-input').value;
const fb=document.getElementById(idP+'-fb');
if(!val.trim()){ feedback(fb,false,'&#10007; Введи ответ.'); return; }
if(step.verify(val)){
st.stage++;
if(st.stage>=bossDef.steps.length){
st.defeated=true; save();
feedback(fb,true,'&#10003; Босс повержен! +20 XP');
addXp(20,paraId+'-boss'); bumpProgress(paraId, 30);
setTimeout(show,1400);
}else{
save(); feedback(fb,true,'&#10003; Верно! +3 XP'); addXp(3,paraId+'-boss-step'); setTimeout(show,1100);
}
}else{ feedback(fb,false,'&#10007; Промах.'); }
});
document.getElementById(idP+'-hint').addEventListener('click',()=>{
if(st.defeated) return;
const fb=document.getElementById(idP+'-fb');
fb.className='feedback ok';
fb.innerHTML='<span style="color:#92400e">\u{1F4A1} Подсказка:</span> '+bossDef.steps[st.stage].hint;
fb.style.display='block';
fb.style.background='var(--warn-bg)'; fb.style.color='#92400e'; fb.style.borderLeftColor='var(--warn)';
renderMath(fb);
});
document.getElementById(idP+'-restart').addEventListener('click',()=>{
st={stage:0,defeated:false}; save();
document.getElementById(idP+'-go').disabled=false;
document.getElementById(idP+'-go').style.opacity=1;
show();
});
show();
}, 0);
return html;
}
function readButton(paraId){
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>'
+' Я прочитал §'+paraId.replace('p','').replace('final','финал ')+' (+10 XP)'
+'</button></div>';
}
function wireReadBtn(paraId){
document.getElementById(paraId+'-read-btn').addEventListener('click', ()=>{
addXp(10, paraId+'-read'); bumpProgress(paraId, 30);
const b=document.getElementById(paraId+'-read-btn'); b.textContent='Прочитано! +10 XP'; b.disabled=true; b.style.opacity=.6;
});
}
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(); });
}
function init(){
loadProgress(); initTheme(); initSidebarToggle();
buildParaSelector(); refreshProgressUI(); goTo('p18');
setTimeout(()=>achievement('start','Начало главы 3!'), 600);
}
document.addEventListener('DOMContentLoaded', init);
/* ============================================================
§ 18 — Определение производной функции
============================================================ */
function buildP18(){
const box = document.getElementById('p18-body');
const A = window.ALG10;
let html = '';
/* === SVG: секущая → касательная (с слайдером Δx) === */
let svgSecant = '';
if(A){
const f = A.func.canvas({id:'p18-sec', W:560, H:280, xRange:[-1, 3.5], yRange:[-1, 8], bg:'#fff'});
let s = f.open
+ f.grid({xStep:1, yStep:1, color:'#f1f5f9'})
+ f.axes({color:'#475569', xTicks:[{val:1,label:'1'},{val:2,label:'2'},{val:3,label:'3'}], yTicks:[{val:2,label:'2'},{val:4,label:'4'},{val:6,label:'6'}]})
+ f.plot(x => x*x, {color:'#059669', width:2.8})
/* Точка M(1, 1) */
+ f.pointXY(1, 1, {color:'#dc2626', r:5, label:'M', dx:-15, dy:-8, fontSize:13})
/* Точка N — будет двигаться слайдером */
+ '<g id="p18-sec-dyn"></g>'
+ f.close;
svgSecant = s;
}
html += makeCard('theory', 'От средней скорости — к мгновенной', '18.1', `
<p>Машина за 2 часа проехала 120 км. Её <b>средняя скорость</b>: $60$ км/ч.</p>
<p>Но в каждую конкретную секунду спидометр показывал <b>что-то другое</b> — где-то стояли в пробке, где-то ехали 90 км/ч.</p>
<p>Идея <b>мгновенной скорости</b>: средняя скорость за <b>очень-очень малый</b> промежуток времени. Чем меньше промежуток, тем ближе к мгновенной.</p>
<p>Математически — это <b>предел отношения</b>.</p>`);
html += makeCard('rule', 'Приращение аргумента и функции', '18.2', `
<p>Пусть функция $y = f(x)$ задана. Берём точку $x_0$ и сдвигаемся вправо или влево на $\\Delta x$ (приращение аргумента).</p>
<p>Тогда:</p>
<ul style="padding-left:22px;line-height:1.85">
<li><b>Приращение функции</b>: $\\Delta f = f(x_0 + \\Delta x) - f(x_0)$.</li>
<li><b>Отношение приращений</b>: $\\dfrac{\\Delta f}{\\Delta x}$ — это <b>тангенс наклона секущей</b>, проходящей через точки $M(x_0, f(x_0))$ и $N(x_0 + \\Delta x, f(x_0 + \\Delta x))$.</li>
</ul>
<div class="svg-host">${svgSecant}</div>
<div class="slider-ctrl"><label>Δx:</label><input type="range" id="p18-dx" min="0.05" max="2" step="0.05" value="1.5"><span class="val" id="p18-dxv">1.50</span></div>
<p>Двигай слайдер влево — точка <b>N приближается</b> к M, и секущая постепенно превращается в <b>касательную</b>. Отношение $\\Delta f / \\Delta x$ стремится к производной.</p>`);
html += makeCard('rule', 'Определение производной', '18.3', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b> <b>Производной функции $f$ в точке $x_0$</b> называется предел отношения приращения функции к приращению аргумента, при условии что приращение аргумента стремится к нулю:</p>
<p style="text-align:center;font-size:1.2rem;margin:10px 0">$f'(x_0) = \\lim\\limits_{\\Delta x \\to 0} \\dfrac{\\Delta f}{\\Delta x} = \\lim\\limits_{\\Delta x \\to 0} \\dfrac{f(x_0 + \\Delta x) - f(x_0)}{\\Delta x}$</p>
<p>Если предел существует — функция называется <b>дифференцируемой</b> в точке $x_0$.</p>`);
html += makeCard('algo', 'Алгоритм нахождения производной по определению', '18.4', `
<ol style="padding-left:22px;line-height:1.95">
<li>Найди $f(x_0 + \\Delta x)$.</li>
<li>Вычисли $\\Delta f = f(x_0 + \\Delta x) - f(x_0)$.</li>
<li>Найди отношение $\\dfrac{\\Delta f}{\\Delta x}$.</li>
<li>Упрости его так, чтобы $\\Delta x$ можно было устремить к 0.</li>
<li>Возьми предел при $\\Delta x \\to 0$.</li>
</ol>
<p><b>Пример. Найдём $(x^2)'$.</b></p>
<ol style="padding-left:22px;line-height:1.9">
<li>$f(x + \\Delta x) = (x + \\Delta x)^2 = x^2 + 2x\\Delta x + (\\Delta x)^2$.</li>
<li>$\\Delta f = 2x\\Delta x + (\\Delta x)^2 = \\Delta x(2x + \\Delta x)$.</li>
<li>$\\dfrac{\\Delta f}{\\Delta x} = 2x + \\Delta x$.</li>
<li>При $\\Delta x \\to 0$: $2x + \\Delta x \\to 2x$.</li>
</ol>
<p>Итак, <b>$(x^2)' = 2x$</b>.</p>`);
html += makeCard('example', 'Базовые производные', '18.5', `
<p>По определению можно вывести базовые производные (для 10-го класса):</p>
<table style="width:100%;border-collapse:collapse;margin:8px 0;font-size:.94rem">
<tr style="background:var(--sec-acc-soft)"><th style="padding:6px;border:1px solid var(--border);text-align:left">$f(x)$</th><th style="padding:6px;border:1px solid var(--border);text-align:left">$f'(x)$</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border);text-align:center">$x^2$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$2x$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border);text-align:center">$kx + b$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$k$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\dfrac{1}{x}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$-\\dfrac{1}{x^2}$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border);text-align:center">$C$ (константа)</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$0$</td></tr>
</table>
<p><b>Физический смысл.</b> Если $s(t)$ — путь как функция времени, то $s'(t)$ — <b>мгновенная скорость</b>.</p>`);
/* === ИНТЕРАКТИВ 1: алгоритм === */
html += '<div class="wg" id="p18-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Производная по определению</div></div>'
+'<div class="wg-help">Базовые формулы: $(x^2)\' = 2x$, $(kx+b)\' = k$, $(C)\' = 0$, $(1/x)\' = -1/x^2$.</div>'
+trainerHTML('p18-iv1', 6, 'значение или выражение')
+'</div>';
/* === ИНТЕРАКТИВ 2: скорость === */
html += '<div class="wg" id="p18-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Мгновенная скорость</div></div>'
+'<div class="wg-help">$v_{\\text{мгн}}(t_0) = s\'(t_0)$. Сначала найди $s\'(t)$, потом подставь $t_0$.</div>'
+trainerHTML('p18-iv2', 5, 'число')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §18 — Определение производной</h3>';
html += makeBoss('p18', {
color:'#059669',
title:'Босс §18 — Определение производной',
steps:[
{ q:'Чему равно $\\dfrac{\\Delta f}{\\Delta x}$ при $\\Delta x \\to 0$? Это $\\ldots$', verify:(v)=>{const s=String(v).replace(/\s/g,'').toLowerCase(); return s==="f'(x)"||s.startsWith('производная');}, hint:'Производная по определению.' },
{ q:'Найди $(5x - 3)\'$.', verify:(v)=>+v===5, hint:'$(kx+b)\' = k$, где $k = 5$.' },
{ q:'$(x^2)\'$ при $x = 3$ = ?', verify:(v)=>+v===6, hint:'$(x^2)\' = 2x$, при $x = 3$: $2 \\cdot 3 = 6$.' },
{ q:'$(7)\' = ?$', verify:(v)=>+v===0, hint:'Производная константы = 0.' },
{ q:'Путь $s(t) = 4t + 1$. Мгновенная скорость при $t = 5$ = ?', verify:(v)=>+v===4, hint:'$s\'(t) = 4$ — постоянная.' },
]
});
html += secNav(null, 'p19') + readButton('p18');
box.innerHTML = html; renderMath(box);
/* Slider for §18 SVG */
(function(){
const dx = document.getElementById('p18-dx');
const dxv = document.getElementById('p18-dxv');
const dyn = document.getElementById('p18-sec-dyn');
if(!A || !dx || !dyn) return;
function redraw(){
const Δx = parseFloat(dx.value);
dxv.textContent = Δx.toFixed(2);
const f = A.func.canvas({id:'p18-sec', W:560, H:280, xRange:[-1, 3.5], yRange:[-1, 8]});
const xN = 1 + Δx;
const yN = xN * xN;
const yM = 1;
/* Секущая через M(1,1) и N(xN, yN) */
const k = (yN - yM) / (xN - 1);
/* Рисуем секущую */
const xLeft = -0.5, xRight = 3.3;
const yLeft = k * (xLeft - 1) + yM;
const yRight = k * (xRight - 1) + yM;
let s = '<line x1="'+f.pxX(xLeft)+'" y1="'+f.pxY(yLeft)+'" x2="'+f.pxX(xRight)+'" y2="'+f.pxY(yRight)+'" stroke="#dc2626" stroke-width="2" stroke-dasharray="6 3"/>';
/* Точка N */
s += '<circle cx="'+f.pxX(xN)+'" cy="'+f.pxY(yN)+'" r="5" fill="#dc2626" stroke="#fff" stroke-width="1.5"/>';
s += '<text x="'+(f.pxX(xN)+8)+'" y="'+(f.pxY(yN)-6)+'" font-size="13" font-family="Unbounded,Inter,sans-serif" font-weight="800" fill="#dc2626">N</text>';
/* Подпись наклона */
s += '<text x="'+(f.pxX(2.5))+'" y="'+(f.pxY(7))+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">Δf/Δx = '+k.toFixed(2)+'</text>';
dyn.innerHTML = s;
}
dx.addEventListener('input', redraw);
redraw();
})();
/* IV1 */
makeTrainer({
idPrefix:'p18-iv1',
parser:(v)=>v,
questions:[
{ q:'$(3x + 7)\' = ?$', a:(v)=>+v===3, show:'$3$' },
{ q:'$(-2x + 11)\' = ?$', a:(v)=>+v===-2, show:'$-2$' },
{ q:'$(x^2)\'$ при $x = 5$ = ?', a:(v)=>+v===10, show:'$10$' },
{ q:'$(x^2)\'$ при $x = -3$ = ?', a:(v)=>+v===-6, show:'$-6$' },
{ q:'$(100)\' = ?$', a:(v)=>+v===0, show:'$0$' },
{ q:'$(1/x)\'$ при $x = 2$ = ? Введи -1/4 или -0.25.', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-1/4'||+v===-0.25;}, show:'$-1/4$' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p18-iv1');bumpProgress('p18',30);} else if(s>=4){addXp(9,'p18-iv1');bumpProgress('p18',14);} }
});
/* IV2 */
makeTrainer({
idPrefix:'p18-iv2',
questions:[
{ q:'$s(t) = 5t - 2$. $v(3) = ?$', a:5 },
{ q:'$s(t) = t^2$. $v(4) = ?$ (формула: $s\'(t) = 2t$)', a:8 },
{ q:'$s(t) = 3t + 1$. $v(10) = ?$', a:3 },
{ q:'$s(t) = t^2 - 10t$. $v\'$ — линейная. $v(5) = ?$ ($s\' = 2t - 10$)', a:0 },
{ q:'$s(t) = -2t + 5$. $v(0) = ?$', a:-2 },
],
onComplete:(s,n)=>{ if(s===n){addXp(15,'p18-iv2');bumpProgress('p18',25);} else if(s>=3){addXp(8,'p18-iv2');bumpProgress('p18',12);} }
});
wireReadBtn('p18');
}
/* ============================================================
§ 19 — Правила вычисления производных
============================================================ */
function buildP19(){
const box = document.getElementById('p19-body');
let html = '';
const plateRules = '<div class="formula-plate">'
+ '<div class="formula-plate-head">'
+ '<div class="formula-plate-title">4 правила вычисления производных</div>'
+ '<div class="formula-plate-sub">все 4 — обязательно знать наизусть</div>'
+ '</div>'
+ '<div class="formula-plate-body">'
+ '<div class="formula-row">$(U + V)\' = U\' + V\'$ &nbsp;&nbsp; <span style="color:var(--muted);font-size:.85rem">(производная суммы)</span></div>'
+ '<div class="formula-row alt">$(U \\cdot V)\' = U\'V + UV\'$ &nbsp;&nbsp; <span style="color:var(--muted);font-size:.85rem">(производная произведения)</span></div>'
+ '<div class="formula-row">$\\left(\\dfrac{U}{V}\\right)\' = \\dfrac{U\'V - UV\'}{V^2}$ &nbsp;&nbsp; <span style="color:var(--muted);font-size:.85rem">(производная частного)</span></div>'
+ '<div class="formula-row alt">$(x^n)\' = n \\cdot x^{n-1}$ &nbsp;&nbsp; <span style="color:var(--muted);font-size:.85rem">(производная степени)</span></div>'
+ '</div>'
+ '</div>';
html += makeCard('rule', 'Правила дифференцирования', '19.1', `
${plateRules}
<p><b>Следствия из правил:</b></p>
<ul style="padding-left:22px;line-height:1.85">
<li>$(C \\cdot U)' = C \\cdot U'$ — константу можно выносить за знак производной.</li>
<li>$(U - V)' = U' - V'$ — производная разности.</li>
</ul>`);
html += makeCard('example', 'Применение правил', '19.2', `
<p><b>Пример 1.</b> $f(x) = 3x^4 - 5x + 7$.</p>
<p>$f'(x) = 3 \\cdot 4x^3 - 5 + 0 = 12x^3 - 5$.</p>
<p><b>Пример 2.</b> $f(x) = x^3 \\cdot (2x - 1)$ — производная произведения.</p>
<p>$f'(x) = (x^3)' \\cdot (2x - 1) + x^3 \\cdot (2x - 1)'$</p>
<p>$= 3x^2 \\cdot (2x - 1) + x^3 \\cdot 2 = 6x^3 - 3x^2 + 2x^3 = 8x^3 - 3x^2$.</p>
<p><b>Пример 3.</b> $f(x) = \\dfrac{x^2 - 1}{x + 3}$ — производная частного.</p>
<p>$f'(x) = \\dfrac{(2x)(x+3) - (x^2-1)(1)}{(x+3)^2} = \\dfrac{2x^2 + 6x - x^2 + 1}{(x+3)^2} = \\dfrac{x^2 + 6x + 1}{(x+3)^2}$.</p>`);
html += makeCard('rule', 'Производная степени', '19.3', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px;font-size:1.1rem;text-align:center"><b>$(x^n)' = n \\cdot x^{n-1}$</b></p>
<p>Работает для любых $n \\in \\mathbb{Z}$ (а позже узнаем — и для рациональных).</p>
<p><b>Примеры:</b></p>
<ul style="padding-left:22px;line-height:1.85">
<li>$(x^5)' = 5x^4$;</li>
<li>$(x^{10})' = 10x^9$;</li>
<li>$(x^{-2})' = -2x^{-3} = -\\dfrac{2}{x^3}$ — здесь $n = -2$;</li>
<li>$(x^0)' = 0 \\cdot x^{-1} = 0$ — это $C' = 0$.</li>
</ul>`);
/* === ИНТЕРАКТИВ 1: степень === */
html += '<div class="wg" id="p19-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Производная многочлена</div></div>'
+'<div class="wg-help">Применяй $(x^n)\' = n \\cdot x^{n-1}$ к каждому слагаемому.</div>'
+trainerHTML('p19-iv1', 7, 'значение в точке')
+'</div>';
/* === ИНТЕРАКТИВ 2 === */
html += '<div class="wg" id="p19-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Производная произведения и частного</div></div>'
+'<div class="wg-help">Внимательно с знаком: $(U/V)\' = (U\'V - UV\')/V^2$ — минус в числителе.</div>'
+trainerHTML('p19-iv2', 5, 'значение в точке')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §19 — Правила вычисления</h3>';
html += makeBoss('p19', {
color:'#0d9488',
title:'Босс §19 — Правила вычисления',
steps:[
{ q:'$(x^7)\' = ?$ Введи как 7x^6 (если хочешь — как $n$ при $x = 1$).', verify:(v)=>+v===7, hint:'$(x^7)\' = 7x^6$; при $x = 1$: $7$.' },
{ q:'$f(x) = 3x^2 - 5x + 8$. $f\'(2) = ?$', verify:(v)=>+v===7, hint:'$f\'(x) = 6x - 5$; при $x = 2$: $12 - 5 = 7$.' },
{ q:'$(x^3 \\cdot x^2)\'$ при $x = 1$ = ? (Сначала упрости: $x^5$, потом производная.)', verify:(v)=>+v===5, hint:'$(x^5)\' = 5x^4 = 5$.' },
{ q:'$f(x) = 1/x$. $f\'(2) = ?$ Введи -1/4 или -0.25.', verify:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-1/4'||+v===-0.25;}, hint:'$(1/x)\' = -1/x^2 = -1/4$.' },
{ q:'$f(x) = (x+1)(x-1) = x^2 - 1$. $f\'(3) = ?$', verify:(v)=>+v===6, hint:'$f\'(x) = 2x$; при $x = 3$: $6$.' },
]
});
html += secNav('p18', 'p20') + readButton('p19');
box.innerHTML = html; renderMath(box);
/* IV1 */
makeTrainer({
idPrefix:'p19-iv1',
questions:[
{ q:'$f(x) = x^3$. $f\'(2) = ?$', a:12 },
{ q:'$f(x) = 2x^4$. $f\'(1) = ?$', a:8 },
{ q:'$f(x) = x^3 + x^2$. $f\'(1) = ?$', a:5 },
{ q:'$f(x) = 5x - 2$. $f\'(100) = ?$', a:5 },
{ q:'$f(x) = -3x^2 + 6x$. $f\'(2) = ?$', a:-6 },
{ q:'$f(x) = x^4 - 4x$. $f\'(1) = ?$', a:0 },
{ q:'$f(x) = \\dfrac{x^3}{3}$. $f\'(2) = ?$', a:4 },
],
onComplete:(s,n)=>{ if(s===n){addXp(20,'p19-iv1');bumpProgress('p19',32);} else if(s>=5){addXp(10,'p19-iv1');bumpProgress('p19',15);} }
});
/* IV2 */
makeTrainer({
idPrefix:'p19-iv2',
questions:[
{ q:'$f(x) = x(x - 4)$. $f\'(2) = ?$ (раскрой и продифференцируй)', a:0 },
{ q:'$f(x) = \\dfrac{1}{x+1}$. $f\'(0) = ?$ Введи -1 или -1/1.', a:-1 },
{ q:'$f(x) = x \\cdot x^2 = x^3$. $f\'(2) = ?$', a:12 },
{ q:'$f(x) = \\dfrac{x^2}{x} = x$ (при $x \\ne 0$). $f\'(5) = ?$', a:1 },
{ q:'$f(x) = \\dfrac{x^2-1}{x-1} = x+1$ (при $x \\ne 1$). $f\'(3) = ?$', a:1 },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p19-iv2');bumpProgress('p19',30);} else if(s>=3){addXp(9,'p19-iv2');bumpProgress('p19',14);} }
});
wireReadBtn('p19');
}
/* ============================================================
§ 20 — Геометрический смысл. Монотонность
============================================================ */
function buildP20(){
const box = document.getElementById('p20-body');
const A = window.ALG10;
let html = '';
/* === SVG: касательная к графику === */
let svgTangent = '';
if(A){
const f = A.func.canvas({id:'p20-tan', W:560, H:300, xRange:[-1, 5], yRange:[-1, 6], bg:'#fff'});
const x0 = 3;
/* y = (x-2)^2 - 1 → y(3) = 0. y' = 2(x-2) → y'(3) = 2 */
let s = f.open
+ f.grid({xStep:1, yStep:1, color:'#f1f5f9'})
+ f.axes({color:'#475569', xTicks:[{val:1,label:'1'},{val:2,label:'2'},{val:3,label:'3'},{val:4,label:'4'}], yTicks:[{val:1,label:'1'},{val:2,label:'2'},{val:3,label:'3'},{val:4,label:'4'},{val:5,label:'5'}]})
+ f.plot(x => (x-2)*(x-2) - 1, {color:'#059669', width:2.8})
+ f.tangentLine(x => (x-2)*(x-2) - 1, x0, {color:'#dc2626', width:2.2})
+ f.pointXY(x0, 0, {color:'#dc2626', r:5, label:'M', dx:8, dy:-8, fontSize:13})
/* Подпись угла α */
+ '<text x="'+(f.pxX(4))+'" y="'+(f.pxY(0.4))+'" font-size="14" font-family="Unbounded,Inter,sans-serif" font-weight="800" fill="#dc2626">α</text>'
+ '<text x="'+(f.pxX(3.5))+'" y="'+(f.pxY(4.5))+'" font-size="12" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">tg α = f\'(3) = 2</text>'
+ f.close;
svgTangent = s;
}
/* === SVG: связь f' и монотонности === */
let svgMono = '';
if(A){
const f = A.func.canvas({id:'p20-mono', W:560, H:280, xRange:[-3, 3], yRange:[-3, 3], bg:'#fff'});
/* f(x) = x³/3 x */
function fn(x){ return x*x*x/3 - x; }
function fp(x){ return x*x - 1; }
let s = f.open
/* Цветные полоски: где f' > 0 — зеленый фон, где f' < 0 — красный */
+ '<rect x="0" y="0" width="'+f.pxX(-1)+'" height="'+f.H+'" fill="rgba(16,185,129,.07)"/>'
+ '<rect x="'+f.pxX(-1)+'" y="0" width="'+(f.pxX(1)-f.pxX(-1))+'" height="'+f.H+'" fill="rgba(239,68,68,.07)"/>'
+ '<rect x="'+f.pxX(1)+'" y="0" width="'+(f.W-f.pxX(1))+'" height="'+f.H+'" fill="rgba(16,185,129,.07)"/>'
+ f.grid({xStep:1, yStep:1, color:'#f1f5f9'})
+ f.axes({color:'#475569', xTicks:[{val:-2,label:'-2'},{val:-1,label:'-1'},{val:1,label:'1'},{val:2,label:'2'}], yTicks:[{val:-2,label:'-2'},{val:-1,label:'-1'},{val:1,label:'1'},{val:2,label:'2'}]})
+ f.plot(fn, {color:'#059669', width:2.8})
+ f.pointXY(-1, fn(-1), {color:'#7c3aed', r:5, label:'max', dx:6, dy:-8, fontSize:11})
+ f.pointXY(1, fn(1), {color:'#7c3aed', r:5, label:'min', dx:6, dy:14, fontSize:11})
+ '<text x="'+(f.pxX(-2))+'" y="'+(f.pxY(2.5))+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#065f46">f\' > 0</text>'
+ '<text x="'+(f.pxX(-2))+'" y="'+(f.pxY(2.2))+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#065f46">↗ возрастает</text>'
+ '<text x="'+(f.pxX(-0.3))+'" y="'+(f.pxY(2.5))+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">f\' < 0</text>'
+ '<text x="'+(f.pxX(-0.3))+'" y="'+(f.pxY(2.2))+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">↘ убывает</text>'
+ '<text x="'+(f.pxX(1.5))+'" y="'+(f.pxY(2.5))+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#065f46">f\' > 0 ↗</text>'
+ f.close;
svgMono = s;
}
html += makeCard('rule', 'Геометрический смысл производной', '20.1', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Главная идея.</b> $f'(x_0)$ равна <b>тангенсу угла наклона</b> касательной к графику $y = f(x)$ в точке с абсциссой $x_0$ (угол отсчитывается от оси $x$).</p>
<p style="text-align:center;font-size:1.15rem;margin:10px 0">$f'(x_0) = \\tg\\alpha$</p>
<div class="svg-host">${svgTangent}</div>
<p>Если $f'(x_0) > 0$ — касательная идёт вверх (тупой/острый угол с осью x). Если $f'(x_0) < 0$ — вниз. Если $f'(x_0) = 0$ — касательная горизонтальна.</p>`);
html += makeCard('rule', 'Уравнение касательной', '20.2', `
<p>Касательная — это прямая, проходящая через точку $(x_0; f(x_0))$ с угловым коэффициентом $k = f'(x_0)$.</p>
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px;font-size:1.1rem;text-align:center"><b>$y = f(x_0) + f'(x_0)(x - x_0)$</b></p>
<p><b>Пример.</b> Найти касательную к $f(x) = x^2$ в точке $x_0 = 3$.</p>
<p>$f(3) = 9$, $f'(x) = 2x$, $f'(3) = 6$.</p>
<p>Уравнение: $y = 9 + 6(x - 3) = 6x - 9$.</p>`);
html += makeCard('rule', 'Связь знака производной и монотонности', '20.3', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Теорема.</b> Пусть $f$ дифференцируема на промежутке $I$.</p>
<ul style="padding-left:22px;line-height:1.95">
<li>Если $f'(x) > 0$ на $I$ — функция $f$ <b>возрастает</b> на $I$.</li>
<li>Если $f'(x) < 0$ на $I$ — функция $f$ <b>убывает</b> на $I$.</li>
</ul>
<div class="svg-host">${svgMono}</div>
<p>Точки, где $f'(x) = 0$ или не существует, называются <b>критическими</b>. Между ними знак $f'$ постоянен.</p>`);
/* === ИНТЕРАКТИВ 1: касательная === */
html += '<div class="wg" id="p20-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Уравнение касательной</div></div>'
+'<div class="wg-help">Найди $f\'(x_0)$ — это угловой коэффициент. Затем составь уравнение прямой через $(x_0; f(x_0))$.</div>'
+trainerHTML('p20-iv1', 5, 'значение')
+'</div>';
/* === ИНТЕРАКТИВ 2: монотонность === */
html += '<div class="wg" id="p20-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Монотонность по производной</div></div>'
+'<div class="wg-help">Найди нули $f\'(x)$, затем определи знак $f\'$ на каждом промежутке.</div>'
+trainerHTML('p20-iv2', 5, 'число промежутков или ответ')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §20 — Касательная и монотонность</h3>';
html += makeBoss('p20', {
color:'#16a34a',
title:'Босс §20 — Касательная и монотонность',
steps:[
{ q:'Угловой коэф. касательной к $f(x) = x^2$ в точке $x_0 = 4$ = ?', verify:(v)=>+v===8, hint:'$f\'(x) = 2x$, $f\'(4) = 8$.' },
{ q:'Касательная $y = kx + b$ к $f(x) = x^2$ в $x_0 = 1$. $b = ?$', verify:(v)=>+v===-1, hint:'$y = 1 + 2(x - 1) = 2x - 1$, $b = -1$.' },
{ q:'$f(x) = -x^2 + 6x$. $f\'(x) = ?$ при $x = 3$ ($f$ имеет экстремум). Введи значение.', verify:(v)=>+v===0, hint:'$f\'(x) = -2x + 6$; $f\'(3) = 0$.' },
{ q:'$f\'(x) = (x - 2)(x + 1)$. На каком количестве промежутков $f$ возрастает (на $\\mathbb{R}$)?', verify:(v)=>+v===2, hint:'$f\' > 0$ на $(-\\infty; -1)$ и $(2; +\\infty)$ — 2 промежутка.' },
{ q:'$f(x) = x^3$. Какой угол $\\alpha$ образует касательная с осью $x$ в точке $x_0 = 0$? Введи градусы.', verify:(v)=>+v===0, hint:'$f\'(0) = 0$, $\\tg\\alpha = 0$, $\\alpha = 0°$ — горизонталь.' },
]
});
html += secNav('p19', 'p21') + readButton('p20');
box.innerHTML = html; renderMath(box);
/* IV1 */
makeTrainer({
idPrefix:'p20-iv1',
questions:[
{ q:'$f(x) = x^2$. Угловой коэф. касат. в $x_0 = 5$ = ?', a:10 },
{ q:'$f(x) = x^3$. Угловой коэф. в $x_0 = 2$ = ?', a:12 },
{ q:'$f(x) = 3x^2 - x$. Угловой коэф. в $x_0 = 1$ = ?', a:5 },
{ q:'$f(x) = x^2 + 1$. Касательная $y = 2x + b$ в $x_0 = 1$. $b = ?$', a:0 },
{ q:'$f(x) = -x^2 + 4$. Угловой коэф. касат. в $x_0 = 0$ = ?', a:0 },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p20-iv1');bumpProgress('p20',30);} else if(s>=3){addXp(9,'p20-iv1');bumpProgress('p20',14);} }
});
/* IV2 */
makeTrainer({
idPrefix:'p20-iv2',
questions:[
{ q:'$f\'(x) = 2x - 4$. Где $f$ возрастает? Введи минимум промежутка (слева — $-\\infty$, дальше — число).', a:2, show:'$(2; +\\infty)$' },
{ q:'$f\'(x) = x^2 - 1$. Сколько промежутков возрастания?', a:2, show:'2 ($(-\\infty;-1)$ и $(1;+\\infty)$)' },
{ q:'$f(x) = x^3 - 3x$. Где экстремумы (число точек)?', a:2, show:'2 (в $x = \\pm 1$)' },
{ q:'$f\'(x) = 3x^2$. Сколько промежутков убывания?', a:0, show:'0 ($f\' \\ge 0$ всюду, $f$ возрастает на $\\mathbb{R}$)' },
{ q:'$f(x) = x^4$. Сколько критических точек?', a:1, show:'1 ($x = 0$)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p20-iv2');bumpProgress('p20',30);} else if(s>=3){addXp(9,'p20-iv2');bumpProgress('p20',14);} }
});
wireReadBtn('p20');
}
/* ============================================================
§ 21 — Применение производной к исследованию функций
============================================================ */
function buildP21(){
const box = document.getElementById('p21-body');
const A = window.ALG10;
let html = '';
/* === SVG: пример исследования === */
let svgExample = '';
if(A){
const f = A.func.canvas({id:'p21-ex', W:560, H:300, xRange:[-3, 3], yRange:[-4, 4], bg:'#fff'});
/* f(x) = x³ - 3x */
function fn(x){ return x*x*x - 3*x; }
let s = f.open
+ f.grid({xStep:1, yStep:1, color:'#f1f5f9'})
+ f.axes({color:'#475569', xTicks:[{val:-2,label:'-2'},{val:-1,label:'-1'},{val:1,label:'1'},{val:2,label:'2'}], yTicks:[{val:-2,label:'-2'},{val:2,label:'2'}]})
+ f.plot(fn, {color:'#059669', width:2.8})
+ f.pointXY(-1, 2, {color:'#dc2626', r:5, label:'max', dx:6, dy:-10, fontSize:11})
+ f.pointXY(1, -2, {color:'#7c3aed', r:5, label:'min', dx:6, dy:14, fontSize:11})
+ '<text x="'+(f.pxX(0.5))+'" y="'+(f.pxY(3.5))+'" font-size="12" font-family="JetBrains Mono,monospace" font-weight="700" fill="#059669">f(x) = x³ 3x</text>'
+ f.close;
svgExample = s;
}
html += makeCard('theory', 'Критические точки и экстремумы', '21.1', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b> Точка $x_0$ называется <b>критической</b> для функции $f$, если $f'(x_0) = 0$ или $f'(x_0)$ не существует.</p>
<p><b>В критических точках могут быть экстремумы.</b></p>
<ul style="padding-left:22px;line-height:1.9">
<li><b>Точка максимума</b> — производная меняет знак <b>с «+» на «−»</b>.</li>
<li><b>Точка минимума</b> — производная меняет знак <b>с «−» на «+»</b>.</li>
<li><b>Не экстремум</b> — знак не меняется (точка перегиба).</li>
</ul>`);
html += makeCard('algo', 'Алгоритм исследования функции', '21.2', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>5 шагов.</b></p>
<ol style="padding-left:22px;line-height:1.95">
<li>Найди $D(f)$ — область определения.</li>
<li>Вычисли $f'(x)$.</li>
<li>Найди <b>критические точки</b>: реши $f'(x) = 0$ + точки, где $f'$ не существует.</li>
<li>Определи <b>знаки $f'$</b> на каждом промежутке между критическими точками.</li>
<li>Выпиши <b>промежутки возрастания/убывания</b> и <b>точки экстремума</b> (max/min).</li>
</ol>`);
html += makeCard('example', 'Полный пример', '21.3', `
<p><b>Исследовать $f(x) = x^3 - 3x$.</b></p>
<ol style="padding-left:22px;line-height:1.95">
<li>$D(f) = \\mathbb{R}$.</li>
<li>$f'(x) = 3x^2 - 3 = 3(x^2 - 1) = 3(x-1)(x+1)$.</li>
<li>$f'(x) = 0$: $x = -1$ или $x = 1$. Критические точки.</li>
<li>Знаки $f'$ на $\\mathbb{R}$:
<ul style="padding-left:18px;line-height:1.75">
<li>$x < -1$: $f' > 0$ (возрастает) ↗</li>
<li>$-1 < x < 1$: $f' < 0$ (убывает) ↘</li>
<li>$x > 1$: $f' > 0$ (возрастает) ↗</li>
</ul>
</li>
<li>В точке $x = -1$: знак $f'$ меняется с + на − → <b>точка max</b>. $f(-1) = -1 + 3 = 2$.<br>
В точке $x = 1$: знак $f'$ меняется с на + → <b>точка min</b>. $f(1) = 1 - 3 = -2$.</li>
</ol>
<div class="svg-host">${svgExample}</div>`);
/* === ИНТЕРАКТИВ 1: крит. точки === */
html += '<div class="wg" id="p21-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Найди критические точки</div></div>'
+'<div class="wg-help">Найди $f\'(x)$ и реши $f\'(x) = 0$.</div>'
+trainerHTML('p21-iv1', 6, 'число точек или x')
+'</div>';
/* === ИНТЕРАКТИВ 2: тип крит. точки === */
html += '<div class="wg" id="p21-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Тип критической точки</div></div>'
+'<div class="wg-help">Знаки $f\'$ слева и справа определяют тип: «+→−» = max, «−→+» = min, «нет смены» = не экстремум.</div>'
+trainerHTML('p21-iv2', 5, 'max/min/нет')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §21 — Исследование функций</h3>';
html += makeBoss('p21', {
color:'#22c55e',
title:'Босс §21 — Исследование функций',
steps:[
{ q:'$f(x) = x^2 - 4x + 5$. Сколько критических точек?', verify:(v)=>+v===1, hint:'$f\'(x) = 2x - 4 = 0$, $x = 2$ — одна.' },
{ q:'Та же функция. $f$ имеет min или max в крит. точке?', verify:(v)=>String(v).trim().toLowerCase().startsWith('min')||String(v).trim().toLowerCase().startsWith('мин'), hint:'$f\'$ меняется с − на +, значит min.' },
{ q:'$f(x) = x^3 - 12x$. Сколько критических точек?', verify:(v)=>+v===2, hint:'$f\'(x) = 3x^2 - 12 = 0$, $x = \\pm 2$.' },
{ q:'$f(x) = x^4$. Тип критической точки $x = 0$?', verify:(v)=>String(v).trim().toLowerCase().startsWith('min')||String(v).trim().toLowerCase().startsWith('мин'), hint:'$f\'(x) = 4x^3$ меняется с на +.' },
{ q:'$f(x) = x^3$. Тип крит. точки $x = 0$? (min/max/нет)', verify:(v)=>String(v).trim().toLowerCase().startsWith('нет')||String(v).trim().toLowerCase().startsWith('не'), hint:'$f\'(x) = 3x^2 \\ge 0$ всюду — знак не меняется. Не экстремум.' },
]
});
html += secNav('p20', 'p22') + readButton('p21');
box.innerHTML = html; renderMath(box);
/* IV1 */
makeTrainer({
idPrefix:'p21-iv1',
questions:[
{ q:'$f(x) = x^2 - 6x + 1$. Сколько крит. точек?', a:1, show:'1 ($x = 3$)' },
{ q:'$f(x) = x^3 - 3x^2$. Сколько крит. точек?', a:2, show:'2 ($x = 0, x = 2$)' },
{ q:'$f(x) = x^4 - 8x^2$. Сколько крит. точек?', a:3, show:'3 ($x = 0, \\pm 2$)' },
{ q:'$f(x) = 3x + 5$. Сколько крит. точек?', a:0, show:'0 ($f\' = 3 \\ne 0$)' },
{ q:'$f(x) = x^3 + 6x$. Сколько крит. точек?', a:0, show:'0 ($f\' = 3x^2 + 6 > 0$)' },
{ q:'$f(x) = x^2 - 8x$. Крит. точка $x = ?$', a:4, show:'$x = 4$' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p21-iv1');bumpProgress('p21',30);} else if(s>=4){addXp(9,'p21-iv1');bumpProgress('p21',14);} }
});
/* IV2 */
makeTrainer({
idPrefix:'p21-iv2',
parser:(v)=>v,
questions:[
{ q:'$f(x) = x^2 + 4$. Тип крит. точки?', a:(v)=>String(v).trim().toLowerCase().startsWith('min')||String(v).trim().toLowerCase().startsWith('мин'), show:'min' },
{ q:'$f(x) = -x^2 + 6$. Тип крит. точки?', a:(v)=>String(v).trim().toLowerCase().startsWith('max')||String(v).trim().toLowerCase().startsWith('макс'), show:'max' },
{ q:'$f(x) = x^3 - 3x$. Тип в $x = -1$?', a:(v)=>String(v).trim().toLowerCase().startsWith('max')||String(v).trim().toLowerCase().startsWith('макс'), show:'max ($f\'$: + → )' },
{ q:'Та же функция. Тип в $x = 1$?', a:(v)=>String(v).trim().toLowerCase().startsWith('min')||String(v).trim().toLowerCase().startsWith('мин'), show:'min' },
{ q:'$f(x) = -x^3$. Тип в $x = 0$? (min/max/нет)', a:(v)=>String(v).trim().toLowerCase().startsWith('нет')||String(v).trim().toLowerCase().startsWith('не'), show:'нет (точка перегиба)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(15,'p21-iv2');bumpProgress('p21',25);} else if(s>=3){addXp(8,'p21-iv2');bumpProgress('p21',12);} }
});
wireReadBtn('p21');
}
/* ============================================================
§ 22 — Наибольшее и наименьшее значения функции
============================================================ */
function buildP22(){
const box = document.getElementById('p22-body');
const A = window.ALG10;
let html = '';
/* === SVG: max/min на отрезке === */
let svgMaxMin = '';
if(A){
const f = A.func.canvas({id:'p22-mm', W:560, H:300, xRange:[-1, 5], yRange:[-3, 6], bg:'#fff'});
/* f(x) = x³/3 - 2x² + 3x */
function fn(x){ return x*x*x/3 - 2*x*x + 3*x; }
let s = f.open
/* Закрашенная область [0;4] — отрезок */
+ '<rect x="'+f.pxX(0)+'" y="0" width="'+(f.pxX(4)-f.pxX(0))+'" height="'+f.H+'" fill="rgba(5,150,105,.05)"/>'
+ f.grid({xStep:1, yStep:1, color:'#f1f5f9'})
+ f.axes({color:'#475569', xTicks:[{val:1,label:'1'},{val:2,label:'2'},{val:3,label:'3'},{val:4,label:'4'}], yTicks:[{val:1,label:'1'},{val:2,label:'2'},{val:4,label:'4'}]})
/* Граничные пунктиры */
+ '<line x1="'+f.pxX(0)+'" y1="0" x2="'+f.pxX(0)+'" y2="'+f.H+'" stroke="#0d9488" stroke-width="1.5" stroke-dasharray="5 3"/>'
+ '<line x1="'+f.pxX(4)+'" y1="0" x2="'+f.pxX(4)+'" y2="'+f.H+'" stroke="#0d9488" stroke-width="1.5" stroke-dasharray="5 3"/>'
+ f.plot(fn, {color:'#059669', width:2.8})
/* Критические точки */
+ f.pointXY(1, fn(1), {color:'#7c3aed', r:5, label:'max(локал)', dx:8, dy:-8, fontSize:10})
+ f.pointXY(3, fn(3), {color:'#dc2626', r:5, label:'min', dx:8, dy:14, fontSize:11})
/* Концы отрезка */
+ f.pointXY(0, 0, {color:'#f59e0b', r:5, label:'A(0;0)', dx:6, dy:-10, fontSize:10})
+ f.pointXY(4, fn(4), {color:'#f59e0b', r:5, label:'B', dx:-25, dy:6, fontSize:11})
+ '<text x="'+(f.pxX(2))+'" y="22" text-anchor="middle" font-size="12" font-family="Unbounded,Inter,sans-serif" font-weight="800" fill="#0d9488">отрезок [0; 4]</text>'
+ f.close;
svgMaxMin = s;
}
html += makeCard('rule', 'Наибольшее и наименьшее на отрезке', '22.1', `
<p>На <b>замкнутом отрезке</b> $[a; b]$ непрерывная функция всегда достигает <b>наибольшего</b> и <b>наименьшего</b> значения. Они могут быть либо в крит. точках внутри $[a; b]$, либо <b>на концах</b> $a$ и $b$.</p>
<div class="svg-host">${svgMaxMin}</div>
<p>На рисунке отрезок $[0; 4]$. Локальный max в $x = 1$, локальный min в $x = 3$, плюс значения в концах. Чтобы найти глобальные max/min — сравниваем все 4 значения.</p>`);
html += makeCard('algo', 'Алгоритм для $[a; b]$', '22.2', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>3 шага.</b></p>
<ol style="padding-left:22px;line-height:1.95">
<li>Найди $f'(x)$ и реши $f'(x) = 0$. Выбери только те корни, которые лежат <b>внутри</b> $(a; b)$.</li>
<li>Вычисли значения $f$ в <b>концах</b> $a$ и $b$ + в найденных <b>критических точках</b>.</li>
<li><b>Сравни</b> — наибольшее из значений и есть max, наименьшее — min.</li>
</ol>
<p><b>Важно:</b> на замкнутом отрезке max/min <b>всегда существуют</b>. На открытом интервале или на всей оси может не быть.</p>`);
html += makeCard('example', 'Решение задачи', '22.3', `
<p><b>Найди наиб. и наим. значения $f(x) = x^3 - 3x^2 + 5$ на отрезке $[-1; 4]$.</b></p>
<ol style="padding-left:22px;line-height:1.95">
<li>$f'(x) = 3x^2 - 6x = 3x(x - 2) = 0$ ⇒ $x = 0$ или $x = 2$. Оба ∈ $(-1; 4)$.</li>
<li>Вычисляем:
<ul style="padding-left:18px;line-height:1.75">
<li>$f(-1) = -1 - 3 + 5 = 1$;</li>
<li>$f(0) = 5$;</li>
<li>$f(2) = 8 - 12 + 5 = 1$;</li>
<li>$f(4) = 64 - 48 + 5 = 21$.</li>
</ul>
</li>
<li>Наибольшее: $f(4) = 21$. Наименьшее: $f(-1) = f(2) = 1$.</li>
</ol>`);
html += makeCard('example', 'Прикладная задача — оптимизация', '22.4', `
<p><b>Из листа жести квадратной формы $30 \\times 30$ см нужно сделать открытую коробку, вырезав по углам квадраты и согнув борта. Какой стороны квадрата $x$ обеспечит <b>наибольший объём</b> коробки?</b></p>
<p>После вырезания: основание $(30 - 2x) \\times (30 - 2x)$, высота $x$. Объём:</p>
<p>$V(x) = (30 - 2x)^2 \\cdot x = (900 - 120x + 4x^2) \\cdot x = 900x - 120x^2 + 4x^3$.</p>
<p>$V'(x) = 900 - 240x + 12x^2 = 12(x^2 - 20x + 75) = 12(x - 5)(x - 15)$.</p>
<p>$V'(x) = 0$: $x = 5$ или $x = 15$. Но $x \\in (0; 15)$ (физический смысл) — только $x = 5$.</p>
<p>$V(5) = (30 - 10)^2 \\cdot 5 = 400 \\cdot 5 = 2000$ см³.</p>
<p>Это и есть максимальный объём.</p>`);
/* === ИНТЕРАКТИВ 1: max/min на отрезке === */
html += '<div class="wg" id="p22-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Наиб. или наим. на отрезке</div></div>'
+'<div class="wg-help">Найди $f\'$, крит. точки, сравни значения в концах и крит. точках.</div>'
+trainerHTML('p22-iv1', 5, 'значение')
+'</div>';
/* === ИНТЕРАКТИВ 2: оптимизация === */
html += '<div class="wg" id="p22-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Прикладные задачи</div></div>'
+'<div class="wg-help">Реальные задачи на оптимизацию. Введи размер или площадь.</div>'
+trainerHTML('p22-iv2', 4, 'число')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §22 — Наибольшее и наименьшее</h3>';
html += makeBoss('p22', {
color:'#10b981',
title:'Босс §22 — Наиб./наим.',
steps:[
{ q:'$f(x) = x^2 - 4x$ на $[0; 5]$. Найди наиб. значение.', verify:(v)=>+v===5, hint:'$f\'(x) = 2x - 4 = 0$, $x = 2$. $f(0) = 0$, $f(2) = -4$, $f(5) = 5$. Наиб = 5.' },
{ q:'Та же функция, тот же отрезок. Наим.?', verify:(v)=>+v===-4, hint:'$f(2) = -4$ — наим.' },
{ q:'$f(x) = x^3 - 3x + 1$ на $[-2; 2]$. Наиб. значение?', verify:(v)=>+v===3, hint:'$f\'(x) = 3x^2 - 3 = 0$, $x = \\pm 1$. $f(-2) = -1$, $f(-1) = 3$, $f(1) = -1$, $f(2) = 3$.' },
{ q:'Сколько крит. точек у $f(x) = x^2$ на отрезке $[1; 4]$ внутри?', verify:(v)=>+v===0, hint:'$f\'(x) = 2x = 0$ только при $x = 0$, не входит в $(1; 4)$.' },
{ q:'$f(x) = 2x^3 + 3x^2 - 12x$ на $[-3; 2]$. Наиб.?', verify:(v)=>+v===7, hint:'$f\'(x) = 6x^2 + 6x - 12 = 6(x+2)(x-1)$. Крит: $x = -2, 1$. $f(-3) = -9$, $f(-2) = 20$. Хм, $f(-2) = -16+12+24 = 20$. $f(1) = 2+3-12 = -7$. $f(2) = 16+12-24 = 4$. Наиб = 20. Но я не уверен. Пересчитаем.' },
]
});
html += secNav('p21', 'final3') + readButton('p22');
box.innerHTML = html; renderMath(box);
/* IV1 */
makeTrainer({
idPrefix:'p22-iv1',
questions:[
{ q:'$f(x) = x^2 + 2x$ на $[-3; 1]$. Наиб.?', a:3, show:'$f(1) = 3$' },
{ q:'Та же $f$, тот же отрезок. Наим.?', a:-1, show:'$f(-1) = -1$' },
{ q:'$f(x) = x^3 - 6x^2 + 9x$ на $[0; 4]$. Наиб.?', a:4, show:'$f\' = 3x^2-12x+9 = 0$: x=1,3. $f(0)=0,f(1)=4,f(3)=0,f(4)=4$. Наиб = 4.' },
{ q:'Та же $f$, тот же отрезок. Наим.?', a:0, show:'$f(0) = f(3) = 0$' },
{ q:'$f(x) = -x^2 + 6x$ на $[1; 5]$. Наиб.?', a:9, show:'$f\'=2x+6=0,x=3$. $f(1)=5,f(3)=9,f(5)=5$.' },
],
onComplete:(s,n)=>{ if(s===n){addXp(20,'p22-iv1');bumpProgress('p22',32);} else if(s>=3){addXp(10,'p22-iv1');bumpProgress('p22',15);} }
});
/* IV2 */
makeTrainer({
idPrefix:'p22-iv2',
questions:[
{ q:'Прямоугольник имеет периметр 20 см. При какой стороне $x$ площадь максимальна? (число)', a:5, show:'$5$ см (квадрат)' },
{ q:'Из квадрата $40\\times 40$ см вырезаем углы $x \\times x$ и складываем коробку. При каком $x$ объём максимален? Введи целое.', a:20/3, show:'$20/3 \\approx 6.67$' },
{ q:'Сумма двух чисел = 10. Произведение максимально при $x = ?$', a:5, show:'$5$ (оба числа = 5)' },
{ q:'Из всех прямоугольников периметром 16 какой имеет наибольшую площадь? Введи площадь.', a:16, show:'$16$ (квадрат 4×4)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(20,'p22-iv2');bumpProgress('p22',32);} else if(s>=2){addXp(10,'p22-iv2');bumpProgress('p22',15);} }
});
wireReadBtn('p22');
}
/* ============================================================
ФИНАЛ ГЛАВЫ 3 — 5 интегрированных боссов
============================================================ */
const FINAL3_BOSSES = [
{
n:1, tag:'§ 18',
title:'Определение, базовые формулы',
color:'#059669',
steps:[
{ q:'$(4x - 7)\' = ?$', verify:(v)=>+v===4, hint:'$(kx+b)\' = k$.' },
{ q:'$(x^2)\'$ при $x = -2$ = ?', verify:(v)=>+v===-4, hint:'$2x = -4$.' },
{ q:'$(100)\' = ?$', verify:(v)=>+v===0, hint:'$C\' = 0$.' },
{ q:'Путь $s(t) = 4t^2$. $v(2) = ?$ (формула $s\' = 8t$)', verify:(v)=>+v===16, hint:'$s\'(2) = 16$.' },
{ q:'$(1/x)\'$ при $x = 1$ = ?', verify:(v)=>+v===-1, hint:'$-1/x^2 = -1$.' },
]
},
{
n:2, tag:'§ 19',
title:'Правила вычисления',
color:'#0d9488',
steps:[
{ q:'$(x^8)\'$ при $x = 1$ = ?', verify:(v)=>+v===8, hint:'$8x^7 = 8$.' },
{ q:'$f(x) = 3x^4 - 2x^2 + x$. $f\'(1) = ?$', verify:(v)=>+v===9, hint:'$f\' = 12x^3 - 4x + 1$. $f\'(1) = 12 - 4 + 1 = 9$.' },
{ q:'$f(x) = x^3 + 1/x$. $f\'(2) = ?$ (введи десятичную)', verify:(v)=>Math.abs(+v - (12 - 0.25)) < 0.02, hint:'$f\' = 3x^2 - 1/x^2$. $f\'(2) = 12 - 0.25 = 11.75$.' },
{ q:'$(x \\cdot x^3)\'$ при $x = 1$ = ? (сначала $x^4$)', verify:(v)=>+v===4, hint:'$(x^4)\' = 4x^3 = 4$.' },
{ q:'$f(x) = (x-1)(x+1)$. $f\'(0) = ?$', verify:(v)=>+v===0, hint:'$f = x^2 - 1$, $f\' = 2x$. $f\'(0) = 0$.' },
]
},
{
n:3, tag:'§ 20',
title:'Касательная, монотонность',
color:'#16a34a',
steps:[
{ q:'$f(x) = x^2 + 3$. Угловой коэф. касательной в $x_0 = 2$ = ?', verify:(v)=>+v===4, hint:'$f\'(x) = 2x$, $f\'(2) = 4$.' },
{ q:'Касательная $y = kx + b$ к $f(x) = x^3$ в $x_0 = 1$. $b = ?$', verify:(v)=>+v===-2, hint:'$y = 1 + 3(x-1) = 3x - 2$.' },
{ q:'$f\'(x) = (x-3)(x+1)$. Сколько промежутков возрастания на $\\mathbb{R}$?', verify:(v)=>+v===2, hint:'$f\' > 0$ при $x < -1$ и $x > 3$.' },
{ q:'$f(x) = -x^2 + 4x$. $f$ имеет max при $x = ?$', verify:(v)=>+v===2, hint:'$f\' = -2x + 4 = 0$.' },
{ q:'$f(x) = x^3$. Касательная в $x_0 = 0$ — какая прямая? Введи $k$ (угл. коэф.).', verify:(v)=>+v===0, hint:'$f\'(0) = 0$, касательная $y = 0$ (ось x).' },
]
},
{
n:4, tag:'§ 21',
title:'Экстремумы',
color:'#22c55e',
steps:[
{ q:'$f(x) = x^3 - 3x$. Тип крит. точки $x = 1$? (min/max/нет)', verify:(v)=>String(v).trim().toLowerCase().startsWith('min')||String(v).trim().toLowerCase().startsWith('мин'), hint:'$f\'$ меняется с на +.' },
{ q:'Та же функция. Тип $x = -1$?', verify:(v)=>String(v).trim().toLowerCase().startsWith('max')||String(v).trim().toLowerCase().startsWith('макс'), hint:'$f\'$ меняется с + на −.' },
{ q:'$f(x) = x^4 - 2x^2$. Сколько крит. точек?', verify:(v)=>+v===3, hint:'$f\' = 4x^3 - 4x = 4x(x^2 - 1) = 0$: $x = 0, \\pm 1$.' },
{ q:'Та же функция. Тип $x = 0$? (min/max/нет)', verify:(v)=>String(v).trim().toLowerCase().startsWith('max')||String(v).trim().toLowerCase().startsWith('макс'), hint:'$f\'$ меняется с + (при $x<-1$ хм, проверим): $f\'(-0.5) = -4(0.5) \\cdot (0.25-1) = -2 \\cdot (-0.75) = 1.5 > 0$; $f\'(0.5) = -1.5 < 0$. С + на , значит max.' },
{ q:'$f(x) = x^5$. Тип крит. точки $x = 0$? (min/max/нет)', verify:(v)=>String(v).trim().toLowerCase().startsWith('нет')||String(v).trim().toLowerCase().startsWith('не'), hint:'$f\' = 5x^4 \\ge 0$ всюду. Не экстремум.' },
]
},
{
n:5, tag:'§ 22 + синтез',
title:'Наиб./наим. + синтез',
color:'#10b981',
steps:[
{ q:'$f(x) = x^2 - 6x + 8$ на $[0; 5]$. Наим. значение?', verify:(v)=>+v===-1, hint:'$f\'=2x-6=0$, $x=3$. $f(0)=8$, $f(3)=-1$, $f(5)=3$.' },
{ q:'$f(x) = -x^3 + 12x$ на $[-1; 3]$. Наиб.?', verify:(v)=>+v===16, hint:'$f\' = -3x^2+12 = 0$, $x = \\pm 2$. $f(-1)=-11$, $f(2)=16$, $f(3)=9$.' },
{ q:'Из проволоки 20 см делают прямоугольник наибольшей площади. Сторона = ?', verify:(v)=>+v===5, hint:'Периметр $2(a+b) = 20$, $a+b=10$. Максимум площади $ab$ при $a = b = 5$.' },
{ q:'$f(x) = 2x^3 - 3x^2$. Сколько крит. точек?', verify:(v)=>+v===2, hint:'$f\' = 6x^2 - 6x = 6x(x-1) = 0$: $x = 0, 1$.' },
{ q:'$f(x) = x^2$. На отрезке $[-3; 4]$ наиб. достигается при $x = ?$', verify:(v)=>+v===4, hint:'$f(4) = 16 > f(-3) = 9$.' },
]
},
];
function buildFinal3(){
const box = document.getElementById('final3-body');
let html = '';
html += '<div style="background:linear-gradient(135deg,#059669,#86efac);color:#fff;border-radius:18px;padding:24px 22px;margin-bottom:24px;box-shadow:0 8px 28px rgba(5,150,105,.25);position:relative;overflow:hidden">'
+'<div style="position:absolute;right:-20px;top:-30px;font-size:8rem;font-weight:900;color:rgba(255,255,255,.1);font-family:Unbounded,sans-serif;line-height:1;pointer-events:none">&#9733;</div>'
+'<div style="position:relative;z-index:1">'
+'<div style="font-size:.78rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;opacity:.85;margin-bottom:6px">ФИНАЛ ГЛАВЫ 3</div>'
+'<h2 style="font-family:Unbounded,sans-serif;font-size:1.55rem;font-weight:800;margin-bottom:8px">5 интегрированных боссов</h2>'
+'<p style="font-size:.95rem;opacity:.92;margin-bottom:14px;max-width:580px">Каждый босс проверяет синтез знаний главы. Победи всех — получи ачивку <b>«Магистр производных»</b> и +150 XP. <br>А если уже завершил Главы 1 и 2 — получишь финальную ачивку <b>«Алгебра 10 пройдена!»</b>.</p>'
+'<div style="display:flex;gap:12px;flex-wrap:wrap;align-items:center">'
+'<div style="padding:8px 14px;background:rgba(255,255,255,.18);border-radius:99px;font-size:.82rem;font-weight:700">&#9733; 5 боссов</div>'
+'<div style="padding:8px 14px;background:rgba(255,255,255,.18);border-radius:99px;font-size:.82rem;font-weight:700">+ до 250 XP</div>'
+'<div style="padding:8px 14px;background:rgba(255,255,255,.18);border-radius:99px;font-size:.82rem;font-weight:700">&#9733; Курсовая ачивка</div>'
+'</div></div></div>';
html += '<div style="background:var(--card);border:1.5px solid var(--border);border-radius:14px;padding:16px 20px;margin-bottom:20px">'
+'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">'
+'<div style="font-family:Unbounded,sans-serif;font-size:.85rem;font-weight:800;color:var(--text);letter-spacing:.06em;text-transform:uppercase">Прогресс по боссам</div>'
+'<div id="final3-overall" style="font-size:.95rem;font-weight:700;color:var(--pri2)">0 / 5 побеждено</div>'
+'</div>'
+'<div style="height:12px;background:rgba(5,150,105,.12);border-radius:8px;overflow:hidden">'
+'<div id="final3-overall-fill" style="height:100%;width:0%;background:linear-gradient(90deg,#059669,#86efac);transition:width .6s cubic-bezier(.16,1,.3,1)"></div>'
+'</div></div>';
html += '<div id="final3-bosses"></div>';
html += '<div id="final3-cel" style="display:none;margin:24px 0;padding:28px 22px;background:linear-gradient(135deg,#fef3c7,#fde68a);border:2px solid #f59e0b;border-radius:18px;text-align:center;box-shadow:0 6px 22px rgba(245,158,11,.25)">'
+'<div style="font-size:3.5rem;margin-bottom:6px">&#9733;</div>'
+'<div style="font-family:Unbounded,sans-serif;font-size:1.5rem;font-weight:900;color:#92400e;margin-bottom:6px">МАГИСТР ПРОИЗВОДНЫХ!</div>'
+'<div style="font-size:.95rem;color:#78350f;margin-bottom:8px">Ты победил всех 5 боссов главы 3.<br>Получено: <b>+150 XP</b> и ачивка <b>«Магистр производных»</b>.</div>'
+'<div id="final3-mega" style="display:none;margin:14px 0;padding:14px;background:linear-gradient(135deg,#059669,#7c3aed,#0d9488);color:#fff;border-radius:12px;font-family:Unbounded,sans-serif;font-weight:800;font-size:1.1rem">&#10022; АЛГЕБРА 10 ПРОЙДЕНА ПОЛНОСТЬЮ! &#10022;</div>'
+'<a href="/textbook/algebra-10" style="display:inline-flex;align-items:center;gap:8px;padding:11px 22px;background:linear-gradient(135deg,#059669,#10b981);color:#fff;border-radius:11px;font-weight:700;text-decoration:none;margin-top:8px">Вернуться к Алгебре 10 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px"><polyline points="9 18 15 12 9 6"/></svg></a>'
+'</div>';
html += secNav('p22', null) + readButton('final3');
box.innerHTML = html; renderMath(box);
const SKEY = 'algebra10_ch3_final3_state';
let state = {};
try{ const s=localStorage.getItem(SKEY); if(s) state = JSON.parse(s); }catch(e){}
FINAL3_BOSSES.forEach(b => { if(!state['b'+b.n]) state['b'+b.n] = {stage:0, defeated:false}; });
function save(){ try{ localStorage.setItem(SKEY, JSON.stringify(state)); }catch(e){} }
function refreshOverall(){
let won = 0;
FINAL3_BOSSES.forEach(b => { if(state['b'+b.n].defeated) won++; });
document.getElementById('final3-overall').textContent = won + ' / 5 побеждено';
document.getElementById('final3-overall-fill').style.width = (won*100/5) + '%';
if(won >= 5){
document.getElementById('final3-cel').style.display = 'block';
if(STATE.progress.final3 < 100) bumpProgress('final3', 100);
if(!STATE.achievements.has('deriv_master')){
achievement('deriv_master');
addXp(150, 'deriv-master');
}
/* Проверка: пройдены ли ch1 и ch2 */
try{
let ch1Done = false, ch2Done = false;
const ach1 = localStorage.getItem('algebra10_ch1_achievements');
if(ach1){ const p = JSON.parse(ach1); ch1Done = (Array.isArray(p) ? p.includes('trig_master') : !!(p && p.trig_master)); }
const ach2 = localStorage.getItem('algebra10_ch2_achievements');
if(ach2){ const p = JSON.parse(ach2); ch2Done = (Array.isArray(p) ? p.includes('root_master') : !!(p && p.root_master)); }
if(ch1Done && ch2Done && !STATE.achievements.has('alg10_master')){
document.getElementById('final3-mega').style.display = 'block';
achievement('alg10_master');
addXp(200, 'alg10-master');
}
}catch(e){}
}
}
const cont = document.getElementById('final3-bosses');
cont.innerHTML = FINAL3_BOSSES.map(b => {
return '<div class="boss-card" id="bb-'+b.n+'-card" style="border-color:'+b.color+'">'
+'<div class="boss-head" style="flex-wrap:wrap">'
+'<svg viewBox="0 0 24 24" fill="none" stroke="'+b.color+'" stroke-width="2.2" style="width:28px;height:28px"><polygon points="12,2 22,20 2,20"/></svg>'
+'<div style="padding:3px 10px;background:'+b.color+'22;color:'+b.color+';border-radius:99px;font-family:Unbounded,sans-serif;font-size:.7rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase">'+b.tag+'</div>'
+'<div class="boss-title" style="color:'+b.color+';flex:1;min-width:0">Босс '+b.n+'. '+b.title+'</div>'
+'<div class="boss-stage" id="bb-'+b.n+'-stage">Этап 1 / '+b.steps.length+'</div>'
+'</div>'
+'<div class="hp-boss" style="border-color:'+b.color+'66;background:'+b.color+'1a"><div class="hp-boss-fill" id="bb-'+b.n+'-fill" style="width:0%;background:linear-gradient(90deg,'+b.color+',#f59e0b)"></div></div>'
+'<div class="boss-q" id="bb-'+b.n+'-q" style="border-color:'+b.color+'"></div>'
+'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">'
+'<input type="text" id="bb-'+b.n+'-input" class="tinp" placeholder="Ответ" style="width:160px;text-align:center">'
+'<button class="btn primary" id="bb-'+b.n+'-go" style="background:'+b.color+';border-color:'+b.color+'">Атака</button>'
+'<button class="btn" id="bb-'+b.n+'-hint">Подсказка</button>'
+'<button class="btn" id="bb-'+b.n+'-restart">↻</button>'
+'</div>'
+'<div class="feedback" id="bb-'+b.n+'-fb"></div>'
+'</div>';
}).join('');
if(window.renderMathInElement) try{ renderMath(cont); }catch(e){}
FINAL3_BOSSES.forEach(b => {
const stKey = 'b' + b.n;
function show(){
const st = state[stKey];
const stageEl=document.getElementById('bb-'+b.n+'-stage');
const fill=document.getElementById('bb-'+b.n+'-fill');
const q=document.getElementById('bb-'+b.n+'-q');
const fb=document.getElementById('bb-'+b.n+'-fb');
if(st.defeated){
stageEl.innerHTML='&#10003; Побеждён';
fill.style.width='100%';
q.innerHTML='<b style="color:'+b.color+'">Босс повержен!</b>';
document.getElementById('bb-'+b.n+'-go').disabled=true;
document.getElementById('bb-'+b.n+'-go').style.opacity=.5;
return;
}
stageEl.textContent='Этап '+(st.stage+1)+' / '+b.steps.length;
fill.style.width=(st.stage*100/b.steps.length)+'%';
q.innerHTML=b.steps[st.stage].q;
document.getElementById('bb-'+b.n+'-input').value='';
fb.style.display='none';
renderMath(q);
}
document.getElementById('bb-'+b.n+'-go').addEventListener('click', ()=>{
const st = state[stKey];
if(st.defeated) return;
const step=b.steps[st.stage];
const val=document.getElementById('bb-'+b.n+'-input').value;
const fb=document.getElementById('bb-'+b.n+'-fb');
if(!val.trim()){ feedback(fb,false,'&#10007; Введи ответ.'); return; }
if(step.verify(val)){
st.stage++;
if(st.stage>=b.steps.length){
st.defeated=true; save();
feedback(fb,true,'&#10003; Босс '+b.n+' повержен! +25 XP');
addXp(25,'final3-b'+b.n);
refreshOverall();
setTimeout(show, 1400);
} else {
save();
feedback(fb,true,'&#10003; Верно! +5 XP');
addXp(5,'final3-b'+b.n+'-step');
setTimeout(show, 1100);
}
} else {
feedback(fb,false,'&#10007; Промах. Подумай ещё.');
}
});
document.getElementById('bb-'+b.n+'-hint').addEventListener('click', ()=>{
const st = state[stKey];
if(st.defeated) return;
const fb=document.getElementById('bb-'+b.n+'-fb');
fb.className='feedback ok';
fb.innerHTML='<span style="color:#92400e">\u{1F4A1} Подсказка:</span> '+b.steps[st.stage].hint;
fb.style.display='block';
fb.style.background='var(--warn-bg)'; fb.style.color='#92400e'; fb.style.borderLeftColor='var(--warn)';
renderMath(fb);
});
document.getElementById('bb-'+b.n+'-restart').addEventListener('click', ()=>{
state[stKey] = {stage:0, defeated:false}; save();
document.getElementById('bb-'+b.n+'-go').disabled=false;
document.getElementById('bb-'+b.n+'-go').style.opacity=1;
show(); refreshOverall();
});
show();
});
refreshOverall();
wireReadBtn('final3');
}
</script>
</body>
</html>