Files
Learn_System/frontend/textbooks/algebra_10_ch1.html
T
Maxim Dolgolyov e63c05cc34 feat(alg10 W3): §8 главы 1 (тригонометрические уравнения)
Самый большой параграф главы 1:

§8 Тригонометрические уравнения:

Карточки теории (8 шт):
- 8.1 Зачем геометрия — мотивация
- 8.2 sin x = a (геометрия + объединённая формула (-1)^n)
- 8.3 cos x = a (геометрия + ±arccos)
- 8.4 tg x = a (через ось тангенсов)
- 8.5 Особые случаи (a = 0, ±1) — полная таблица
- 8.6 Метод замены переменной
- 8.7 Метод разложения на множители
- 8.8 Однородные уравнения 1-й и 2-й степени

SVG (через ALG10.tri.canvas):
- sin x = a: окружность + горизонтальная линия y=a + 2 точки
- cos x = a: окружность + вертикальная линия x=a + 2 точки
- tg x = a: окружность + ось тангенсов + точка A_a + прямая через O

Интерактивы:
- ИВ1: 10 простейших уравнений (sin/cos/tg = a)
- ИВ2: 6 заданий 'сколько корней в промежутке'
- ИВ3: 5 заданий на замену переменной (квадратные относительно sin/cos)

Босс §8 — 6 этапов:
- 1: проверка |a|>1 → нет корней
- 2: подсчёт корней в [0;2π]
- 3: простейшее cos x = -1
- 4: квадратное относительно cos
- 5: проверка подстановкой
- 6: tg x = 1 → серия π/4 + πn

Обновлены ACH_LABELS (+p8_done), bumpProgress, SIDEBAR §8
(10 строк с формулами и особыми случаями), TIP §8.

Файл вырос со 141 KB до 160 KB (1888 → 2189 строк).
2026-05-29 11:07:03 +03:00

2184 lines
157 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 · Глава 1 · Тригонометрия</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:#ecfeff; --card:#fff; --card-soft:#f0fdfa; --text:#0f1a1f; --muted:#4b6671;
--border:#cffafe; --sh:0 1px 3px rgba(0,0,0,.06); --sh2:0 4px 14px rgba(0,0,0,.08);
--pri:#0d9488; --pri2:#0f766e; --pri-soft:#ccfbf1;
--acc:#14b8a6; --acc2:#0d9488; --acc-soft:#99f6e4;
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
}
.dark{--bg:#04181c; --card:#0a2329; --card-soft:#0e2c32; --text:#e0fbf9; --muted:#88aab1; --border:#1d4248}
*{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,#134e4a 0%,#0d9488 55%,#5eead4 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(204,251,241,.2);min-height:130px}
.hdr::before{content:'ГЛАВА 1';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,250,250,.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:'sin α';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(13,148,136,.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(13,148,136,.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(150px,1fr));gap:10px}
.psel-card{background:var(--card);border:1.5px solid var(--border);border-radius:13px;padding:12px;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:4px}
.psel-name{font-size:.82rem;font-weight:700;color:var(--text);line-height:1.3;margin-bottom:6px}
.psel-prog{height:4px;background:rgba(13,148,136,.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-p1"] { --sec-acc:#0d9488; --sec-acc-d:#0f766e; --sec-acc-soft:#ccfbf1; }
.sec[id="sec-p2"] { --sec-acc:#0891b2; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
.sec[id="sec-p3"] { --sec-acc:#16a34a; --sec-acc-d:#15803d; --sec-acc-soft:#dcfce7; }
.sec[id="sec-p4"] { --sec-acc:#7c3aed; --sec-acc-d:#6d28d9; --sec-acc-soft:#ede9fe; }
.sec[id="sec-p5"], .sec[id="sec-p6"], .sec[id="sec-p7"], .sec[id="sec-p8"],
.sec[id="sec-p9"], .sec[id="sec-p10"], .sec[id="sec-p11"], .sec[id="sec-p12"],
.sec[id="sec-final1"]{ --sec-acc:#0d9488; --sec-acc-d:#0f766e; --sec-acc-soft:#ccfbf1; }
.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(13,148,136,.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(13,148,136,.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,#0d9488,#14b8a6);color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(13,148,136,.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 control for interactives */
.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:88px}
.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}
.stub-soon{padding:30px 22px;text-align:center;background:linear-gradient(135deg,var(--pri-soft),var(--acc-soft));border:1.5px dashed var(--pri);border-radius:14px;color:var(--text)}
.stub-soon h3{font-family:'Unbounded',sans-serif;font-size:1.15rem;color:var(--pri2);margin-bottom:8px}
.stub-soon p{font-size:.92rem;color:var(--muted);max-width:520px;margin:0 auto}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-row">
<div>
<h1>Алгебра 10 · Глава 1</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>sin α</b> и <b>cos α</b> (координаты точки), <b>tg α</b> и <b>ctg α</b> (точки на касательных). Из них вырастают <b>графики</b>, <b>уравнения</b>, <b>формулы</b>.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p1')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 1</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"></div>
</div>
</section>
<section class="psel">
<div class="psel-title">Параграфы главы</div>
<div id="psel-grid" class="psel-grid"></div>
</section>
<section id="sec-p1" class="sec" data-watermark="P_α"><div class="sec-header"><span class="sec-num">§ 1</span><h2 class="sec-h">Единичная окружность. Градусная и радианная мера</h2></div><div id="p1-body"></div></section>
<section id="sec-p2" class="sec" data-watermark="sin"><div class="sec-header"><span class="sec-num">§ 2</span><h2 class="sec-h">Синус и косинус произвольного угла</h2></div><div id="p2-body"></div></section>
<section id="sec-p3" class="sec" data-watermark="tg"><div class="sec-header"><span class="sec-num">§ 3</span><h2 class="sec-h">Тангенс и котангенс произвольного угла</h2></div><div id="p3-body"></div></section>
<section id="sec-p4" class="sec" data-watermark="≡"><div class="sec-header"><span class="sec-num">§ 4</span><h2 class="sec-h">Тригонометрические тождества</h2></div><div id="p4-body"></div></section>
<section id="sec-p5" class="sec" data-watermark="∿"><div class="sec-header"><span class="sec-num">§ 5</span><h2 class="sec-h">Функции y = sin x и y = cos x</h2></div><div id="p5-body"></div></section>
<section id="sec-p6" class="sec" data-watermark="∿"><div class="sec-header"><span class="sec-num">§ 6</span><h2 class="sec-h">Функции y = tg x и y = ctg x</h2></div><div id="p6-body"></div></section>
<section id="sec-p7" class="sec" data-watermark="arc"><div class="sec-header"><span class="sec-num">§ 7</span><h2 class="sec-h">Арксинус, арккосинус, арктангенс, арккотангенс</h2></div><div id="p7-body"></div></section>
<section id="sec-p8" class="sec" data-watermark="="><div class="sec-header"><span class="sec-num">§ 8</span><h2 class="sec-h">Тригонометрические уравнения</h2></div><div id="p8-body"></div></section>
<section id="sec-p9" class="sec" data-watermark="↺"><div class="sec-header"><span class="sec-num">§ 9</span><h2 class="sec-h">Формулы приведения</h2></div><div id="p9-body"></div></section>
<section id="sec-p10" class="sec" data-watermark="±"><div class="sec-header"><span class="sec-num">§ 10</span><h2 class="sec-h">Синус, косинус, тангенс суммы и разности</h2></div><div id="p10-body"></div></section>
<section id="sec-p11" class="sec" data-watermark="2α"><div class="sec-header"><span class="sec-num">§ 11</span><h2 class="sec-h">Формулы двойного аргумента</h2></div><div id="p11-body"></div></section>
<section id="sec-p12" class="sec" data-watermark="·"><div class="sec-header"><span class="sec-num">§ 12</span><h2 class="sec-h">Преобразование суммы в произведение</h2></div><div id="p12-body"></div></section>
<section id="sec-final1" class="sec" data-watermark="★"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#0d9488,#5eead4)">Финал главы</span><h2 class="sec-h">Итоги. 6 боссов главы 1</h2></div><div id="final1-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 класс» · Глава 1 · Тригонометрия · 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:'p1', progress:{p1:0,p2:0,p3:0,p4:0,p5:0,p6:0,p7:0,p8:0,p9:0,p10:0,p11:0,p12:0,final1:0}, achievements:new Map(), xp:0, level:1 };
const TOTAL_PARAS = 13;
const _TB_SLUG = 'algebra-10-ch1';
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:'Начало главы 1!',
p1_done:'Окружность и углы — освоены!',
p2_done:'sin α и cos α — на ладони!',
p3_done:'tg α и ctg α — понимаешь!',
p4_done:'Тождества — твои!',
p5_done:'Графики sin x и cos x — мастер!',
p6_done:'Графики tg x и ctg x — знаешь!',
p7_done:'Обратные тригонометрические — освоены!',
p8_done:'Тригонометрические уравнения — решаешь!',
ch1_done:'Глава 1 — Тригонометрия пройдена!',
};
function loadProgress(){
try{
const s=localStorage.getItem('algebra10_ch1_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
const a=localStorage.getItem('algebra10_ch1_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_ch1_progress', JSON.stringify(STATE.progress));
localStorage.setItem('algebra10_ch1_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==='p1') achievement('p1_done');
else if(key==='p2') achievement('p2_done');
else if(key==='p3') achievement('p3_done');
else if(key==='p4') achievement('p4_done');
else if(key==='p5') achievement('p5_done');
else if(key==='p6') achievement('p6_done');
else if(key==='p7') achievement('p7_done');
else if(key==='p8') achievement('p8_done');
else if(key==='final1') achievement('ch1_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-ch1-'+(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:'p1', num:'§ 1', name:'Единичная окружность', sub:'град ↔ рад' },
{ id:'p2', num:'§ 2', name:'sin и cos', sub:'координаты P_α' },
{ id:'p3', num:'§ 3', name:'tg и ctg', sub:'оси тангенсов' },
{ id:'p4', num:'§ 4', name:'Тождества', sub:'sin² + cos² = 1' },
{ id:'p5', num:'§ 5', name:'y = sin x / cos x', sub:'графики' },
{ id:'p6', num:'§ 6', name:'y = tg x / ctg x', sub:'графики' },
{ id:'p7', num:'§ 7', name:'arcsin, arccos, arctg, arcctg', sub:'обратные' },
{ id:'p8', num:'§ 8', name:'Уравнения', sub:'sin x = a и др.' },
{ id:'p9', num:'§ 9', name:'Формулы приведения', sub:'π/2 ± α и др.' },
{ id:'p10',num:'§ 10', name:'Сумма и разность', sub:'sin(α±β)' },
{ id:'p11',num:'§ 11', name:'Двойной аргумент', sub:'sin 2α' },
{ id:'p12',num:'§ 12', name:'Сумма → произведение', sub:'sin α + sin β' },
{ id:'final1', num:'★', name:'Финал главы', sub:'6 боссов', 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 = { p1:()=>buildP1(), p2:()=>buildP2(), p3:()=>buildP3(), p4:()=>buildP4(),
p5:()=>buildP5(), p6:()=>buildP6(), p7:()=>buildP7(), p8:()=>buildP8(),
p9:()=>buildStub('p9','§9 — Формулы приведения'),
p10:()=>buildStub('p10','§10 — Синус, косинус, тангенс суммы и разности'),
p11:()=>buildStub('p11','§11 — Формулы двойного аргумента'),
p12:()=>buildStub('p12','§12 — Преобразование суммы в произведение'),
final1:()=>buildStub('final1','Финал главы 1 — 6 боссов')
};
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 = {
p1:{title:'Шпаргалка §1',rows:[
['Единичная окружн.','центр $(0;0)$, радиус $1$'],
['$P_\\alpha$','поворот $P_0(1;0)$ на $\\alpha$'],
['1 рад','$\\approx 57°$'],
['Перевод','град $\\cdot \\frac{\\pi}{180}$ → рад'],
['Перевод','рад $\\cdot \\frac{180}{\\pi}$ → град'],
['Полный оборот','$360° = 2\\pi$ рад'],
]},
p2:{title:'Шпаргалка §2',rows:[
['Опр.','$\\sin\\alpha = y_\\alpha$, $\\cos\\alpha = x_\\alpha$'],
['Область знач.','$-1 \\le \\sin\\alpha \\le 1$'],
['','$-1 \\le \\cos\\alpha \\le 1$'],
['I четверть','sin $+$, cos $+$'],
['II четверть','sin $+$, cos $-$'],
['III четверть','sin $-$, cos $-$'],
['IV четверть','sin $-$, cos $+$'],
]},
p3:{title:'Шпаргалка §3',rows:[
['Опр.','$\\tg\\alpha = \\frac{\\sin\\alpha}{\\cos\\alpha}$'],
['Опр.','$\\ctg\\alpha = \\frac{\\cos\\alpha}{\\sin\\alpha}$'],
['ОДЗ tg','$\\alpha \\ne \\frac{\\pi}{2} + \\pi n$'],
['ОДЗ ctg','$\\alpha \\ne \\pi n$'],
['Знаки','I: $+$, II: $-$, III: $+$, IV: $-$'],
['Произведение','$\\tg\\alpha \\cdot \\ctg\\alpha = 1$'],
]},
p4:{title:'Шпаргалка §4',rows:[
['Основное','$\\sin^2\\alpha + \\cos^2\\alpha = 1$'],
['Через tg','$1 + \\tg^2\\alpha = \\frac{1}{\\cos^2\\alpha}$'],
['Через ctg','$1 + \\ctg^2\\alpha = \\frac{1}{\\sin^2\\alpha}$'],
['Связь','$\\tg\\alpha \\cdot \\ctg\\alpha = 1$'],
['Знать одно','найти все 4'],
]},
p5:{title:'Шпаргалка §5',rows:[
['Период','$T = 2\\pi$'],
['$D(\\sin)$','$\\mathbb{R}$'],
['$E(\\sin)$','$[-1;\\,1]$'],
['sin — нечётная','$\\sin(-x) = -\\sin x$'],
['cos — чётная','$\\cos(-x) = \\cos x$'],
['Нули sin','$x = \\pi n$'],
['Нули cos','$x = \\frac{\\pi}{2} + \\pi n$'],
['Связь','$\\cos x = \\sin(x + \\frac{\\pi}{2})$'],
]},
p6:{title:'Шпаргалка §6',rows:[
['Период tg / ctg','$T = \\pi$'],
['$D(\\tg)$','$x \\ne \\frac{\\pi}{2} + \\pi n$'],
['$D(\\ctg)$','$x \\ne \\pi n$'],
['$E(\\tg) = E(\\ctg)$','$\\mathbb{R}$'],
['Асимптоты tg','$x = \\frac{\\pi}{2} + \\pi n$'],
['Асимптоты ctg','$x = \\pi n$'],
['tg — нечётная','$\\tg(-x) = -\\tg x$'],
['ctg — нечётная','$\\ctg(-x) = -\\ctg x$'],
]},
p7:{title:'Шпаргалка §7',rows:[
['$\\arcsin a$','$\\in [-\\frac{\\pi}{2};\\,\\frac{\\pi}{2}]$, $a \\in [-1;1]$'],
['$\\arccos a$','$\\in [0;\\,\\pi]$, $a \\in [-1;1]$'],
['$\\arctg a$','$\\in (-\\frac{\\pi}{2};\\,\\frac{\\pi}{2})$, $a \\in \\mathbb{R}$'],
['$\\arcctg a$','$\\in (0;\\,\\pi)$, $a \\in \\mathbb{R}$'],
['Связь','$\\arcsin a + \\arccos a = \\frac{\\pi}{2}$'],
['','$\\arctg a + \\arcctg a = \\frac{\\pi}{2}$'],
['Нечётные','$\\arcsin(-a) = -\\arcsin a$, $\\arctg$'],
['Не нечётные','$\\arccos(-a) = \\pi - \\arccos a$'],
]},
p8:{title:'Шпаргалка §8',rows:[
['$\\sin x = a$','$x = (-1)^n\\arcsin a + \\pi n$'],
['','при $|a| > 1$ — нет корней'],
['$\\cos x = a$','$x = \\pm\\arccos a + 2\\pi n$'],
['','при $|a| > 1$ — нет корней'],
['$\\tg x = a$','$x = \\arctg a + \\pi n$'],
['$\\ctg x = a$','$x = \\arcctg a + \\pi n$'],
['$\\sin x = 0$','$x = \\pi n$'],
['$\\sin x = 1$','$x = \\frac{\\pi}{2} + 2\\pi n$'],
['$\\cos x = 0$','$x = \\frac{\\pi}{2} + \\pi n$'],
['$\\cos x = 1$','$x = 2\\pi n$'],
]},
};
const TIPS=[
{sec:'p1',html:'Положительное направление — <b>против часовой</b>. $P_{450°}$ совпадает с $P_{90°}$ — лишний полный оборот.'},
{sec:'p2',html:'Запомни: <b>sin = ордината (y)</b>, <b>cos = абсцисса (x)</b>. Точка $P_\\alpha$ — это и есть пара $(\\cos\\alpha;\\,\\sin\\alpha)$.'},
{sec:'p3',html:'<b>Ось тангенсов</b> — касательная к окружности при $x=1$. Продолжение радиуса $OP_\\alpha$ упирается в эту ось — там и сидит значение tg α.'},
{sec:'p4',html:'Алгоритм «знаю одну → найду все»: 1) основное тождество даёт пару sin/cos; 2) знак выбираем по четверти; 3) tg = sin/cos; 4) ctg = 1/tg.'},
{sec:'p5',html:'$\\cos x$ — это $\\sin x$, сдвинутый <b>влево на $\\frac{\\pi}{2}$</b>. Графики выглядят одинаково, но смещены: где у sin ноль — у cos максимум, и наоборот.'},
{sec:'p6',html:'<b>tg x</b> имеет вертикальные асимптоты в $\\frac{\\pi}{2} + \\pi n$ (там, где $\\cos x = 0$). <b>ctg x</b> — в $\\pi n$ (там, где $\\sin x = 0$). Период <b>$\\pi$</b>, а не $2\\pi$ — это короче, чем у sin/cos.'},
{sec:'p7',html:'Главные значения: $\\arcsin$ и $\\arctg$ — <b>от $-\\frac{\\pi}{2}$ до $\\frac{\\pi}{2}$</b>; $\\arccos$ и $\\arcctg$ — <b>от $0$ до $\\pi$</b>. Это всегда!'},
{sec:'p8',html:'Перед формулой проверь: <b>$|a| > 1$ для sin и cos — корней НЕТ</b>. Если $a = 0, \\pm 1$ — используй <b>особые случаи</b>, они проще общих формул.'},
];
function buildSidebar(id){
const box=document.getElementById('sidebar-content');
const sb=SIDEBARS[id]||SIDEBARS.p1;
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"><div class="xp-card-title"><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)">✓ '+text+'</div>'; });
html+='</div>';
}
box.innerHTML=html;
if(window.renderMathInElement) try{ renderMath(box); }catch(e){}
}
function initTheme(){
const t=localStorage.getItem('algebra10_ch1_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_ch1_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={p1:'§1',p2:'§2',p3:'§3',p4:'§4',p5:'§5',p6:'§6',p7:'§7',p8:'§8',p9:'§9',p10:'§10',p11:'§11',p12:'§12',final1:'Финал'};
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){
/* bossDef: { color, title, steps:[{q, verify, hint}] } */
const idP = paraId+'-boss';
const SKEY = 'algebra10_ch1_'+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.textContent='✓ Побеждён'; 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('p1');
setTimeout(()=>achievement('start','Начало главы 1!'), 600);
}
document.addEventListener('DOMContentLoaded', init);
/* ============================================================
Заглушка для §5-§12 и финала
============================================================ */
function buildStub(paraId, title){
const box = document.getElementById(paraId+'-body');
box.innerHTML = '<div class="stub-soon">'
+'<h3>'+title+'</h3>'
+'<p>Этот параграф появится в одной из ближайших волн реализации. Сейчас доступны §1–§4 — базовый блок «единичная окружность + sin/cos + tg/ctg + тождества».</p>'
+'</div>'
+ secNav(paraId==='p5'?'p4':(paraId==='final1'?'p12':PARAS[PARAS.findIndex(p=>p.id===paraId)-1].id),
paraId==='final1'?null:PARAS[PARAS.findIndex(p=>p.id===paraId)+1].id);
}
/* ============================================================
§ 1 — Единичная окружность. Градусная и радианная мера
============================================================ */
function buildP1(){
const box = document.getElementById('p1-body');
const A = window.ALG10;
let html = '';
/* === Главный SVG: единичная окружность с делениями === */
let svgBase = '';
if(A){
const c = A.tri.canvas({id:'p1-base', W:340, H:340, R:130, bg:'#fff'});
let s = c.open
+ c.axes()
+ c.circle({width:2.5})
+ c.degreeMark(0) + c.degreeMark(30) + c.degreeMark(60) + c.degreeMark(90)
+ c.degreeMark(120)+ c.degreeMark(150) + c.degreeMark(180) + c.degreeMark(210)
+ c.degreeMark(240)+ c.degreeMark(270) + c.degreeMark(300) + c.degreeMark(330)
+ c.point(0, {label:'P_0', color:'#1e293b', labelOffset:18, fontSize:11})
+ c.point(Math.PI/3, {label:'P_{60°}', color:'#dc2626', labelOffset:18, fontSize:11})
+ c.radius(Math.PI/3, {color:'#dc2626'})
+ c.rotationArrow(Math.PI/3, {color:'#16a34a', r:35})
+ c.close;
svgBase = s;
}
/* === Slider-эксперимент: точка P_α на окружности === */
let svgSlider = '';
if(A){
const c = A.tri.canvas({id:'p1-sl', W:340, H:340, R:130, bg:'#fff'});
/* Заглушка — отрисует с углом 60°, динамика добавится при инициализации */
let s = c.open
+ c.axes()
+ c.circle({width:2})
+ c.point(0, {label:'P_0', color:'#94a3b8', labelOffset:18, fontSize:11})
+ '<g id="p1-sl-dyn"></g>'
+ c.close;
svgSlider = s;
}
html += makeCard('theory', 'Единичная окружность', '1.1', `
<p><b>Единичной (тригонометрической) окружностью</b> называется окружность с центром в начале координат и радиусом $R = 1$.</p>
<p>Начало отсчёта — точка $P_0(1;\\,0)$. <b>Положительное направление</b> движения по окружности — против часовой стрелки.</p>
<div class="svg-host">${svgBase}</div>
<p>Точка $P_\\alpha$ получается поворотом точки $P_0$ вокруг начала координат на угол $\\alpha$ — это базовая операция тригонометрии.</p>`);
html += makeCard('rule', 'Углы любой величины', '1.2', `
<p>В отличие от планиметрии, здесь угол может быть <b>любым действительным числом</b>:</p>
<ul style="padding-left:22px;line-height:1.85">
<li><b>$\\alpha > 0$</b> — поворот <b>против часовой</b>;</li>
<li><b>$\\alpha < 0$</b> — поворот <b>по часовой</b>;</li>
<li><b>$|\\alpha| > 360°$</b> — несколько полных оборотов плюс остаток.</li>
</ul>
<p>Например, $P_{450°} = P_{360° + 90°} = P_{90°}$ — лишний полный оборот не изменяет положения.</p>
<p>Общая формула: $P_\\alpha = P_{\\alpha + 360° \\cdot n}$ для любого целого $n$.</p>`);
html += makeCard('rule', 'Радианная мера', '1.3', `
<p>На единичной окружности длина дуги <b>равна</b> радианной мере соответствующего угла.</p>
<p>$1$ радиан — центральный угол, опирающийся на дугу длиной $1$ (то есть равную радиусу).</p>
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>$2\\pi$ рад $= 360°$</b>, поэтому <b>$1$ рад $= \\frac{180°}{\\pi} \\approx 57°$</b>.</p>
<p><b>Перевод:</b></p>
<ul style="padding-left:22px;line-height:1.9">
<li>град $\\to$ рад: <b>умножить на $\\dfrac{\\pi}{180}$</b>;</li>
<li>рад $\\to$ град: <b>умножить на $\\dfrac{180}{\\pi}$</b>.</li>
</ul>
<p>Примеры: $30° = \\dfrac{\\pi}{6}$, $45° = \\dfrac{\\pi}{4}$, $60° = \\dfrac{\\pi}{3}$, $90° = \\dfrac{\\pi}{2}$.</p>`);
html += makeCard('algo', 'Четверть угла', '1.4', `
<p>Чтобы определить, в какой четверти лежит угол $\\alpha$:</p>
<ol style="padding-left:22px;line-height:1.9">
<li>Если $\\alpha$ в радианах — переведи в градусы (по желанию).</li>
<li>Приведи к промежутку $[0°;\\,360°)$, отнимая или прибавляя нужное число оборотов.</li>
<li>Сравни:
<ul style="padding-left:18px;line-height:1.75">
<li>$[0°;\\,90°)$ — <b>I</b>;</li>
<li>$[90°;\\,180°)$ — <b>II</b>;</li>
<li>$[180°;\\,270°)$ — <b>III</b>;</li>
<li>$[270°;\\,360°)$ — <b>IV</b>.</li>
</ul>
</li>
</ol>
<p><b>Пример.</b> $\\alpha = 1300°$ → $1300° - 3 \\cdot 360° = 220°$ → III четверть.</p>`);
/* === ИНТЕРАКТИВ 1: Slider угла === */
html += '<div class="wg" id="p1-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Точка $P_\\alpha$ — крути угол</div></div>'
+'<div class="wg-help">Двигай ползунок угла от <b>-720°</b> до <b>+720°</b> и наблюдай, как точка $P_\\alpha$ перемещается по окружности.</div>'
+'<div class="slider-ctrl"><label>Угол α:</label><input type="range" id="p1-iv1-r" min="-720" max="720" step="5" value="60"><span class="val" id="p1-iv1-v">60°</span></div>'
+'<div class="svg-host">'+svgSlider+'</div>'
+'<div style="font-size:.86rem;color:var(--muted);text-align:center">Эквивалент в $[0°;\\,360°)$: <b id="p1-iv1-eq" style="color:var(--pri)">60°</b></div>'
+'</div>';
/* === ИНТЕРАКТИВ 2: Перевод град ↔ рад === */
html += '<div class="wg" id="p1-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Градусы ↔ радианы</div></div>'
+'<div class="wg-help">Введи ответ в виде дроби (например <b>5pi/6</b>) или числа (для градусов — без °).</div>'
+trainerHTML('p1-iv2', 8, 'ответ')
+'</div>';
/* === ИНТЕРАКТИВ 3: Четверть угла === */
html += '<div class="wg" id="p1-iv3">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">В какой четверти?</div></div>'
+'<div class="wg-help">Определи номер четверти (1, 2, 3, 4), в которой лежит угол.</div>'
+trainerHTML('p1-iv3', 6, 'номер')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §1 — Окружность и углы</h3>';
html += makeBoss('p1', {
color:'#0d9488',
title:'Босс §1 — Окружность и углы',
steps:[
{ q:'Сколько градусов в $\\pi$ радиан?', verify:(v)=>+v===180, hint:'$\\pi$ рад $= 180°$.' },
{ q:'Преобразуй $240°$ в радианы (введи как <b>4pi/3</b>).', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='4pi/3' || s==='4π/3';}, hint:'$240° \\cdot \\dfrac{\\pi}{180} = \\dfrac{4\\pi}{3}$.' },
{ q:'В какой четверти лежит угол $1300°$?', verify:(v)=>+v===3, hint:'$1300° - 3 \\cdot 360° = 220°$ — III четверть.' },
{ q:'Сколько различных точек $P_\\alpha$ дадут углы $\\frac{\\pi}{3}$, $-\\frac{\\pi}{3}$, $\\frac{7\\pi}{3}$, $-\\frac{5\\pi}{3}$?', verify:(v)=>+v===2, hint:'$\\frac{\\pi}{3} = \\frac{7\\pi}{3}$ (отличие $2\\pi$) и $-\\frac{\\pi}{3} = -\\frac{5\\pi}{3} + \\frac{2\\pi} \\cdot? $ — на самом деле $-\\frac{5\\pi}{3} = \\frac{\\pi}{3}$. Итого 2.' },
{ q:'Радианная мера двух углов треугольника — $\\frac{2\\pi}{5}$ и $\\frac{3\\pi}{10}$. Найди третий угол в градусах.', verify:(v)=>+v===54, hint:'Сумма $= \\pi$, третий $= \\pi - \\frac{2\\pi}{5} - \\frac{3\\pi}{10} = \\frac{3\\pi}{10}$ — это $54°$.' },
]
});
html += secNav(null, 'p2') + readButton('p1');
box.innerHTML = html; renderMath(box);
/* === Логика интерактивов === */
/* IV1: slider угла */
(function(){
const r = document.getElementById('p1-iv1-r');
const v = document.getElementById('p1-iv1-v');
const eq = document.getElementById('p1-iv1-eq');
const dyn = document.getElementById('p1-sl-dyn');
function redraw(deg){
v.textContent = deg + '°';
let mod = ((deg % 360) + 360) % 360;
eq.textContent = mod + '°';
if(!A || !dyn) return;
const c = A.tri.canvas({id:'p1-sl-h', W:340, H:340, R:130});
const rad = deg * Math.PI / 180;
dyn.innerHTML = c.radius(rad, {color:'#dc2626'})
+ c.point(rad, {label:'P_α', color:'#dc2626', labelOffset:18, fontSize:11})
+ c.rotationArrow(rad, {r:30});
}
r.addEventListener('input', e=>redraw(+e.target.value));
redraw(60);
})();
/* IV2: тренажёр перевода */
makeTrainer({
idPrefix:'p1-iv2',
parser:(v)=>v,
questions:[
{ q:'Преобразуй $30°$ в радианы. Введи как pi/n.', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/6'||s==='π/6';}, show:'$\\pi/6$' },
{ q:'Преобразуй $90°$ в радианы.', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/2'||s==='π/2';}, show:'$\\pi/2$' },
{ q:'Преобразуй $150°$ в радианы.', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='5pi/6'||s==='5π/6';}, show:'$5\\pi/6$' },
{ q:'Преобразуй $\\dfrac{\\pi}{4}$ в градусы.', a:(v)=>+v===45, show:'$45°$' },
{ q:'Преобразуй $\\dfrac{2\\pi}{3}$ в градусы.', a:(v)=>+v===120, show:'$120°$' },
{ q:'Преобразуй $\\dfrac{7\\pi}{6}$ в градусы.', a:(v)=>+v===210, show:'$210°$' },
{ q:'Преобразуй $-80°$ в радианы. Введи как -np/m.', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='-4pi/9'||s==='-4π/9';}, show:'$-4\\pi/9$' },
{ q:'Сколько градусов в $4$ радианах? (округли)', a:(v)=>+v===229, show:'$\\approx 229°$' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p1-iv2');bumpProgress('p1',30);} else if(s>=5){addXp(8,'p1-iv2');bumpProgress('p1',15);} }
});
/* IV3: четверть угла */
makeTrainer({
idPrefix:'p1-iv3',
questions:[
{ q:'$\\alpha = 126°$. Какая четверть?', a:2 },
{ q:'$\\alpha = 220°$. Какая четверть?', a:3 },
{ q:'$\\alpha = 7\\pi/10$. Какая четверть?', a:2 },
{ q:'$\\alpha = -\\pi/3$. Какая четверть?', a:4 },
{ q:'$\\alpha = 722°$. Какая четверть?', a:1 },
{ q:'$\\alpha = -189°$. Какая четверть?', a:2 },
],
onComplete:(s,n)=>{ if(s===n){addXp(15,'p1-iv3');bumpProgress('p1',25);} else if(s>=4){addXp(8,'p1-iv3');bumpProgress('p1',12);} }
});
wireReadBtn('p1');
}
/* ============================================================
§ 2 — Синус и косинус произвольного угла
============================================================ */
function buildP2(){
const box = document.getElementById('p2-body');
const A = window.ALG10;
let html = '';
/* === SVG 1: определение через координаты P_α === */
let svgDef = '';
if(A){
const c = A.tri.canvas({id:'p2-def', W:320, H:320, R:120});
const angle = 60 * Math.PI / 180;
let s = c.open
+ c.axes()
+ c.circle({width:2})
+ c.radius(angle, {color:'#dc2626'})
+ c.sinSegment(angle, {color:'#dc2626', label:'sin α', dash:'0', width:2.5})
+ c.cosSegment(angle, {color:'#2563eb', label:'cos α', dash:'0', width:2.5})
+ c.point(angle, {label:'P_α (cos α; sin α)', color:'#dc2626', labelOffset:20, fontSize:10})
+ c.close;
svgDef = s;
}
/* === SVG 2: знаки по четвертям === */
let svgSigns = '';
if(A){
const c = A.tri.canvas({id:'p2-signs', W:320, H:320, R:120});
let s = c.open
+ c.quadrant(1, {fill:'rgba(16,185,129,.15)'})
+ c.quadrant(2, {fill:'rgba(245,158,11,.15)'})
+ c.quadrant(3, {fill:'rgba(239,68,68,.15)'})
+ c.quadrant(4, {fill:'rgba(124,58,237,.15)'})
+ c.axes()
+ c.circle({width:2})
+ c.quadrantLabels({color:'#1e293b'})
/* Подписи знаков */
+ '<text x="220" y="115" text-anchor="middle" font-size="13" font-weight="800" fill="#065f46">sin +</text>'
+ '<text x="220" y="135" text-anchor="middle" font-size="13" font-weight="800" fill="#065f46">cos +</text>'
+ '<text x="100" y="115" text-anchor="middle" font-size="13" font-weight="800" fill="#92400e">sin +</text>'
+ '<text x="100" y="135" text-anchor="middle" font-size="13" font-weight="800" fill="#dc2626">cos </text>'
+ '<text x="100" y="225" text-anchor="middle" font-size="13" font-weight="800" fill="#dc2626">sin </text>'
+ '<text x="100" y="245" text-anchor="middle" font-size="13" font-weight="800" fill="#dc2626">cos </text>'
+ '<text x="220" y="225" text-anchor="middle" font-size="13" font-weight="800" fill="#dc2626">sin </text>'
+ '<text x="220" y="245" text-anchor="middle" font-size="13" font-weight="800" fill="#065f46">cos +</text>'
+ c.close;
svgSigns = s;
}
/* === SVG 3: точные значения для главных углов === */
let svgTable = '';
if(A){
const c = A.tri.canvas({id:'p2-tbl', W:340, H:340, R:130});
let s = c.open + c.axes() + c.circle({width:2});
const marks = [
{a:Math.PI/6, lab:'π/6', c:'#dc2626'},
{a:Math.PI/4, lab:'π/4', c:'#16a34a'},
{a:Math.PI/3, lab:'π/3', c:'#2563eb'},
{a:Math.PI/2, lab:'π/2', c:'#7c3aed'},
];
for(const m of marks){
s += c.radius(m.a, {color:m.c, width:1.8});
s += c.point(m.a, {color:m.c, label:m.lab, labelOffset:18, fontSize:11, r:3.5});
}
s += c.close;
svgTable = s;
}
html += makeCard('theory', 'Определение sin и cos', '2.1', `
<p>В планиметрии $\\sin\\alpha$ и $\\cos\\alpha$ были определены только для острого угла прямоугольного треугольника. Теперь обобщаем на любой угол.</p>
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b> Для любого угла $\\alpha$ точка $P_\\alpha$ единичной окружности имеет координаты $(\\cos\\alpha;\\,\\sin\\alpha)$:</p>
<p style="text-align:center;font-size:1.1rem;margin:10px 0">$\\sin\\alpha = y_\\alpha, \\quad \\cos\\alpha = x_\\alpha$</p>
<div class="svg-host">${svgDef}</div>
<p>Запомни: <b>sin — ордината (y)</b>, <b>cos — абсцисса (x)</b>.</p>`);
html += makeCard('rule', 'Область значений', '2.2', `
<p>Координаты любой точки единичной окружности лежат в $[-1;\\,1]$, поэтому:</p>
<p style="text-align:center;font-size:1.1rem;margin:10px 0">$-1 \\le \\sin\\alpha \\le 1, \\quad -1 \\le \\cos\\alpha \\le 1$</p>
<p>Значения, которые <b>не могут</b> быть синусами или косинусами: $\\sqrt{3}$, $-2$, $1{,}5$ — они вне отрезка $[-1;\\,1]$.</p>`);
html += makeCard('rule', 'Знаки sin/cos по четвертям', '2.3', `
<p>Знак $\\sin\\alpha$ совпадает со знаком ординаты точки $P_\\alpha$, а $\\cos\\alpha$ — со знаком абсциссы.</p>
<div class="svg-host">${svgSigns}</div>
<p><b>Мнемоника</b> для $\\sin\\alpha$: «положителен сверху от оси x» — то есть в I и II четвертях.</p>
<p><b>Для $\\cos\\alpha$:</b> «положителен справа от оси y» — I и IV четверти.</p>`);
html += makeCard('example', 'Значения для главных углов', '2.4', `
<p>Запомнить нужно только эти три:</p>
<table style="width:100%;border-collapse:collapse;margin:10px 0;font-size:.94rem">
<tr style="background:var(--sec-acc-soft)"><th style="padding:8px;border:1px solid var(--border)">α</th><th style="padding:8px;border:1px solid var(--border)">$\\pi/6$ ($30°$)</th><th style="padding:8px;border:1px solid var(--border)">$\\pi/4$ ($45°$)</th><th style="padding:8px;border:1px solid var(--border)">$\\pi/3$ ($60°$)</th></tr>
<tr><td style="padding:8px;border:1px solid var(--border);text-align:center"><b>sin α</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center">$\\frac{1}{2}$</td><td style="padding:8px;border:1px solid var(--border);text-align:center">$\\frac{\\sqrt{2}}{2}$</td><td style="padding:8px;border:1px solid var(--border);text-align:center">$\\frac{\\sqrt{3}}{2}$</td></tr>
<tr><td style="padding:8px;border:1px solid var(--border);text-align:center"><b>cos α</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center">$\\frac{\\sqrt{3}}{2}$</td><td style="padding:8px;border:1px solid var(--border);text-align:center">$\\frac{\\sqrt{2}}{2}$</td><td style="padding:8px;border:1px solid var(--border);text-align:center">$\\frac{1}{2}$</td></tr>
</table>
<p>Остальные значения находим через симметрии:</p>
<ul style="padding-left:22px;line-height:1.85">
<li>Через ось $x$: $\\sin(-\\alpha) = -\\sin\\alpha$, $\\cos(-\\alpha) = \\cos\\alpha$.</li>
<li>Через ось $y$: $\\sin(\\pi - \\alpha) = \\sin\\alpha$, $\\cos(\\pi - \\alpha) = -\\cos\\alpha$.</li>
<li>Через начало: $\\sin(\\alpha + \\pi) = -\\sin\\alpha$, $\\cos(\\alpha + \\pi) = -\\cos\\alpha$.</li>
</ul>
<div class="svg-host">${svgTable}</div>`);
/* === ИНТЕРАКТИВ 1: Знак sin/cos === */
html += '<div class="wg" id="p2-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Знаки sin и cos</div></div>'
+'<div class="wg-help">Введи знак: <b>+</b>, <b>-</b> (или <b>0</b> если значение равно нулю).</div>'
+trainerHTML('p2-iv1', 8, '+ или -')
+'</div>';
/* === ИНТЕРАКТИВ 2: Значение === */
html += '<div class="wg" id="p2-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Точные значения</div></div>'
+'<div class="wg-help">Введи ответ в виде дроби: <b>1/2</b>, <b>sqrt2/2</b>, <b>sqrt3/2</b>, <b>-1/2</b> и т.п. Знак минус — впереди.</div>'
+trainerHTML('p2-iv2', 6, 'значение')
+'</div>';
/* === ИНТЕРАКТИВ 3: Возможно ли? === */
html += '<div class="wg" id="p2-iv3">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Может ли так быть?</div></div>'
+'<div class="wg-help">Проверяй: $-1 \\le \\sin\\alpha \\le 1$ и $-1 \\le \\cos\\alpha \\le 1$. И $\\sin^2 + \\cos^2 = 1$.</div>'
+'<div class="score-display"><span>Задача <b id="p2-iv3-i">1</b> / 6</span><span>Очки: <b id="p2-iv3-s">0</b> / 6</span></div>'
+'<div id="p2-iv3-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1rem;text-align:center;margin-bottom:10px"></div>'
+'<div style="display:flex;gap:8px;justify-content:center"><button class="btn primary" id="p2-iv3-y" style="background:#10b981;border-color:#10b981">Да</button><button class="btn primary" id="p2-iv3-n" style="background:#dc2626;border-color:#dc2626">Нет</button></div>'
+'<div class="feedback" id="p2-iv3-fb"></div></div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §2 — sin и cos</h3>';
html += makeBoss('p2', {
color:'#0891b2',
title:'Босс §2 — sin и cos',
steps:[
{ q:'$\\sin\\dfrac{\\pi}{2} = ?$', verify:(v)=>+v===1, hint:'Точка $P_{\\pi/2} = (0;1)$, ордината $= 1$.' },
{ q:'$\\cos 180° = ?$', verify:(v)=>+v===-1, hint:'Точка $P_\\pi = (-1;0)$, абсцисса $= -1$.' },
{ q:'Точка $P_\\alpha = (3/5;\\,-4/5)$. Найди $\\sin\\alpha$ как дробь (введи -4/5).', verify:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-4/5'||+v===-0.8;}, hint:'sin = ордината.' },
{ q:'В каких четвертях $\\sin\\alpha > 0$? Введи через запятую: 1,2 или 3,4.', verify:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='1,2'||s==='2,1';}, hint:'Ордината положительна сверху от оси x.' },
{ q:'Может ли $\\sin\\alpha = \\sqrt{3}$? «да» или «нет»', verify:(v)=>String(v).trim().toLowerCase().startsWith('н'), hint:'$\\sqrt{3} \\approx 1{,}73 > 1$, а $\\sin\\alpha \\le 1$.' },
]
});
html += secNav('p1', 'p3') + readButton('p2');
box.innerHTML = html; renderMath(box);
/* IV1: знаки */
makeTrainer({
idPrefix:'p2-iv1',
parser:(v)=>v,
questions:[
{ q:'$\\sin 130°$ — какой знак?', a:(v)=>String(v).trim().startsWith('+'), show:'+ (II четв.)' },
{ q:'$\\cos 258°$ — какой знак?', a:(v)=>String(v).trim().startsWith('-')||String(v).trim()==='', show:' (III четв.)' },
{ q:'$\\sin(-150°)$ — какой знак?', a:(v)=>String(v).trim().startsWith('-')||String(v).trim()==='', show:' (III четв.)' },
{ q:'$\\cos(-340°)$ — какой знак?', a:(v)=>String(v).trim().startsWith('+'), show:'+ (I четв.)' },
{ q:'$\\sin 90°$ — какой знак?', a:(v)=>String(v).trim().startsWith('+'), show:'+ (равно 1)' },
{ q:'$\\cos 180°$ — какой знак?', a:(v)=>String(v).trim().startsWith('-')||String(v).trim()==='', show:' (равно 1)' },
{ q:'$\\sin\\pi$ — какой знак?', a:(v)=>+v===0||String(v).trim()==='0', show:'0' },
{ q:'$\\cos\\dfrac{3\\pi}{2}$ — какой знак?', a:(v)=>+v===0||String(v).trim()==='0', show:'0' },
],
onComplete:(s,n)=>{ if(s===n){addXp(15,'p2-iv1');bumpProgress('p2',25);} else if(s>=5){addXp(8,'p2-iv1');bumpProgress('p2',12);} }
});
/* IV2: точные значения */
makeTrainer({
idPrefix:'p2-iv2',
parser:(v)=>v,
questions:[
{ q:'$\\sin\\dfrac{\\pi}{6} = ?$', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='1/2'||+v===0.5;}, show:'$\\frac{1}{2}$' },
{ q:'$\\cos\\dfrac{\\pi}{3} = ?$', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='1/2'||+v===0.5;}, show:'$\\frac{1}{2}$' },
{ q:'$\\sin 90° = ?$', a:(v)=>+v===1, show:'1' },
{ q:'$\\cos 180° = ?$', a:(v)=>+v===-1, show:'$-1$' },
{ q:'$\\sin(-60°) = ?$ (введи -sqrt3/2 как ответ)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='-sqrt3/2'||s==='-√3/2';}, show:'$-\\frac{\\sqrt{3}}{2}$' },
{ q:'$\\cos 120° = ?$ (введи -1/2)', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-1/2'||+v===-0.5;}, show:'$-\\frac{1}{2}$' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p2-iv2');bumpProgress('p2',30);} else if(s>=3){addXp(9,'p2-iv2');bumpProgress('p2',15);} }
});
/* IV3: возможно ли */
(function(){
const Q=[
{ e:'$\\sin\\alpha = 5/13$ и $\\cos\\alpha = 12/13$ одновременно', ok:true, why:'$(5/13)^2 + (12/13)^2 = 169/169 = 1$ ✓' },
{ e:'$\\sin\\alpha = -0{,}3$ и $\\cos\\alpha = 0{,}4$ одновременно', ok:false, why:'$0{,}09 + 0{,}16 = 0{,}25 \\ne 1$.' },
{ e:'$\\sin\\alpha = 0{,}8$ и $\\cos\\alpha = 0{,}6$ одновременно', ok:true, why:'$0{,}64 + 0{,}36 = 1$ ✓' },
{ e:'$\\sin\\alpha = \\sqrt{3}$', ok:false, why:'$\\sqrt{3} \\approx 1{,}73 > 1$.' },
{ e:'$\\cos\\alpha = -1$', ok:true, why:'$\\cos\\pi = -1$.' },
{ e:'$\\sin\\alpha = 2$', ok:false, why:'$|\\sin\\alpha| \\le 1$.' },
];
let i=0,score=0;
function show(){
if(i>=Q.length){
document.getElementById('p2-iv3-q').innerHTML='<b>Готово!</b> '+score+' / '+Q.length;
if(score===Q.length){addXp(15,'p2-iv3');bumpProgress('p2',25);} else if(score>=4){addXp(8,'p2-iv3');bumpProgress('p2',12);}
return;
}
document.getElementById('p2-iv3-i').textContent=(i+1);
document.getElementById('p2-iv3-s').textContent=score;
document.getElementById('p2-iv3-q').innerHTML=Q[i].e;
renderMath(document.getElementById('p2-iv3-q'));
document.getElementById('p2-iv3-fb').style.display='none';
}
function ans(yes){
if(i>=Q.length) return;
const fb=document.getElementById('p2-iv3-fb');
if(yes===Q[i].ok){ score++; feedback(fb,true,'&#10003; Верно! '+Q[i].why); }
else feedback(fb,false,'&#10007; '+(Q[i].ok?'Да: ':'Нет: ')+Q[i].why);
document.getElementById('p2-iv3-s').textContent=score;
i++; setTimeout(show,1400);
}
document.getElementById('p2-iv3-y').addEventListener('click',()=>ans(true));
document.getElementById('p2-iv3-n').addEventListener('click',()=>ans(false));
show();
})();
wireReadBtn('p2');
}
/* ============================================================
§ 3 — Тангенс и котангенс произвольного угла
============================================================ */
function buildP3(){
const box = document.getElementById('p3-body');
const A = window.ALG10;
let html = '';
/* === SVG 1: ось тангенсов === */
let svgTg = '';
if(A){
const c = A.tri.canvas({id:'p3-tg', W:340, H:340, R:120});
const angle = 30 * Math.PI / 180;
let s = c.open
+ c.axes({xExt:c.R+40})
+ c.circle({width:2})
+ c.tgAxis()
+ c.radius(angle, {color:'#dc2626'})
+ c.point(angle, {label:'P_α', color:'#dc2626', labelOffset:14, fontSize:11})
+ c.tgValue(angle, {color:'#16a34a'})
+ c.close;
svgTg = s;
}
/* === SVG 2: ось котангенсов === */
let svgCtg = '';
if(A){
const c = A.tri.canvas({id:'p3-ctg', W:340, H:340, R:120});
const angle = 60 * Math.PI / 180;
let s = c.open
+ c.axes({yExt:c.R+40})
+ c.circle({width:2})
+ c.ctgAxis()
+ c.radius(angle, {color:'#dc2626'})
+ c.point(angle, {label:'P_α', color:'#dc2626', labelOffset:14, fontSize:11})
+ c.ctgValue(angle, {color:'#7c3aed'})
+ c.close;
svgCtg = s;
}
html += makeCard('theory', 'Определения', '3.1', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b> Тангенс и котангенс угла $\\alpha$:</p>
<p style="text-align:center;font-size:1.1rem;margin:10px 0">$\\tg\\alpha = \\dfrac{\\sin\\alpha}{\\cos\\alpha}, \\quad \\ctg\\alpha = \\dfrac{\\cos\\alpha}{\\sin\\alpha}$</p>
<p><b>ОДЗ:</b></p>
<ul style="padding-left:22px;line-height:1.85">
<li>$\\tg\\alpha$ существует, если $\\cos\\alpha \\ne 0$, то есть $\\alpha \\ne \\dfrac{\\pi}{2} + \\pi n$, $n \\in \\mathbb{Z}$.</li>
<li>$\\ctg\\alpha$ существует, если $\\sin\\alpha \\ne 0$, то есть $\\alpha \\ne \\pi n$, $n \\in \\mathbb{Z}$.</li>
</ul>
<p>Между ними простая связь: $\\tg\\alpha \\cdot \\ctg\\alpha = 1$ (если оба определены).</p>`);
html += makeCard('rule', 'Ось тангенсов', '3.2', `
<p>Геометрически tg α можно «увидеть»: проведём <b>касательную к окружности в точке $P_0(1;\\,0)$</b> — это прямая $x = 1$. Назовём её <b>осью тангенсов</b>.</p>
<p>Прямая $OP_\\alpha$ (или её продолжение) пересекает ось тангенсов в точке $A_\\alpha$. Координата $y$ этой точки и есть $\\tg\\alpha$.</p>
<div class="svg-host">${svgTg}</div>
<p>Если $P_\\alpha$ в I или IV четверти — $A_\\alpha$ строится через продолжение радиуса прямо; если во II или III — через продолжение радиуса в противоположную сторону.</p>`);
html += makeCard('rule', 'Ось котангенсов', '3.3', `
<p>Аналогично: касательная в точке $P_{\\pi/2}(0;\\,1)$ — это прямая $y = 1$. На ней «живёт» $\\ctg\\alpha$.</p>
<div class="svg-host">${svgCtg}</div>
<p>Координата $x$ точки пересечения — это $\\ctg\\alpha$.</p>`);
html += makeCard('algo', 'Знаки tg и ctg по четвертям', '3.4', `
<p>Так как $\\tg\\alpha = \\dfrac{\\sin\\alpha}{\\cos\\alpha}$, знак — произведение знаков sin и cos:</p>
<table style="width:100%;border-collapse:collapse;margin:10px 0;font-size:.94rem">
<tr style="background:var(--sec-acc-soft)"><th style="padding:8px;border:1px solid var(--border)">Четверть</th><th style="padding:8px;border:1px solid var(--border)">I</th><th style="padding:8px;border:1px solid var(--border)">II</th><th style="padding:8px;border:1px solid var(--border)">III</th><th style="padding:8px;border:1px solid var(--border)">IV</th></tr>
<tr><td style="padding:8px;border:1px solid var(--border);text-align:center"><b>sin</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#065f46">+</td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#065f46">+</td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#dc2626"></td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#dc2626"></td></tr>
<tr><td style="padding:8px;border:1px solid var(--border);text-align:center"><b>cos</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#065f46">+</td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#dc2626"></td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#dc2626"></td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#065f46">+</td></tr>
<tr style="background:var(--sec-acc-soft)"><td style="padding:8px;border:1px solid var(--border);text-align:center"><b>tg, ctg</b></td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#065f46">+</td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#dc2626"></td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#065f46">+</td><td style="padding:8px;border:1px solid var(--border);text-align:center;color:#dc2626"></td></tr>
</table>
<p><b>Запоминалка:</b> tg/ctg положительны в I и III четвертях, отрицательны во II и IV.</p>`);
/* === ИНТЕРАКТИВ 1: Существует ли? === */
html += '<div class="wg" id="p3-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Существует ли?</div></div>'
+'<div class="wg-help">tg α не существует, если cos α = 0 (то есть α = π/2 + πn). ctg α не существует, если sin α = 0 (α = πn).</div>'
+'<div class="score-display"><span>Задача <b id="p3-iv1-i">1</b> / 6</span><span>Очки: <b id="p3-iv1-s">0</b> / 6</span></div>'
+'<div id="p3-iv1-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1rem;text-align:center;margin-bottom:10px"></div>'
+'<div style="display:flex;gap:8px;justify-content:center"><button class="btn primary" id="p3-iv1-y" style="background:#10b981;border-color:#10b981">Существует</button><button class="btn primary" id="p3-iv1-n" style="background:#dc2626;border-color:#dc2626">Не существует</button></div>'
+'<div class="feedback" id="p3-iv1-fb"></div></div>';
/* === ИНТЕРАКТИВ 2: Знак tg/ctg === */
html += '<div class="wg" id="p3-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Знак tg / ctg</div></div>'
+'<div class="wg-help">Введи знак: <b>+</b> или <b>-</b>.</div>'
+trainerHTML('p3-iv2', 6, '+ или -')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §3 — tg и ctg</h3>';
html += makeBoss('p3', {
color:'#16a34a',
title:'Босс §3 — tg и ctg',
steps:[
{ q:'$\\tg\\pi = ?$', verify:(v)=>+v===0, hint:'$\\sin\\pi = 0$, $\\cos\\pi = -1$, $0/(-1) = 0$.' },
{ q:'Существует ли $\\tg\\dfrac{\\pi}{2}$? «да» или «нет»', verify:(v)=>String(v).trim().toLowerCase().startsWith('н'), hint:'$\\cos\\frac{\\pi}{2} = 0$, делить нельзя.' },
{ q:'$\\ctg\\dfrac{\\pi}{4} = ?$', verify:(v)=>+v===1, hint:'$\\cos\\frac{\\pi}{4} / \\sin\\frac{\\pi}{4} = 1$.' },
{ q:'Точка $P_\\alpha = (5/13;\\,-12/13)$. Найди $\\tg\\alpha$ (введи в виде десятичной дроби, например -2.4).', verify:(v)=>Math.abs(+v - (-12/5)) < 0.05, hint:'$\\tg\\alpha = -12/5 = -2{,}4$.' },
{ q:'В каких четвертях $\\tg\\alpha > 0$? Введи: 1,2 / 1,3 / 2,4 / 2,3.', verify:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='1,3'||s==='3,1';}, hint:'sin и cos одного знака — I и III.' },
]
});
html += secNav('p2', 'p4') + readButton('p3');
box.innerHTML = html; renderMath(box);
/* IV1: существует ли */
(function(){
const Q=[
{ e:'$\\tg 0$', ok:true, why:'$\\sin 0 / \\cos 0 = 0/1 = 0$.' },
{ e:'$\\tg \\dfrac{\\pi}{2}$', ok:false, why:'$\\cos\\frac{\\pi}{2} = 0$.' },
{ e:'$\\ctg 0$', ok:false, why:'$\\sin 0 = 0$.' },
{ e:'$\\ctg 2\\pi$', ok:false, why:'$\\sin 2\\pi = 0$.' },
{ e:'$\\tg\\left(-\\dfrac{5\\pi}{2}\\right)$', ok:false, why:'$-5\\pi/2 = -2\\pi - \\pi/2$, эквивалентен $-\\pi/2$, $\\cos = 0$.' },
{ e:'$\\ctg(-3\\pi)$', ok:false, why:'$-3\\pi = -2\\pi - \\pi$, эквивалентен $\\pi$, $\\sin\\pi = 0$.' },
];
let i=0,score=0;
function show(){
if(i>=Q.length){ document.getElementById('p3-iv1-q').innerHTML='<b>Готово!</b> '+score+' / '+Q.length; if(score===Q.length){addXp(15,'p3-iv1');bumpProgress('p3',25);} else if(score>=4){addXp(8,'p3-iv1');bumpProgress('p3',12);} return; }
document.getElementById('p3-iv1-i').textContent=(i+1);
document.getElementById('p3-iv1-s').textContent=score;
document.getElementById('p3-iv1-q').innerHTML=Q[i].e;
renderMath(document.getElementById('p3-iv1-q'));
document.getElementById('p3-iv1-fb').style.display='none';
}
function ans(yes){
if(i>=Q.length) return;
const fb=document.getElementById('p3-iv1-fb');
if(yes===Q[i].ok){ score++; feedback(fb,true,'&#10003; Верно! '+Q[i].why); }
else feedback(fb,false,'&#10007; '+(Q[i].ok?'Существует: ':'Не существует: ')+Q[i].why);
document.getElementById('p3-iv1-s').textContent=score;
i++; setTimeout(show,1500);
}
document.getElementById('p3-iv1-y').addEventListener('click',()=>ans(true));
document.getElementById('p3-iv1-n').addEventListener('click',()=>ans(false));
show();
})();
/* IV2: знаки tg/ctg */
makeTrainer({
idPrefix:'p3-iv2',
parser:(v)=>v,
questions:[
{ q:'$\\tg 118°$ — какой знак?', a:(v)=>String(v).trim().startsWith('-')||String(v).trim()==='', show:' (II четв.)' },
{ q:'$\\ctg 200°$ — какой знак?', a:(v)=>String(v).trim().startsWith('+'), show:'+ (III четв.)' },
{ q:'$\\tg(-50°)$ — какой знак?', a:(v)=>String(v).trim().startsWith('-')||String(v).trim()==='', show:' (IV четв.)' },
{ q:'$\\ctg 330°$ — какой знак?', a:(v)=>String(v).trim().startsWith('-')||String(v).trim()==='', show:' (IV четв.)' },
{ q:'$\\tg 240°$ — какой знак?', a:(v)=>String(v).trim().startsWith('+'), show:'+ (III четв.)' },
{ q:'$\\ctg(-100°)$ — какой знак?', a:(v)=>String(v).trim().startsWith('+'), show:'+ (III четв., $-100°+360° = 260°$)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(15,'p3-iv2');bumpProgress('p3',25);} else if(s>=4){addXp(8,'p3-iv2');bumpProgress('p3',12);} }
});
wireReadBtn('p3');
}
/* ============================================================
§ 4 — Тригонометрические тождества
============================================================ */
function buildP4(){
const box = document.getElementById('p4-body');
const A = window.ALG10;
let html = '';
/* === SVG 1: теорема Пифагора → основное тождество === */
let svgMain = '';
if(A){
const c = A.tri.canvas({id:'p4-main', W:320, H:320, R:120});
const angle = 50 * Math.PI / 180;
let s = c.open
+ c.axes()
+ c.circle({width:2})
+ c.radius(angle, {color:'#dc2626'})
+ c.sinSegment(angle, {color:'#dc2626', dash:'0', width:2.5})
+ c.cosSegment(angle, {color:'#2563eb', dash:'0', width:2.5})
+ c.point(angle, {color:'#dc2626', label:'P_α(x; y)', labelOffset:18, fontSize:10})
/* Подпись внизу */
+ '<text x="160" y="305" text-anchor="middle" font-size="12" font-family="JetBrains Mono,monospace" font-weight="700" fill="#0d9488">x² + y² = 1 ⇒ cos²α + sin²α = 1</text>'
+ c.close;
svgMain = s;
}
html += makeCard('rule', 'Основное тригонометрическое тождество', '4.1', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Теорема.</b> Для любого угла $\\alpha$:</p>
<p style="text-align:center;font-size:1.2rem;margin:10px 0">$\\sin^2\\alpha + \\cos^2\\alpha = 1$</p>
<div class="svg-host">${svgMain}</div>
<p><b>Доказательство.</b> Точка $P_\\alpha = (\\cos\\alpha;\\,\\sin\\alpha)$ лежит на единичной окружности, заданной уравнением $x^2 + y^2 = 1$. Подставляем $x = \\cos\\alpha$, $y = \\sin\\alpha$ — получаем тождество. ■</p>`);
html += makeCard('rule', 'Производные тождества', '4.2', `
<p>Из основного тождества выводим ещё три:</p>
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px;text-align:center">$\\tg\\alpha \\cdot \\ctg\\alpha = 1$ (если оба определены)</p>
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px;text-align:center">$1 + \\tg^2\\alpha = \\dfrac{1}{\\cos^2\\alpha}$ (при $\\cos\\alpha \\ne 0$)</p>
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px;text-align:center">$1 + \\ctg^2\\alpha = \\dfrac{1}{\\sin^2\\alpha}$ (при $\\sin\\alpha \\ne 0$)</p>
<details class="spoiler"><summary>Доказательство для $1 + \\tg^2 = 1/\\cos^2$</summary>
<div class="spoiler-body">
<p>Разделим основное тождество $\\sin^2\\alpha + \\cos^2\\alpha = 1$ на $\\cos^2\\alpha$:</p>
<p>$\\dfrac{\\sin^2\\alpha}{\\cos^2\\alpha} + 1 = \\dfrac{1}{\\cos^2\\alpha}$ ⇒ $\\tg^2\\alpha + 1 = \\dfrac{1}{\\cos^2\\alpha}$. ■</p>
</div></details>`);
html += makeCard('algo', 'Алгоритм «знаю одну → найду все»', '4.3', `
<p>Если известно одно тригонометрическое значение угла $\\alpha$ и четверть, в которой он лежит, найди остальные три.</p>
<ol style="padding-left:22px;line-height:1.95">
<li>Из основного тождества вырази недостающее (sin или cos).</li>
<li>Знак выбери по четверти.</li>
<li>$\\tg\\alpha = \\dfrac{\\sin\\alpha}{\\cos\\alpha}$.</li>
<li>$\\ctg\\alpha = \\dfrac{1}{\\tg\\alpha}$ (или $\\dfrac{\\cos\\alpha}{\\sin\\alpha}$).</li>
</ol>`);
html += makeCard('example', 'Пример', '4.4', `
<p><b>Задача.</b> $\\sin\\alpha = \\dfrac{3}{5}$, $\\alpha \\in \\left(\\dfrac{\\pi}{2};\\,\\pi\\right)$. Найди $\\cos\\alpha$, $\\tg\\alpha$, $\\ctg\\alpha$.</p>
<p><b>Решение.</b></p>
<ol style="padding-left:22px;line-height:1.95">
<li>$\\cos^2\\alpha = 1 - \\sin^2\\alpha = 1 - \\dfrac{9}{25} = \\dfrac{16}{25}$ ⇒ $\\cos\\alpha = \\pm \\dfrac{4}{5}$.</li>
<li>$\\alpha \\in (\\pi/2;\\pi)$ — II четверть, $\\cos\\alpha < 0$, значит $\\cos\\alpha = -\\dfrac{4}{5}$.</li>
<li>$\\tg\\alpha = \\dfrac{3/5}{-4/5} = -\\dfrac{3}{4}$.</li>
<li>$\\ctg\\alpha = -\\dfrac{4}{3}$.</li>
</ol>`);
/* === ИНТЕРАКТИВ 1: Найди недостающее === */
html += '<div class="wg" id="p4-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Найди cos α</div></div>'
+'<div class="wg-help">Известны sin α и четверть. Найди cos α как дробь или с десятичной точкой.</div>'
+trainerHTML('p4-iv1', 5, 'значение')
+'</div>';
/* === ИНТЕРАКТИВ 2: Упрости === */
html += '<div class="wg" id="p4-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Упрости выражение</div></div>'
+'<div class="wg-help">Используй $\\sin^2 + \\cos^2 = 1$ и $\\tg \\cdot \\ctg = 1$. Введи итоговое значение или выражение.</div>'
+trainerHTML('p4-iv2', 5, 'итог')
+'</div>';
/* === ИНТЕРАКТИВ 3: Найди tg, ctg === */
html += '<div class="wg" id="p4-iv3">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Найди tg α или ctg α</div></div>'
+'<div class="wg-help">$\\tg\\alpha = \\sin\\alpha / \\cos\\alpha$, $\\ctg\\alpha = 1 / \\tg\\alpha$.</div>'
+trainerHTML('p4-iv3', 5, 'значение')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §4 — Тождества</h3>';
html += makeBoss('p4', {
color:'#7c3aed',
title:'Босс §4 — Тождества',
steps:[
{ q:'Чему равно $\\sin^2 30° + \\cos^2 30°$?', verify:(v)=>+v===1, hint:'Основное тождество, всегда равно 1.' },
{ q:'$\\sin\\alpha = 5/13$ и $\\cos\\alpha = 12/13$. Возможно? «да»/«нет»', verify:(v)=>String(v).trim().toLowerCase().startsWith('д'), hint:'$25/169 + 144/169 = 1$ ✓.' },
{ q:'$\\sin\\alpha = -3/5$, $\\alpha \\in (\\pi; 3\\pi/2)$. Найди $\\cos\\alpha$ как дробь (введи -4/5).', verify:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-4/5'||+v===-0.8;}, hint:'$\\cos^2 = 16/25$, в III четверти $\\cos < 0$.' },
{ q:'Если $\\tg\\alpha = 0{,}75$, то $\\ctg\\alpha = ?$ (введи в виде десятичной дроби).', verify:(v)=>Math.abs(+v - 4/3) < 0.01, hint:'$\\ctg = 1/\\tg = 1/0{,}75 = 4/3 \\approx 1{,}33$.' },
{ q:'Упрости: $(1 + \\tg^2\\alpha) \\cdot \\cos^2\\alpha$. Чему равно?', verify:(v)=>+v===1, hint:'$1 + \\tg^2 = 1/\\cos^2$, значит произведение $= 1$.' },
]
});
html += secNav('p3', 'p5') + readButton('p4');
box.innerHTML = html; renderMath(box);
/* IV1: Найди cos α */
makeTrainer({
idPrefix:'p4-iv1',
parser:(v)=>v,
questions:[
{ q:'$\\sin\\alpha = 3/5$, $\\alpha \\in (0;\\pi/2)$. Найди $\\cos\\alpha$ (введи 4/5 или 0.8).', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='4/5'||+v===0.8;}, show:'$4/5 = 0{,}8$' },
{ q:'$\\sin\\alpha = 3/5$, $\\alpha \\in (\\pi/2;\\pi)$. Найди $\\cos\\alpha$.', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-4/5'||+v===-0.8;}, show:'$-4/5$' },
{ q:'$\\sin\\alpha = -5/13$, $\\alpha \\in (3\\pi/2;\\,2\\pi)$. Найди $\\cos\\alpha$.', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='12/13'||Math.abs(+v - 12/13)<0.01;}, show:'$12/13$' },
{ q:'$\\cos\\alpha = -4/5$, $\\alpha \\in (\\pi;3\\pi/2)$. Найди $\\sin\\alpha$.', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-3/5'||+v===-0.6;}, show:'$-3/5$' },
{ q:'$\\sin\\alpha = 0{,}8$, $\\alpha$ во II четв. Найди $\\cos\\alpha$.', a:(v)=>Math.abs(+v - (-0.6))<0.01, show:'$-0{,}6$' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p4-iv1');bumpProgress('p4',30);} else if(s>=3){addXp(9,'p4-iv1');bumpProgress('p4',15);} }
});
/* IV2: Упрости */
makeTrainer({
idPrefix:'p4-iv2',
parser:(v)=>v,
questions:[
{ q:'$3 - \\sin^2\\alpha - \\cos^2\\alpha = ?$', a:(v)=>+v===2, show:'2' },
{ q:'$\\cos^2\\alpha + \\sin^2\\alpha - 7 = ?$', a:(v)=>+v===-6, show:'$-6$' },
{ q:'$\\sin\\alpha \\cdot \\ctg\\alpha + \\cos\\alpha = ?$ (умножь на 1, выр-же $= 2\\cos\\alpha$, введи коэф-т)', a:(v)=>+v===2, show:'$2\\cos\\alpha$, коэф 2' },
{ q:'$(\\tg\\alpha + \\ctg\\alpha)^2 - (\\tg\\alpha - \\ctg\\alpha)^2 = ?$', a:(v)=>+v===4, show:'4' },
{ q:'$(1+\\ctg^2\\alpha)\\sin^2\\alpha = ?$', a:(v)=>+v===1, show:'1' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p4-iv2');bumpProgress('p4',30);} else if(s>=3){addXp(9,'p4-iv2');bumpProgress('p4',14);} }
});
/* IV3: tg, ctg */
makeTrainer({
idPrefix:'p4-iv3',
parser:(v)=>v,
questions:[
{ q:'$\\sin\\alpha = 3/5$, $\\cos\\alpha = -4/5$. Найди $\\tg\\alpha$ (как дробь).', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='-3/4'||+v===-0.75;}, show:'$-3/4$' },
{ q:'$\\tg\\alpha = 2$. Найди $\\ctg\\alpha$.', a:(v)=>+v===0.5, show:'$0{,}5$' },
{ q:'$\\sin\\alpha = 1/2$, $\\cos\\alpha = -\\sqrt{3}/2$. Найди $\\ctg\\alpha$ (введи как -sqrt3 или -1.73).', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='-sqrt3'||s==='-√3'||Math.abs(+v - (-Math.sqrt(3)))<0.05;}, show:'$-\\sqrt{3}$' },
{ q:'$\\tg\\alpha = 5$. Найди $\\dfrac{3\\sin\\alpha - \\cos\\alpha}{\\sin\\alpha + 2\\cos\\alpha}$.', a:(v)=>+v===2, show:'2 (разделить числитель и знаменатель на $\\cos\\alpha$)' },
{ q:'$\\ctg\\alpha = 1/2$. Найди $\\tg\\alpha$.', a:(v)=>+v===2, show:'2' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p4-iv3');bumpProgress('p4',30);} else if(s>=3){addXp(9,'p4-iv3');bumpProgress('p4',14);} }
});
wireReadBtn('p4');
}
/* ============================================================
§ 5 — Функции y = sin x и y = cos x. Свойства и графики
============================================================ */
function buildP5(){
const box = document.getElementById('p5-body');
const A = window.ALG10;
let html = '';
/* === SVG 1: график y = sin x на [-2π; 2π] === */
let svgSin = '';
if(A){
const f = A.func.canvas({id:'p5-sin', W:640, H:240, xRange:[-2*Math.PI, 2*Math.PI], yRange:[-1.6, 1.6], bg:'#fff'});
let s = f.open
+ f.grid({xStep:Math.PI/2, yStep:0.5, color:'#f1f5f9'})
+ f.axes({color:'#475569',
xTicks:[
{val:-2*Math.PI, label:'-2π'},{val:-3*Math.PI/2, label:'-3π/2'},
{val:-Math.PI, label:'-π'},{val:-Math.PI/2, label:'-π/2'},
{val:Math.PI/2, label:'π/2'},{val:Math.PI, label:'π'},
{val:3*Math.PI/2, label:'3π/2'},{val:2*Math.PI, label:'2π'}
],
yTicks:[{val:-1, label:'-1'}, {val:1, label:'1'}]
})
/* Полупрозрачные горизонтальные полоски области значений */
+ '<line x1="0" y1="'+f.pxY(1)+'" x2="'+f.W+'" y2="'+f.pxY(1)+'" stroke="#cbd5e1" stroke-width="1" stroke-dasharray="3 3"/>'
+ '<line x1="0" y1="'+f.pxY(-1)+'" x2="'+f.W+'" y2="'+f.pxY(-1)+'" stroke="#cbd5e1" stroke-width="1" stroke-dasharray="3 3"/>'
+ f.plot(x => Math.sin(x), {color:'#0d9488', width:2.8})
/* Точки максимума и минимума */
+ f.pointXY(Math.PI/2, 1, {color:'#dc2626', r:3.5, label:'max', dx:6, dy:-8, fontSize:10})
+ f.pointXY(-Math.PI/2, -1, {color:'#dc2626', r:3.5, label:'min', dx:6, dy:14, fontSize:10})
+ f.pointXY(3*Math.PI/2, -1, {color:'#dc2626', r:3.5})
+ f.pointXY(-3*Math.PI/2, 1, {color:'#dc2626', r:3.5})
+ f.close;
svgSin = s;
}
/* === SVG 2: график y = cos x === */
let svgCos = '';
if(A){
const f = A.func.canvas({id:'p5-cos', W:640, H:240, xRange:[-2*Math.PI, 2*Math.PI], yRange:[-1.6, 1.6], bg:'#fff'});
let s = f.open
+ f.grid({xStep:Math.PI/2, yStep:0.5, color:'#f1f5f9'})
+ f.axes({color:'#475569',
xTicks:[
{val:-2*Math.PI, label:'-2π'},{val:-Math.PI, label:'-π'},
{val:Math.PI, label:'π'},{val:2*Math.PI, label:'2π'}
],
yTicks:[{val:-1, label:'-1'}, {val:1, label:'1'}]
})
+ '<line x1="0" y1="'+f.pxY(1)+'" x2="'+f.W+'" y2="'+f.pxY(1)+'" stroke="#cbd5e1" stroke-width="1" stroke-dasharray="3 3"/>'
+ '<line x1="0" y1="'+f.pxY(-1)+'" x2="'+f.W+'" y2="'+f.pxY(-1)+'" stroke="#cbd5e1" stroke-width="1" stroke-dasharray="3 3"/>'
+ f.plot(x => Math.cos(x), {color:'#0891b2', width:2.8})
+ f.pointXY(0, 1, {color:'#dc2626', r:3.5, label:'max', dx:6, dy:-8, fontSize:10})
+ f.pointXY(Math.PI, -1, {color:'#dc2626', r:3.5, label:'min', dx:6, dy:14, fontSize:10})
+ f.pointXY(-Math.PI, -1, {color:'#dc2626', r:3.5})
+ f.pointXY(2*Math.PI, 1, {color:'#dc2626', r:3.5})
+ f.pointXY(-2*Math.PI, 1, {color:'#dc2626', r:3.5})
+ f.close;
svgCos = s;
}
/* === SVG 3: совмещённые sin и cos === */
let svgBoth = '';
if(A){
const f = A.func.canvas({id:'p5-both', W:640, H:240, xRange:[-2*Math.PI, 2*Math.PI], yRange:[-1.6, 1.6], bg:'#fff'});
let s = f.open
+ f.grid({xStep:Math.PI/2, yStep:0.5, color:'#f1f5f9'})
+ f.axes({color:'#475569',
xTicks:[{val:-Math.PI, label:'-π'},{val:Math.PI, label:'π'},{val:2*Math.PI, label:'2π'}],
yTicks:[{val:-1, label:'-1'}, {val:1, label:'1'}]
})
+ f.plot(x => Math.sin(x), {color:'#0d9488', width:2.5})
+ f.plot(x => Math.cos(x), {color:'#0891b2', width:2.5, dash:'5 4'})
/* Точка пересечения при x = π/4: sin = cos = √2/2 */
+ f.pointXY(Math.PI/4, Math.sqrt(2)/2, {color:'#dc2626', r:4, label:'π/4', dx:6, dy:-6, fontSize:10})
/* Легенда */
+ '<rect x="'+(f.W-130)+'" y="10" width="120" height="46" rx="6" fill="#fff" stroke="#cbd5e1" stroke-width="1"/>'
+ '<line x1="'+(f.W-120)+'" y1="25" x2="'+(f.W-100)+'" y2="25" stroke="#0d9488" stroke-width="2.5"/>'
+ '<text x="'+(f.W-94)+'" y="29" font-size="12" font-family="JetBrains Mono,monospace" fill="#0d9488" font-weight="700">sin x</text>'
+ '<line x1="'+(f.W-120)+'" y1="45" x2="'+(f.W-100)+'" y2="45" stroke="#0891b2" stroke-width="2.5" stroke-dasharray="5 4"/>'
+ '<text x="'+(f.W-94)+'" y="49" font-size="12" font-family="JetBrains Mono,monospace" fill="#0891b2" font-weight="700">cos x</text>'
+ f.close;
svgBoth = s;
}
html += makeCard('rule', 'Свойства функции y = sin x', '5.1', `
<p>На каждом числе $x$ значение $\\sin x$ — это ордината точки $P_x$ единичной окружности.</p>
<table style="width:100%;border-collapse:collapse;margin:8px 0;font-size:.92rem">
<tr style="background:var(--sec-acc-soft)"><th style="padding:6px;border:1px solid var(--border);text-align:left">Свойство</th><th style="padding:6px;border:1px solid var(--border);text-align:left">Значение</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Область определения</b></td><td style="padding:6px;border:1px solid var(--border)">$D(\\sin) = \\mathbb{R}$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Область значений</b></td><td style="padding:6px;border:1px solid var(--border)">$E(\\sin) = [-1;\\,1]$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Период</b></td><td style="padding:6px;border:1px solid var(--border)">$T = 2\\pi$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Чётность</b></td><td style="padding:6px;border:1px solid var(--border)">Нечётная: $\\sin(-x) = -\\sin x$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Нули</b></td><td style="padding:6px;border:1px solid var(--border)">$x = \\pi n$, $n \\in \\mathbb{Z}$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Возрастает</b></td><td style="padding:6px;border:1px solid var(--border)">на $\\left[-\\frac{\\pi}{2} + 2\\pi n;\\,\\frac{\\pi}{2} + 2\\pi n\\right]$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>max</b></td><td style="padding:6px;border:1px solid var(--border)">$1$ при $x = \\frac{\\pi}{2} + 2\\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>min</b></td><td style="padding:6px;border:1px solid var(--border)">$-1$ при $x = -\\frac{\\pi}{2} + 2\\pi n$</td></tr>
</table>`);
html += makeCard('rule', 'График y = sin x', '5.2', `
<p>График — <b>синусоида</b>. Повторяется каждые $2\\pi$.</p>
<div class="svg-host">${svgSin}</div>
<p>Красные точки — экстремумы. Кривая всегда лежит между $y = -1$ и $y = 1$.</p>`);
html += makeCard('rule', 'Свойства y = cos x', '5.3', `
<p>Свойства аналогичны синусу, но с двумя ключевыми отличиями:</p>
<table style="width:100%;border-collapse:collapse;margin:8px 0;font-size:.92rem">
<tr style="background:var(--sec-acc-soft)"><th style="padding:6px;border:1px solid var(--border);text-align:left">Свойство</th><th style="padding:6px;border:1px solid var(--border);text-align:left">Значение</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Область определения</b></td><td style="padding:6px;border:1px solid var(--border)">$D(\\cos) = \\mathbb{R}$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Область значений</b></td><td style="padding:6px;border:1px solid var(--border)">$E(\\cos) = [-1;\\,1]$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Период</b></td><td style="padding:6px;border:1px solid var(--border)">$T = 2\\pi$</td></tr>
<tr style="background:var(--warn-bg)"><td style="padding:6px;border:1px solid var(--border)"><b>Чётность</b></td><td style="padding:6px;border:1px solid var(--border)"><b>Чётная: $\\cos(-x) = \\cos x$</b></td></tr>
<tr style="background:var(--warn-bg)"><td style="padding:6px;border:1px solid var(--border)"><b>Нули</b></td><td style="padding:6px;border:1px solid var(--border)">$x = \\frac{\\pi}{2} + \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>max</b></td><td style="padding:6px;border:1px solid var(--border)">$1$ при $x = 2\\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>min</b></td><td style="padding:6px;border:1px solid var(--border)">$-1$ при $x = \\pi + 2\\pi n$</td></tr>
</table>`);
html += makeCard('rule', 'График y = cos x', '5.4', `
<p>График $y = \\cos x$ — та же синусоида, но <b>сдвинутая на $\\dfrac{\\pi}{2}$ влево</b>.</p>
<div class="svg-host">${svgCos}</div>
<p>Это значит: $\\cos x = \\sin\\left(x + \\dfrac{\\pi}{2}\\right)$.</p>
<div class="svg-host">${svgBoth}</div>
<p>На совмещённом графике видно: где у $\\sin x$ нули — у $\\cos x$ экстремумы, и наоборот.</p>`);
html += makeCard('algo', 'Преобразования графиков', '5.5', `
<p>Общий вид: $y = A \\sin(\\omega x + \\varphi) + b$, где:</p>
<ul style="padding-left:22px;line-height:1.85">
<li><b>$A$</b> — <b>амплитуда</b>: растяжение по оси $y$. $E = [-|A| + b;\\,|A| + b]$.</li>
<li><b>$\\omega$</b> — <b>частота</b>: новый период $T = \\dfrac{2\\pi}{|\\omega|}$.</li>
<li><b>$\\varphi$</b> — <b>начальная фаза</b>: сдвиг по оси $x$ на $-\\dfrac{\\varphi}{\\omega}$.</li>
<li><b>$b$</b> — сдвиг по оси $y$ (вверх или вниз).</li>
</ul>
<p>Поэкспериментируй с параметрами на следующем интерактиве!</p>`);
/* === ИНТЕРАКТИВ 1: Slider-эксперимент === */
html += '<div class="wg" id="p5-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">y = A · sin(ωx + φ) + b — крути параметры</div></div>'
+'<div class="wg-help">Двигай ползунки и смотри, как меняется график синусоиды.</div>'
+'<div class="slider-ctrl"><label>A (амплитуда):</label><input type="range" id="p5-A" min="-3" max="3" step="0.1" value="1"><span class="val" id="p5-Av">1.0</span></div>'
+'<div class="slider-ctrl"><label>ω (частота):</label><input type="range" id="p5-w" min="0.25" max="3" step="0.05" value="1"><span class="val" id="p5-wv">1.00</span></div>'
+'<div class="slider-ctrl"><label>φ (фаза):</label><input type="range" id="p5-ph" min="-3.14" max="3.14" step="0.05" value="0"><span class="val" id="p5-phv">0.00</span></div>'
+'<div class="slider-ctrl"><label>b (сдвиг):</label><input type="range" id="p5-b" min="-2" max="2" step="0.1" value="0"><span class="val" id="p5-bv">0.0</span></div>'
+'<div id="p5-formula" style="text-align:center;font-family:JetBrains Mono,monospace;font-size:1rem;color:var(--pri2);margin:10px 0;padding:8px;background:var(--sec-acc-soft);border-radius:8px"></div>'
+'<div class="svg-host" id="p5-iv1-svg"></div>'
+'</div>';
/* === ИНТЕРАКТИВ 2: Найди свойство === */
html += '<div class="wg" id="p5-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Свойства функций sin x и cos x</div></div>'
+'<div class="wg-help">Ответы — числа (период в виде «2pi», «pi/2» и т.д.), названия («чётная»/«нечётная»), или градусы.</div>'
+trainerHTML('p5-iv2', 7, 'ответ')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §5 — Графики sin и cos</h3>';
html += makeBoss('p5', {
color:'#0d9488',
title:'Босс §5 — Графики sin и cos',
steps:[
{ q:'Период функции $y = \\sin 2x$ — введи как pi/n или 2pi/n.', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi'||s==='π';}, hint:'$T = 2\\pi / \\omega = 2\\pi / 2 = \\pi$.' },
{ q:'$y = \\cos x$ — чётная или нечётная? Введи слово.', verify:(v)=>String(v).trim().toLowerCase().startsWith('чёт')||String(v).trim().toLowerCase().startsWith('чет'), hint:'$\\cos(-x) = \\cos x$.' },
{ q:'На каком из промежутков $[0;\\,2\\pi]$ функция $\\sin x$ <b>возрастает</b>? Введи правую границу как градусы: $\\pi/2$ → 90.', verify:(v)=>+v===90, hint:'$\\sin x$ возрастает на $[0; \\pi/2]$.' },
{ q:'Чему равно $\\sin\\left(\\dfrac{\\pi}{2} + 4\\pi\\right)$? (используй период)', verify:(v)=>+v===1, hint:'$4\\pi = 2 \\cdot 2\\pi$ — два полных периода. Эквивалентно $\\sin\\frac{\\pi}{2} = 1$.' },
{ q:'Сколько корней у уравнения $\\sin x = 0$ на $[0;\\,2\\pi]$?', verify:(v)=>+v===3, hint:'$x = 0, \\pi, 2\\pi$.' },
]
});
html += secNav('p4', 'p6') + readButton('p5');
box.innerHTML = html; renderMath(box);
/* IV1: slider experiment */
(function(){
const A_in = document.getElementById('p5-A');
const w_in = document.getElementById('p5-w');
const ph_in = document.getElementById('p5-ph');
const b_in = document.getElementById('p5-b');
const Av = document.getElementById('p5-Av');
const wv = document.getElementById('p5-wv');
const phv = document.getElementById('p5-phv');
const bv = document.getElementById('p5-bv');
const formula = document.getElementById('p5-formula');
const svgHost = document.getElementById('p5-iv1-svg');
function redraw(){
if(!A) return;
const Av0 = parseFloat(A_in.value);
const wv0 = parseFloat(w_in.value);
const phv0 = parseFloat(ph_in.value);
const bv0 = parseFloat(b_in.value);
Av.textContent = Av0.toFixed(1);
wv.textContent = wv0.toFixed(2);
phv.textContent = phv0.toFixed(2);
bv.textContent = bv0.toFixed(1);
formula.textContent = 'y = ' + Av0.toFixed(1) + ' · sin(' + wv0.toFixed(2) + 'x + ' + phv0.toFixed(2) + ') + ' + bv0.toFixed(1);
const f = A.func.canvas({id:'p5-iv1-c', W:640, H:240, xRange:[-2*Math.PI, 2*Math.PI], yRange:[-4.5, 4.5], bg:'#fff'});
let svg = f.open
+ f.grid({xStep:Math.PI/2, yStep:1, color:'#f1f5f9'})
+ f.axes({color:'#475569',
xTicks:[{val:-Math.PI, label:'-π'},{val:Math.PI, label:'π'},{val:2*Math.PI, label:'2π'}],
yTicks:[{val:-3, label:'-3'},{val:-1, label:'-1'},{val:1, label:'1'},{val:3, label:'3'}]
})
/* Базовый sin x пунктиром */
+ f.plot(x => Math.sin(x), {color:'#cbd5e1', width:1.5, dash:'4 3'})
/* Преобразованный график */
+ f.plot(x => Av0 * Math.sin(wv0 * x + phv0) + bv0, {color:'#0d9488', width:2.8})
+ f.close;
svgHost.innerHTML = svg;
}
[A_in, w_in, ph_in, b_in].forEach(el => el.addEventListener('input', redraw));
redraw();
})();
/* IV2: properties */
makeTrainer({
idPrefix:'p5-iv2',
parser:(v)=>v,
questions:[
{ q:'Чему равен период функции $y = \\sin x$? (введи как 2pi)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='2pi'||s==='2π';}, show:'$2\\pi$' },
{ q:'Период функции $y = \\cos 3x$? (введи как 2pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='2pi/3'||s==='2π/3';}, show:'$2\\pi/3$' },
{ q:'$y = \\sin x$ — чётная или нечётная? Введи слово.', a:(v)=>String(v).trim().toLowerCase().startsWith('нечёт')||String(v).trim().toLowerCase().startsWith('нечет'), show:'нечётная' },
{ q:'$y = \\cos x$ — чётная или нечётная? Введи слово.', a:(v)=>String(v).trim().toLowerCase().startsWith('чёт')||String(v).trim().toLowerCase().startsWith('чет'), show:'чётная' },
{ q:'Сколько нулей у $\\sin x$ на $[0;\\,2\\pi]$?', a:(v)=>+v===3, show:'3 (это $0, \\pi, 2\\pi$)' },
{ q:'Сколько нулей у $\\cos x$ на $[0;\\,2\\pi]$?', a:(v)=>+v===2, show:'2 (это $\\pi/2, 3\\pi/2$)' },
{ q:'Наибольшее значение $y = 3\\sin x + 1$? ', a:(v)=>+v===4, show:'4 (при sin = 1)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(20,'p5-iv2');bumpProgress('p5',35);} else if(s>=4){addXp(10,'p5-iv2');bumpProgress('p5',16);} }
});
wireReadBtn('p5');
}
/* ============================================================
§ 6 — Функции y = tg x и y = ctg x
============================================================ */
function buildP6(){
const box = document.getElementById('p6-body');
const A = window.ALG10;
let html = '';
/* === SVG 1: график y = tg x === */
let svgTg = '';
if(A){
const f = A.func.canvas({id:'p6-tg', W:640, H:280, xRange:[-2*Math.PI, 2*Math.PI], yRange:[-5, 5], bg:'#fff'});
let s = f.open
+ f.grid({xStep:Math.PI/2, yStep:1, color:'#f1f5f9'})
/* Асимптоты */
+ f.asymptoteV(-3*Math.PI/2, {color:'#dc2626'})
+ f.asymptoteV(-Math.PI/2, {color:'#dc2626'})
+ f.asymptoteV(Math.PI/2, {color:'#dc2626'})
+ f.asymptoteV(3*Math.PI/2, {color:'#dc2626'})
+ f.axes({color:'#475569',
xTicks:[
{val:-3*Math.PI/2, label:'-3π/2'},
{val:-Math.PI, label:'-π'},
{val:-Math.PI/2, label:'-π/2'},
{val:Math.PI/2, label:'π/2'},
{val:Math.PI, label:'π'},
{val:3*Math.PI/2, label:'3π/2'}
],
yTicks:[{val:-3, label:'-3'},{val:-1, label:'-1'},{val:1, label:'1'},{val:3, label:'3'}]
})
/* Tg x с авто-разрывами */
+ f.plot(x => {
/* Избегаем точек слишком близко к асимптотам */
const t = Math.tan(x);
if (Math.abs(t) > 12) return NaN;
return t;
}, {color:'#16a34a', width:2.8})
+ f.close;
svgTg = s;
}
/* === SVG 2: график y = ctg x === */
let svgCtg = '';
if(A){
const f = A.func.canvas({id:'p6-ctg', W:640, H:280, xRange:[-2*Math.PI, 2*Math.PI], yRange:[-5, 5], bg:'#fff'});
let s = f.open
+ f.grid({xStep:Math.PI/2, yStep:1, color:'#f1f5f9'})
+ f.asymptoteV(-2*Math.PI, {color:'#dc2626'})
+ f.asymptoteV(-Math.PI, {color:'#dc2626'})
+ f.asymptoteV(0, {color:'#dc2626'})
+ f.asymptoteV(Math.PI, {color:'#dc2626'})
+ f.asymptoteV(2*Math.PI, {color:'#dc2626'})
+ f.axes({color:'#475569',
xTicks:[
{val:-3*Math.PI/2, label:'-3π/2'},
{val:-Math.PI/2, label:'-π/2'},
{val:Math.PI/2, label:'π/2'},
{val:3*Math.PI/2, label:'3π/2'}
],
yTicks:[{val:-3, label:'-3'},{val:-1, label:'-1'},{val:1, label:'1'},{val:3, label:'3'}]
})
+ f.plot(x => {
const c = 1 / Math.tan(x);
if (Math.abs(c) > 12) return NaN;
return c;
}, {color:'#7c3aed', width:2.8})
+ f.close;
svgCtg = s;
}
html += makeCard('rule', 'Свойства y = tg x', '6.1', `
<table style="width:100%;border-collapse:collapse;margin:8px 0;font-size:.92rem">
<tr style="background:var(--sec-acc-soft)"><th style="padding:6px;border:1px solid var(--border);text-align:left">Свойство</th><th style="padding:6px;border:1px solid var(--border);text-align:left">Значение</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$D(\\tg)$</b></td><td style="padding:6px;border:1px solid var(--border)">$x \\ne \\dfrac{\\pi}{2} + \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$E(\\tg)$</b></td><td style="padding:6px;border:1px solid var(--border)">$\\mathbb{R}$ — все действительные числа</td></tr>
<tr style="background:var(--warn-bg)"><td style="padding:6px;border:1px solid var(--border)"><b>Период</b></td><td style="padding:6px;border:1px solid var(--border)"><b>$T = \\pi$</b> (вдвое короче, чем у sin/cos!)</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Чётность</b></td><td style="padding:6px;border:1px solid var(--border)">Нечётная: $\\tg(-x) = -\\tg x$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Нули</b></td><td style="padding:6px;border:1px solid var(--border)">$x = \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Асимптоты</b></td><td style="padding:6px;border:1px solid var(--border)">$x = \\dfrac{\\pi}{2} + \\pi n$ (вертикальные)</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Монотонность</b></td><td style="padding:6px;border:1px solid var(--border)">Возрастает на $\\left(-\\dfrac{\\pi}{2} + \\pi n;\\,\\dfrac{\\pi}{2} + \\pi n\\right)$</td></tr>
</table>`);
html += makeCard('rule', 'График y = tg x', '6.2', `
<p>Тангенс не похож на синусоиду — это <b>«ветви»</b>, разорванные вертикальными асимптотами.</p>
<div class="svg-host">${svgTg}</div>
<p>Красные пунктирные линии — асимптоты. На каждом промежутке между ними функция возрастает от $-\\infty$ до $+\\infty$.</p>`);
html += makeCard('rule', 'Свойства y = ctg x', '6.3', `
<table style="width:100%;border-collapse:collapse;margin:8px 0;font-size:.92rem">
<tr style="background:var(--sec-acc-soft)"><th style="padding:6px;border:1px solid var(--border);text-align:left">Свойство</th><th style="padding:6px;border:1px solid var(--border);text-align:left">Значение</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$D(\\ctg)$</b></td><td style="padding:6px;border:1px solid var(--border)">$x \\ne \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$E(\\ctg)$</b></td><td style="padding:6px;border:1px solid var(--border)">$\\mathbb{R}$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Период</b></td><td style="padding:6px;border:1px solid var(--border)">$T = \\pi$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Чётность</b></td><td style="padding:6px;border:1px solid var(--border)">Нечётная</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Нули</b></td><td style="padding:6px;border:1px solid var(--border)">$x = \\dfrac{\\pi}{2} + \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Асимптоты</b></td><td style="padding:6px;border:1px solid var(--border)">$x = \\pi n$</td></tr>
<tr style="background:var(--warn-bg)"><td style="padding:6px;border:1px solid var(--border)"><b>Монотонность</b></td><td style="padding:6px;border:1px solid var(--border)"><b>Убывает</b> на $(\\pi n;\\,\\pi + \\pi n)$</td></tr>
</table>`);
html += makeCard('rule', 'График y = ctg x', '6.4', `
<p>Котангенс — «зеркало» тангенса: те же ветви, но <b>убывающие</b>, и сдвинуты на $\\frac{\\pi}{2}$.</p>
<div class="svg-host">${svgCtg}</div>
<p>Связь: $\\ctg x = \\tg\\left(\\dfrac{\\pi}{2} - x\\right)$.</p>`);
/* === ИНТЕРАКТИВ === */
html += '<div class="wg" id="p6-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Свойства tg x и ctg x</div></div>'
+'<div class="wg-help">Период обоих $= \\pi$. Асимптоты — там, где знаменатель = 0.</div>'
+trainerHTML('p6-iv1', 6, 'ответ')
+'</div>';
html += '<div class="wg" id="p6-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Сравни значения по графику</div></div>'
+'<div class="wg-help">Используй монотонность: $\\tg$ <b>возрастает</b>, $\\ctg$ <b>убывает</b> на главном промежутке.</div>'
+'<div class="score-display"><span>Задача <b id="p6-iv2-i">1</b> / 5</span><span>Очки: <b id="p6-iv2-s">0</b> / 5</span></div>'
+'<div id="p6-iv2-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1rem;text-align:center;margin-bottom:10px"></div>'
+'<div style="display:flex;gap:8px;justify-content:center"><button class="btn primary" id="p6-iv2-lt" style="background:#10b981;border-color:#10b981">&lt;</button><button class="btn primary" id="p6-iv2-eq" style="background:#f59e0b;border-color:#f59e0b">=</button><button class="btn primary" id="p6-iv2-gt" style="background:#dc2626;border-color:#dc2626">&gt;</button></div>'
+'<div class="feedback" id="p6-iv2-fb"></div></div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §6 — Графики tg и ctg</h3>';
html += makeBoss('p6', {
color:'#16a34a',
title:'Босс §6 — Графики tg и ctg',
steps:[
{ q:'Период функции $y = \\tg x$ — введи как pi/n или просто pi.', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi'||s==='π';}, hint:'$T = \\pi$.' },
{ q:'Период функции $y = \\tg 2x$? (введи pi/n)', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/2'||s==='π/2';}, hint:'$T = \\pi / 2$.' },
{ q:'Где у $\\tg x$ вертикальные асимптоты? Введи общую формулу в виде «pi/2+pi*n» (без пробелов).', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/2+pi*n'||s==='pi/2+pin'||s==='π/2+πn'||s==='π/2+π*n';}, hint:'Там, где $\\cos x = 0$.' },
{ q:'$\\tg x$ — возрастает или убывает на главном промежутке? Введи слово.', verify:(v)=>String(v).trim().toLowerCase().startsWith('возр'), hint:'От $-\\infty$ до $+\\infty$.' },
{ q:'$\\ctg x$ — возрастает или убывает? Введи слово.', verify:(v)=>String(v).trim().toLowerCase().startsWith('убыв'), hint:'От $+\\infty$ до $-\\infty$.' },
]
});
html += secNav('p5', 'p7') + readButton('p6');
box.innerHTML = html; renderMath(box);
/* IV1 */
makeTrainer({
idPrefix:'p6-iv1',
parser:(v)=>v,
questions:[
{ q:'Период $y = \\tg x$? (введи pi)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi'||s==='π';}, show:'$\\pi$' },
{ q:'Период $y = \\ctg 3x$? (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/3'||s==='π/3';}, show:'$\\pi/3$' },
{ q:'$\\tg x$ — чётная или нечётная? Введи слово.', a:(v)=>String(v).trim().toLowerCase().startsWith('нечёт')||String(v).trim().toLowerCase().startsWith('нечет'), show:'нечётная' },
{ q:'Сколько нулей у $\\tg x$ на $[0;\\,2\\pi]$?', a:(v)=>+v===3, show:'3 (0, π, 2π)' },
{ q:'Сколько вертикальных асимптот у $\\tg x$ на $(0;\\,2\\pi)$?', a:(v)=>+v===2, show:'2 (π/2 и 3π/2)' },
{ q:'$\\tg 0 = ?$', a:(v)=>+v===0, show:'0' },
],
onComplete:(s,n)=>{ if(s===n){addXp(15,'p6-iv1');bumpProgress('p6',30);} else if(s>=4){addXp(8,'p6-iv1');bumpProgress('p6',14);} }
});
/* IV2: compare */
(function(){
const Q=[
{ e:'Сравни $\\tg 30°$ и $\\tg 45°$', ans:'lt' },
{ e:'Сравни $\\tg 60°$ и $\\tg 80°$', ans:'lt' },
{ e:'Сравни $\\ctg 30°$ и $\\ctg 60°$', ans:'gt' },
{ e:'Сравни $\\tg(-30°)$ и $\\tg 30°$', ans:'lt' },
{ e:'Сравни $\\tg 45°$ и $\\ctg 45°$', ans:'eq' },
];
let i=0,score=0;
function show(){
if(i>=Q.length){ document.getElementById('p6-iv2-q').innerHTML='<b>Готово!</b> '+score+' / '+Q.length; if(score===Q.length){addXp(15,'p6-iv2');bumpProgress('p6',25);} else if(score>=3){addXp(8,'p6-iv2');bumpProgress('p6',12);} return; }
document.getElementById('p6-iv2-i').textContent=(i+1);
document.getElementById('p6-iv2-s').textContent=score;
document.getElementById('p6-iv2-q').innerHTML=Q[i].e;
renderMath(document.getElementById('p6-iv2-q'));
document.getElementById('p6-iv2-fb').style.display='none';
}
function ans(a){
if(i>=Q.length) return;
const fb=document.getElementById('p6-iv2-fb');
if(a===Q[i].ans){ score++; feedback(fb,true,'&#10003; Верно!'); }
else{ const lab={lt:'<',eq:'=',gt:'>'}; feedback(fb,false,'&#10007; Правильно: <b>'+lab[Q[i].ans]+'</b>'); }
document.getElementById('p6-iv2-s').textContent=score;
i++; setTimeout(show,1200);
}
document.getElementById('p6-iv2-lt').addEventListener('click',()=>ans('lt'));
document.getElementById('p6-iv2-eq').addEventListener('click',()=>ans('eq'));
document.getElementById('p6-iv2-gt').addEventListener('click',()=>ans('gt'));
show();
})();
wireReadBtn('p6');
}
/* ============================================================
§ 7 — Арксинус, арккосинус, арктангенс, арккотангенс
============================================================ */
function buildP7(){
const box = document.getElementById('p7-body');
const A = window.ALG10;
let html = '';
/* === SVG: 4 графика обратных функций === */
function plotInverse(id, fn, xRange, yRange, color, title){
if(!A) return '';
const f = A.func.canvas({id, W:280, H:240, xRange, yRange, bg:'#fff'});
let s = f.open
+ f.grid({xStep:1, yStep:0.5, color:'#f1f5f9'})
+ f.axes({color:'#475569',
xTicks:[{val:-1, label:'-1'},{val:1, label:'1'}],
yTicks:[
{val:-Math.PI/2, label:'-π/2'},
{val:0, label:'0'},
{val:Math.PI/2, label:'π/2'},
{val:Math.PI, label:'π'}
].filter(t => t.val >= yRange[0] && t.val <= yRange[1])
})
+ f.plot(fn, {color, width:2.5, step:(xRange[1]-xRange[0])/200})
+ '<text x="140" y="22" text-anchor="middle" font-size="13" font-family="Unbounded,Inter,sans-serif" font-weight="800" fill="'+color+'">'+title+'</text>'
+ f.close;
return s;
}
const svgAsin = plotInverse('p7-asin', Math.asin, [-1.05, 1.05], [-Math.PI/2 - 0.2, Math.PI/2 + 0.2], '#0d9488', 'y = arcsin x');
const svgAcos = plotInverse('p7-acos', Math.acos, [-1.05, 1.05], [-0.2, Math.PI + 0.2], '#0891b2', 'y = arccos x');
const svgAtg = plotInverse('p7-atg', Math.atan, [-4, 4], [-Math.PI/2 - 0.2, Math.PI/2 + 0.2], '#16a34a', 'y = arctg x');
const svgActg = plotInverse('p7-actg', x => Math.PI/2 - Math.atan(x), [-4, 4], [-0.2, Math.PI + 0.2], '#7c3aed', 'y = arcctg x');
html += makeCard('theory', 'Зачем обратные функции', '7.1', `
<p>Уравнение $\\sin x = \\dfrac{1}{2}$ имеет бесконечно много решений ($x = \\dfrac{\\pi}{6} + 2\\pi n$ и $x = \\pi - \\dfrac{\\pi}{6} + 2\\pi n$).</p>
<p>Если хочется записать <b>одно</b> «опорное» решение, мы выбираем <b>главное значение</b> — это и есть $\\arcsin\\dfrac{1}{2}$.</p>`);
html += makeCard('rule', 'arcsin a', '7.2', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b> $\\arcsin a$ — это <b>такое число</b> $\\alpha \\in \\left[-\\dfrac{\\pi}{2};\\,\\dfrac{\\pi}{2}\\right]$, что $\\sin\\alpha = a$.</p>
<p>Существует только при $a \\in [-1;\\,1]$. Главные значения:</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)">$a$</th><th>$0$</th><th>$\\frac{1}{2}$</th><th>$\\frac{\\sqrt{2}}{2}$</th><th>$\\frac{\\sqrt{3}}{2}$</th><th>$1$</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$\\arcsin a$</b></td><td style="padding:6px;border:1px solid var(--border);text-align:center">$0$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{6}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{4}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{3}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{2}$</td></tr>
</table>
<p>$\\arcsin$ — <b>нечётная</b>: $\\arcsin(-a) = -\\arcsin a$.</p>
<div class="svg-host">${svgAsin}</div>`);
html += makeCard('rule', 'arccos a', '7.3', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b> $\\arccos a$ — это <b>такое число</b> $\\alpha \\in [0;\\,\\pi]$, что $\\cos\\alpha = a$.</p>
<p>Существует только при $a \\in [-1;\\,1]$. Главные значения:</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)">$a$</th><th>$1$</th><th>$\\frac{\\sqrt{3}}{2}$</th><th>$\\frac{\\sqrt{2}}{2}$</th><th>$\\frac{1}{2}$</th><th>$0$</th><th>$-1$</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$\\arccos a$</b></td><td style="padding:6px;border:1px solid var(--border);text-align:center">$0$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{6}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{4}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{3}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\frac{\\pi}{2}$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\pi$</td></tr>
</table>
<p style="background:var(--warn-bg);padding:9px 13px;border-radius:8px;border-left:4px solid var(--warn)"><b>Важно:</b> $\\arccos$ <b>не является нечётной</b>! $\\arccos(-a) = \\pi - \\arccos a$.</p>
<div class="svg-host">${svgAcos}</div>`);
html += makeCard('rule', 'arctg a и arcctg a', '7.4', `
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b></p>
<ul style="padding-left:22px;line-height:1.85">
<li>$\\arctg a$ — такое $\\alpha \\in \\left(-\\dfrac{\\pi}{2};\\,\\dfrac{\\pi}{2}\\right)$, что $\\tg\\alpha = a$. Определено для всех $a \\in \\mathbb{R}$.</li>
<li>$\\arcctg a$ — такое $\\alpha \\in (0;\\,\\pi)$, что $\\ctg\\alpha = a$. Определено для всех $a \\in \\mathbb{R}$.</li>
</ul>
<p>Главные значения: $\\arctg 0 = 0$, $\\arctg 1 = \\dfrac{\\pi}{4}$, $\\arctg\\sqrt{3} = \\dfrac{\\pi}{3}$, $\\arctg\\dfrac{1}{\\sqrt{3}} = \\dfrac{\\pi}{6}$.</p>
<p>$\\arctg$ — <b>нечётная</b>: $\\arctg(-a) = -\\arctg a$. $\\arcctg$ — нет: $\\arcctg(-a) = \\pi - \\arcctg a$.</p>
<div class="svg-host-row">${svgAtg}${svgActg}</div>`);
html += makeCard('rule', 'Полезные связки', '7.5', `
<p>Эти две формулы стоит запомнить:</p>
<p style="text-align:center;font-size:1.1rem;margin:10px 0">$\\arcsin a + \\arccos a = \\dfrac{\\pi}{2}$</p>
<p style="text-align:center;font-size:1.1rem;margin:10px 0">$\\arctg a + \\arcctg a = \\dfrac{\\pi}{2}$</p>
<p>Например, $\\arccos\\dfrac{1}{2} = \\dfrac{\\pi}{2} - \\arcsin\\dfrac{1}{2} = \\dfrac{\\pi}{2} - \\dfrac{\\pi}{6} = \\dfrac{\\pi}{3}$.</p>`);
/* === ИНТЕРАКТИВ 1: Главные значения === */
html += '<div class="wg" id="p7-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Найди главное значение</div></div>'
+'<div class="wg-help">Ответ — в виде дроби: <b>pi/6</b>, <b>pi/3</b>, <b>-pi/4</b>, или просто число (для нуля).</div>'
+trainerHTML('p7-iv1', 8, 'значение')
+'</div>';
/* === ИНТЕРАКТИВ 2: arc(sin(α)) vs α === */
html += '<div class="wg" id="p7-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">arcsin(sin α) vs α</div></div>'
+'<div class="wg-help">$\\sin(\\arcsin a) = a$ всегда. Но $\\arcsin(\\sin\\alpha) = \\alpha$ <b>только если</b> $\\alpha \\in [-\\pi/2;\\,\\pi/2]$. Иначе нужно привести!</div>'
+trainerHTML('p7-iv2', 5, 'ответ')
+'</div>';
/* === БОСС === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §7 — Обратные функции</h3>';
html += makeBoss('p7', {
color:'#7c3aed',
title:'Босс §7 — Обратные функции',
steps:[
{ q:'Чему равен $\\arcsin 0$?', verify:(v)=>+v===0, hint:'$\\sin 0 = 0$.' },
{ q:'$\\arcsin\\dfrac{1}{2} = ?$ (введи как pi/n)', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/6'||s==='π/6';}, hint:'$\\sin(\\pi/6) = 1/2$.' },
{ q:'$\\arccos(-1) = ?$ (введи как pi или 0)', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi'||s==='π';}, hint:'$\\cos\\pi = -1$.' },
{ q:'$\\arcsin\\dfrac{\\sqrt{3}}{2} + \\arccos\\dfrac{\\sqrt{3}}{2} = ?$ (введи pi/n)', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/2'||s==='π/2';}, hint:'Сумма всегда $= \\pi/2$.' },
{ q:'$\\arcsin\\left(\\sin\\dfrac{5\\pi}{6}\\right) = ?$ (внимание, $5\\pi/6$ вне $[-\\pi/2;\\,\\pi/2]$! Введи pi/n.)', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/6'||s==='π/6';}, hint:'$\\sin(5\\pi/6) = \\sin(\\pi - \\pi/6) = \\sin(\\pi/6) = 1/2$. arcsin(1/2) = $\\pi/6$.' },
]
});
html += secNav('p6', 'p8') + readButton('p7');
box.innerHTML = html; renderMath(box);
/* IV1: главные значения */
makeTrainer({
idPrefix:'p7-iv1',
parser:(v)=>v,
questions:[
{ q:'$\\arcsin 1 = ?$ (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/2'||s==='π/2';}, show:'$\\pi/2$' },
{ q:'$\\arcsin(-1) = ?$ (введи -pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='-pi/2'||s==='-π/2';}, show:'$-\\pi/2$' },
{ q:'$\\arccos 1 = ?$', a:(v)=>+v===0, show:'$0$' },
{ q:'$\\arccos 0 = ?$ (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/2'||s==='π/2';}, show:'$\\pi/2$' },
{ q:'$\\arctg 1 = ?$ (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/4'||s==='π/4';}, show:'$\\pi/4$' },
{ q:'$\\arctg(-1) = ?$ (введи -pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='-pi/4'||s==='-π/4';}, show:'$-\\pi/4$' },
{ q:'$\\arccos\\dfrac{1}{2} = ?$ (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/3'||s==='π/3';}, show:'$\\pi/3$' },
{ q:'$\\arccos\\left(-\\dfrac{1}{2}\\right) = ?$ (введи 2pi/3)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='2pi/3'||s==='2π/3';}, show:'$2\\pi/3$ ($\\pi - \\pi/3$)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(20,'p7-iv1');bumpProgress('p7',32);} else if(s>=5){addXp(10,'p7-iv1');bumpProgress('p7',15);} }
});
/* IV2: arcsin(sin α) */
makeTrainer({
idPrefix:'p7-iv2',
parser:(v)=>v,
questions:[
{ q:'$\\sin(\\arcsin 0{,}5) = ?$', a:(v)=>+v===0.5, show:'$0{,}5$' },
{ q:'$\\arcsin\\left(\\sin\\dfrac{\\pi}{4}\\right) = ?$ (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/4'||s==='π/4';}, show:'$\\pi/4$ — внутри $[-\\pi/2;\\pi/2]$' },
{ q:'$\\arcsin\\left(\\sin\\dfrac{3\\pi}{4}\\right) = ?$ (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/4'||s==='π/4';}, show:'$\\pi/4$ ($\\sin(3\\pi/4) = \\sin(\\pi/4)$)' },
{ q:'$\\cos(\\arccos(-0{,}3)) = ?$', a:(v)=>+v===-0.3, show:'$-0{,}3$' },
{ q:'$\\arccos\\left(\\cos\\dfrac{5\\pi}{4}\\right) = ?$ (введи как 3pi/4)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='3pi/4'||s==='3π/4';}, show:'$3\\pi/4$ ($\\cos(5\\pi/4) = -\\frac{\\sqrt{2}}{2}$, $\\arccos = 3\\pi/4$)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p7-iv2');bumpProgress('p7',28);} else if(s>=3){addXp(9,'p7-iv2');bumpProgress('p7',14);} }
});
wireReadBtn('p7');
}
/* ============================================================
§ 8 — Тригонометрические уравнения
============================================================ */
function buildP8(){
const box = document.getElementById('p8-body');
const A = window.ALG10;
let html = '';
/* === SVG 1: геометрия решения sin x = a === */
let svgSin = '';
if(A){
const c = A.tri.canvas({id:'p8-sin', W:320, H:320, R:120});
const a = 0.5; /* sin x = 0.5 */
const x1 = Math.asin(a); /* π/6 */
const x2 = Math.PI - x1; /* 5π/6 */
const yL = c.cy - a * c.R;
let s = c.open
+ c.axes()
+ c.circle({width:2})
/* Горизонтальная линия y = a */
+ '<line x1="'+(c.cx-c.R-10)+'" y1="'+yL+'" x2="'+(c.cx+c.R+10)+'" y2="'+yL+'" stroke="#dc2626" stroke-width="2" stroke-dasharray="6 3"/>'
+ '<text x="'+(c.cx+c.R+14)+'" y="'+(yL+4)+'" font-size="12" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">y = a</text>'
/* Две точки пересечения */
+ c.radius(x1, {color:'#0d9488'})
+ c.point(x1, {color:'#0d9488', label:'P_{x_1}', labelOffset:18, fontSize:11})
+ c.radius(x2, {color:'#7c3aed'})
+ c.point(x2, {color:'#7c3aed', label:'P_{x_2}', labelOffset:18, fontSize:11})
+ '<text x="160" y="304" text-anchor="middle" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#1e293b">x_1 = arcsin a, x_2 = π arcsin a</text>'
+ c.close;
svgSin = s;
}
/* === SVG 2: геометрия cos x = a === */
let svgCos = '';
if(A){
const c = A.tri.canvas({id:'p8-cos', W:320, H:320, R:120});
const a = 0.5; /* cos x = 0.5 */
const x1 = Math.acos(a);
const x2 = -x1;
const xL = c.cx + a * c.R;
let s = c.open
+ c.axes()
+ c.circle({width:2})
/* Вертикальная линия x = a */
+ '<line x1="'+xL+'" y1="'+(c.cy-c.R-10)+'" x2="'+xL+'" y2="'+(c.cy+c.R+10)+'" stroke="#dc2626" stroke-width="2" stroke-dasharray="6 3"/>'
+ '<text x="'+(xL+5)+'" y="'+(c.cy-c.R-4)+'" font-size="12" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">x = a</text>'
+ c.radius(x1, {color:'#0d9488'})
+ c.point(x1, {color:'#0d9488', label:'P_{x_1}', labelOffset:18, fontSize:11})
+ c.radius(x2, {color:'#7c3aed'})
+ c.point(x2, {color:'#7c3aed', label:'P_{x_2}', labelOffset:18, fontSize:11})
+ '<text x="160" y="304" text-anchor="middle" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#1e293b">x_{1,2} = ±arccos a</text>'
+ c.close;
svgCos = s;
}
/* === SVG 3: геометрия tg x = a === */
let svgTg = '';
if(A){
const c = A.tri.canvas({id:'p8-tg', W:340, H:320, R:120});
const a = 0.6; /* tg x = 0.6 */
const x1 = Math.atan(a); /* arctg a */
const x2 = x1 + Math.PI; /* arctg a + π */
const xAx = c.cx + c.R;
const yA = c.cy - a * c.R;
let s = c.open
+ c.axes({xExt:c.R+40})
+ c.circle({width:2})
+ c.tgAxis()
/* Метка точки A_a на оси тангенсов */
+ '<circle cx="'+xAx+'" cy="'+yA+'" r="4" fill="#dc2626" stroke="#fff" stroke-width="1.5"/>'
+ '<text x="'+(xAx+6)+'" y="'+(yA+4)+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">A_a = (1; a)</text>'
/* Линия от точки A через начало координат */
+ '<line x1="'+(c.cx-c.R-10)+'" y1="'+(c.cy+a*(c.R+10))+'" x2="'+(c.cx+c.R+10)+'" y2="'+(c.cy-a*(c.R+10))+'" stroke="#dc2626" stroke-width="1.5" stroke-dasharray="3 2"/>'
+ c.point(x1, {color:'#0d9488', label:'P_{x_1}', labelOffset:14, fontSize:10})
+ c.point(x2, {color:'#7c3aed', label:'P_{x_2}', labelOffset:14, fontSize:10})
+ '<text x="170" y="304" text-anchor="middle" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#1e293b">x = arctg a + πn (одна формула!)</text>'
+ c.close;
svgTg = s;
}
html += makeCard('theory', 'Зачем геометрия?', '8.1', `
<p>Уравнение $\\sin x = a$ — это «на каких углах ордината точки $P_x$ равна $a$?». Геометрия даёт нам наглядный способ найти <b>все</b> решения.</p>
<p>В простейшем случае берём горизонтальную линию $y = a$ и находим точки её пересечения с единичной окружностью. От них уже получаем все остальные корни через периодичность.</p>`);
html += makeCard('rule', 'Уравнение sin x = a', '8.2', `
<p>Горизонтальная прямая $y = a$ пересекает единичную окружность в <b>двух точках</b> (если $|a| < 1$).</p>
<div class="svg-host">${svgSin}</div>
<p>Эти точки симметричны относительно оси $y$, поэтому:</p>
<ul style="padding-left:22px;line-height:1.85">
<li>$x_1 = \\arcsin a + 2\\pi n$</li>
<li>$x_2 = \\pi - \\arcsin a + 2\\pi n$</li>
</ul>
<p>Эти две серии объединяются <b>одной формулой</b>:</p>
<p style="text-align:center;font-size:1.15rem;margin:10px 0;padding:10px;background:var(--sec-acc-soft);border-radius:8px">$x = (-1)^n \\arcsin a + \\pi n, \\quad n \\in \\mathbb{Z}$</p>
<p>При $|a| > 1$ — <b>корней нет</b>.</p>`);
html += makeCard('rule', 'Уравнение cos x = a', '8.3', `
<p>Вертикальная прямая $x = a$ пересекает окружность в двух точках, симметричных относительно оси $x$.</p>
<div class="svg-host">${svgCos}</div>
<p>Поэтому формула короче:</p>
<p style="text-align:center;font-size:1.15rem;margin:10px 0;padding:10px;background:var(--sec-acc-soft);border-radius:8px">$x = \\pm \\arccos a + 2\\pi n, \\quad n \\in \\mathbb{Z}$</p>
<p>При $|a| > 1$ — корней нет.</p>`);
html += makeCard('rule', 'Уравнение tg x = a', '8.4', `
<p>На оси тангенсов отмечаем точку $A_a = (1;\\,a)$. Прямая через $O$ и $A_a$ пересекает окружность в <b>двух точках</b>, лежащих на одной прямой (симметрично относительно $O$).</p>
<div class="svg-host">${svgTg}</div>
<p>А период tg равен $\\pi$ — поэтому формула одна:</p>
<p style="text-align:center;font-size:1.15rem;margin:10px 0;padding:10px;background:var(--sec-acc-soft);border-radius:8px">$x = \\arctg a + \\pi n, \\quad n \\in \\mathbb{Z}$</p>
<p>Для $\\ctg x = a$ аналогично: $x = \\arcctg a + \\pi n$.</p>
<p>Здесь $a$ <b>любое</b> — ограничений нет.</p>`);
html += makeCard('algo', 'Особые случаи (запомнить!)', '8.5', `
<p>Когда $a = 0, \\pm 1$ — лучше использовать частные формулы вместо общих:</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">Уравнение</th><th style="padding:6px;border:1px solid var(--border);text-align:left">Решение</th></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\sin x = 0$</td><td style="padding:6px;border:1px solid var(--border)">$x = \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\sin x = 1$</td><td style="padding:6px;border:1px solid var(--border)">$x = \\dfrac{\\pi}{2} + 2\\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\sin x = -1$</td><td style="padding:6px;border:1px solid var(--border)">$x = -\\dfrac{\\pi}{2} + 2\\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\cos x = 0$</td><td style="padding:6px;border:1px solid var(--border)">$x = \\dfrac{\\pi}{2} + \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\cos x = 1$</td><td style="padding:6px;border:1px solid var(--border)">$x = 2\\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\cos x = -1$</td><td style="padding:6px;border:1px solid var(--border)">$x = \\pi + 2\\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\tg x = 0$</td><td style="padding:6px;border:1px solid var(--border)">$x = \\pi n$</td></tr>
<tr><td style="padding:6px;border:1px solid var(--border)">$\\ctg x = 0$</td><td style="padding:6px;border:1px solid var(--border)">$x = \\dfrac{\\pi}{2} + \\pi n$</td></tr>
</table>`);
html += makeCard('algo', 'Метод замены переменной', '8.6', `
<p>Если в уравнении встречается одна тригонометрическая функция — обозначь её переменной $t$ и реши получившееся алгебраическое уравнение.</p>
<p><b>Пример.</b> $2\\sin^2 x - 3\\sin x + 1 = 0$.</p>
<p>Пусть $t = \\sin x$, тогда $2t^2 - 3t + 1 = 0$. Корни: $t_1 = 1, t_2 = 0{,}5$.</p>
<p>Возвращаемся: $\\sin x = 1$ или $\\sin x = 0{,}5$.</p>
<ul style="padding-left:22px;line-height:1.85">
<li>$\\sin x = 1$ ⇒ $x = \\dfrac{\\pi}{2} + 2\\pi n$.</li>
<li>$\\sin x = 0{,}5$ ⇒ $x = (-1)^k \\dfrac{\\pi}{6} + \\pi k$.</li>
</ul>`);
html += makeCard('algo', 'Метод разложения на множители', '8.7', `
<p>Если уравнение приводится к виду $f_1(x) \\cdot f_2(x) = 0$ — оно распадается на два простейших.</p>
<p><b>Пример.</b> $\\sqrt{3}\\sin x = \\cos^2 x \\sin x$.</p>
<p>Переносим всё в одну сторону: $\\sin x (\\sqrt{3} - \\cos^2 x) = 0$.</p>
<p>Либо $\\sin x = 0$ (тогда $x = \\pi n$), либо $\\cos^2 x = \\sqrt{3} > 1$ — корней нет.</p>
<p>Итого: $x = \\pi n$.</p>`);
html += makeCard('algo', 'Однородные уравнения', '8.8', `
<p><b>Однородное 1-й степени</b> $a\\sin x + b\\cos x = 0$ — делим на $\\cos x$ (при условии $\\cos x \\ne 0$, что проверяем): $a\\tg x + b = 0$ ⇒ $\\tg x = -\\dfrac{b}{a}$.</p>
<p><b>Однородное 2-й степени</b> $a\\sin^2 x + b\\sin x \\cos x + c\\cos^2 x = 0$ — делим на $\\cos^2 x$: $a\\tg^2 x + b\\tg x + c = 0$. Замена $t = \\tg x$.</p>`);
/* === ИНТЕРАКТИВ 1: Простейшие === */
html += '<div class="wg" id="p8-iv1">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Простейшие тригонометрические</div></div>'
+'<div class="wg-help">Для серий с πn — введи <b>один корень</b> в $[0;\\,2\\pi)$. Если корней несколько в этом промежутке — введи наименьший положительный.</div>'
+trainerHTML('p8-iv1', 10, 'корень в [0;2π)')
+'</div>';
/* === ИНТЕРАКТИВ 2: Сколько корней в промежутке === */
html += '<div class="wg" id="p8-iv2">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Сколько корней в промежутке?</div></div>'
+'<div class="wg-help">Найди серии корней, потом отсчитай, сколько из них попало в указанный промежуток.</div>'
+trainerHTML('p8-iv2', 6, 'число')
+'</div>';
/* === ИНТЕРАКТИВ 3: Замена/разложение === */
html += '<div class="wg" id="p8-iv3">'
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Замена переменной</div></div>'
+'<div class="wg-help">Сделай замену $t = \\sin x$ или $\\cos x$ и реши квадратное.</div>'
+trainerHTML('p8-iv3', 5, 'число корней в [0;2π)')
+'</div>';
/* === БОСС §8 — 6 этапов === */
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §8 — Тригонометрические уравнения</h3>';
html += makeBoss('p8', {
color:'#dc2626',
title:'Босс §8 — Тригонометрические уравнения',
steps:[
{ q:'Уравнение $\\sin x = 2$ имеет корни? «да» или «нет»', verify:(v)=>String(v).trim().toLowerCase().startsWith('н'), hint:'$|2| > 1$, корней нет.' },
{ q:'Сколько корней у $\\sin x = 0{,}5$ на промежутке $[0;\\,2\\pi]$?', verify:(v)=>+v===2, hint:'$x_1 = \\pi/6$ и $x_2 = 5\\pi/6$ — обе в промежутке.' },
{ q:'Реши $\\cos x = -1$. Введи корень в $[0;\\,2\\pi]$ как pi (если ответ $\\pi$).', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi'||s==='π';}, hint:'$\\cos\\pi = -1$.' },
{ q:'Реши $2\\cos^2 x + 3\\cos x + 1 = 0$. Сколько корней в $[0;\\,2\\pi)$?', verify:(v)=>+v===3, hint:'$t = \\cos x$: $2t^2+3t+1=0$, $t = -1$ или $t = -1/2$. cos=1: x=π. cos=1/2: x=2π/3, 4π/3. Итого 3.' },
{ q:'Решает ли значение $x = \\dfrac{\\pi}{2}$ уравнение $\\sin x \\cos x = 0$? «да» или «нет»', verify:(v)=>String(v).trim().toLowerCase().startsWith('д'), hint:'$\\cos(\\pi/2) = 0$, произведение = 0 ✓.' },
{ q:'Реши $\\tg x = 1$. Введи наименьший положительный корень как pi/n.', verify:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/4'||s==='π/4';}, hint:'$\\arctg 1 = \\pi/4$, серия $x = \\pi/4 + \\pi n$.' },
]
});
html += secNav('p7', 'p9') + readButton('p8');
box.innerHTML = html; renderMath(box);
/* IV1: простейшие */
makeTrainer({
idPrefix:'p8-iv1',
parser:(v)=>v,
questions:[
{ q:'$\\sin x = 0$. Наименьший корень в $[0;\\,2\\pi)$?', a:(v)=>+v===0, show:'$0$' },
{ q:'$\\sin x = 1$. Корень в $[0;\\,2\\pi)$? (введи pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/2'||s==='π/2';}, show:'$\\pi/2$' },
{ q:'$\\cos x = 1$. Наименьший корень в $[0;\\,2\\pi)$?', a:(v)=>+v===0, show:'$0$' },
{ q:'$\\cos x = -1$. Корень в $[0;\\,2\\pi)$?', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi'||s==='π';}, show:'$\\pi$' },
{ q:'$\\sin x = 0{,}5$. Наименьший корень в $[0;\\,2\\pi)$? (pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/6'||s==='π/6';}, show:'$\\pi/6$' },
{ q:'$\\cos x = 0{,}5$. Наименьший корень в $[0;\\,2\\pi)$? (pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/3'||s==='π/3';}, show:'$\\pi/3$' },
{ q:'$\\sin x = -1$. Корень в $[0;\\,2\\pi)$? (введи 3pi/2)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='3pi/2'||s==='3π/2';}, show:'$3\\pi/2$' },
{ q:'$\\tg x = 0$. Наименьший корень в $[0;\\,2\\pi)$?', a:(v)=>+v===0, show:'$0$' },
{ q:'$\\tg x = \\sqrt{3}$. Наименьший корень в $[0;\\,2\\pi)$? (pi/n)', a:(v)=>{const s=String(v).replace(/\\s/g,'').toLowerCase(); return s==='pi/3'||s==='π/3';}, show:'$\\pi/3$' },
{ q:'$\\sin x = 3$. Сколько корней? (число)', a:(v)=>+v===0, show:'$0$ (нет, $|3|>1$)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(22,'p8-iv1');bumpProgress('p8',32);} else if(s>=6){addXp(11,'p8-iv1');bumpProgress('p8',16);} }
});
/* IV2: сколько корней */
makeTrainer({
idPrefix:'p8-iv2',
questions:[
{ q:'Сколько корней у $\\sin x = 0$ на $[0;\\,2\\pi]$?', a:3, show:'3 ($0, \\pi, 2\\pi$)' },
{ q:'Сколько корней у $\\sin x = 0{,}5$ на $[0;\\,2\\pi]$?', a:2, show:'2 ($\\pi/6$ и $5\\pi/6$)' },
{ q:'Сколько корней у $\\cos x = 0$ на $[0;\\,2\\pi]$?', a:2, show:'2 ($\\pi/2$ и $3\\pi/2$)' },
{ q:'Сколько корней у $\\cos x = 1$ на $[0;\\,2\\pi]$?', a:2, show:'2 ($0$ и $2\\pi$)' },
{ q:'Сколько корней у $\\tg x = 1$ на $[0;\\,\\pi]$?', a:1, show:'1 ($\\pi/4$)' },
{ q:'Сколько корней у $\\sin x = \\dfrac{\\sqrt{2}}{2}$ на $[0;\\,4\\pi]$?', a:4, show:'4 (на каждом периоде по 2)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p8-iv2');bumpProgress('p8',26);} else if(s>=4){addXp(9,'p8-iv2');bumpProgress('p8',12);} }
});
/* IV3: замена */
makeTrainer({
idPrefix:'p8-iv3',
questions:[
{ q:'$2\\sin^2 x - \\sin x = 0$. Сколько корней в $[0;\\,2\\pi)$?', a:4, show:'4 ($\\sin x(2\\sin x - 1) = 0$: sin x = 0 ⇒ 0, π; sin x = 1/2 ⇒ π/6, 5π/6)' },
{ q:'$\\cos^2 x = 1$. Сколько корней в $[0;\\,2\\pi)$?', a:2, show:'2 (cos x = ±1 ⇒ x = 0, π)' },
{ q:'$2\\sin^2 x - 3\\sin x + 1 = 0$. Сколько корней в $[0;\\,2\\pi)$?', a:3, show:'3 (sin = 1: π/2; sin = 1/2: π/6, 5π/6)' },
{ q:'$\\sin^2 x + \\sin x = 0$. Сколько корней в $[0;\\,2\\pi)$?', a:3, show:'3 (sin x = 0: 0, π; sin x = -1: 3π/2)' },
{ q:'$\\tg^2 x - 1 = 0$. Сколько корней в $[0;\\,2\\pi)$?', a:4, show:'4 (tg = ±1, серии π/4 + πn/2)' },
],
onComplete:(s,n)=>{ if(s===n){addXp(18,'p8-iv3');bumpProgress('p8',26);} else if(s>=2){addXp(9,'p8-iv3');bumpProgress('p8',12);} }
});
wireReadBtn('p8');
}
</script>
</body>
</html>