0e52fedc2d
§3 Построения сечений:
- Hero: куб с шестиугольным сечением через M, N, P (4-шаговая анимация: точки → 2 ребра → 6 точек → заливка)
- 3 типа сечений куба: треугольник / прямоугольник / правильный шестиугольник
- Метод следов: куб с M, N, K и следом плоскости сечения на основании
- 4 теоретические карточки (определение, метод следов, параллельные сечения, max сторон)
- 3 тренажёра: тип многоугольника (6), max сторон (5), метод следов (5)
- Босс §3: 5 этапов, +70 XP
Финал раздела 1 (4 босса):
- Босс 1 Элементы тел (4 этапа, +35 XP)
- Босс 2 Аксиомы (4 этапа, +35 XP)
- Босс 3 Сечения (4 этапа, +35 XP)
- Босс 4 Сборная (5 этапов, +45 XP)
- Celebration: ачивка stereo10_r1_master + 100 XP бонус
- Прогресс хранится в STATE.bosses{f1..f4} + geometry10_achievements в localStorage
1580 lines
93 KiB
HTML
1580 lines
93 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>Геометрия 10 · Раздел 1 · Введение в стереометрию</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=Inter:wght@400;500;600;700&family=Unbounded:wght@400;700;800;900&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
|
||
<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"></script>
|
||
<script src="/js/api.js" defer></script>
|
||
<script src="/js/xp.js" defer></script>
|
||
<script src="/js/stereo3d.js?v=1"></script>
|
||
<style>
|
||
:root{
|
||
--bg:#f8fafc; --card:#fff; --card-2:#f1f5f9;
|
||
--text:#0b1d33; --text-2:#1e293b; --muted:#475569;
|
||
--border:#dbeafe; --border-2:#e2e8f0;
|
||
--pri:#2563eb; --pri-d:#1d4ed8; --pri-l:#93c5fd;
|
||
--pri-soft:#dbeafe; --pri-soft-2:#eff6ff;
|
||
--dark:#1e3a8a;
|
||
--accent:#dc2626;
|
||
--good:#16a34a;
|
||
--warn:#d97706;
|
||
--sh:0 4px 16px rgba(37,99,235,.08);
|
||
--sh-h:0 12px 36px rgba(37,99,235,.18);
|
||
}
|
||
html.dark{
|
||
--bg:#020617; --card:#0a1929; --card-2:#0f1f33;
|
||
--text:#dbeafe; --text-2:#bfdbfe; --muted:#94a3b8;
|
||
--border:#1e3a5f; --border-2:#1e293b;
|
||
--pri-soft:rgba(37,99,235,.18); --pri-soft-2:rgba(37,99,235,.10);
|
||
}
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
html,body{min-height:100vh}
|
||
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;transition:background .25s,color .25s}
|
||
|
||
.hdr{position:relative;background:linear-gradient(110deg,var(--dark) 0%,var(--pri) 55%,var(--pri-l) 100%);color:#fff;padding:32px 24px 28px;overflow:hidden}
|
||
.hdr::before{content:'△';position:absolute;right:8px;top:-18%;font-family:'Outfit',sans-serif;font-size:clamp(8rem,22vw,18rem);font-weight:900;color:rgba(255,255,255,.10);line-height:1;pointer-events:none;user-select:none}
|
||
.hdr-inner{position:relative;z-index:1;max-width:1100px;margin:0 auto;display:flex;align-items:center;gap:18px;flex-wrap:wrap}
|
||
.hdr-back{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;background:rgba(255,255,255,.14);border-radius:9px;color:#fff;text-decoration:none;font-size:.85rem;font-weight:600;transition:background .15s}
|
||
.hdr-back:hover{background:rgba(255,255,255,.24)}
|
||
.hdr h1{font-family:'Outfit',sans-serif;font-size:1.7rem;font-weight:900;letter-spacing:-.01em}
|
||
.hdr-sub{font-size:.92rem;opacity:.88;margin-top:4px}
|
||
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center}
|
||
.hdr-btn{padding:8px 12px;background:rgba(255,255,255,.14);border:none;color:#fff;border-radius:9px;cursor:pointer;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;font-family:inherit}
|
||
.hdr-btn:hover{background:rgba(255,255,255,.24)}
|
||
.hdr-xp{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:linear-gradient(135deg,#f59e0b,#dc2626);border-radius:99px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;color:#fff;box-shadow:0 4px 12px rgba(220,38,38,.32)}
|
||
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
|
||
|
||
.sec-nav{position:sticky;top:0;z-index:30;background:var(--bg);border-bottom:1px solid var(--border-2);padding:10px 16px;overflow-x:auto;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,.04)}
|
||
.sec-nav-inner{display:inline-flex;gap:6px;max-width:1100px;margin:0 auto}
|
||
.sec-tab{display:inline-flex;align-items:center;gap:6px;padding:7px 14px;background:var(--card-2);border:1px solid var(--border-2);border-radius:10px;font-size:.82rem;font-weight:700;color:var(--muted);cursor:pointer;transition:all .15s;text-decoration:none;font-family:inherit}
|
||
.sec-tab:hover{background:var(--pri-soft);color:var(--pri-d);border-color:var(--pri-l)}
|
||
.sec-tab.active{background:var(--pri);color:#fff;border-color:var(--pri-d)}
|
||
.sec-tab .dot{width:8px;height:8px;border-radius:50%;background:rgba(0,0,0,.15);transition:background .25s}
|
||
.sec-tab.read .dot{background:var(--good)}
|
||
.sec-tab.active .dot{background:#fff}
|
||
.sec-tab.locked{opacity:.55}
|
||
|
||
main{max-width:1100px;margin:0 auto;padding:32px 24px 80px}
|
||
|
||
.para{margin-bottom:48px;scroll-margin-top:72px}
|
||
.para-head{display:flex;align-items:flex-start;gap:16px;margin-bottom:18px}
|
||
.para-num{font-family:'Outfit',sans-serif;font-size:1.6rem;font-weight:900;color:#fff;background:linear-gradient(135deg,var(--pri),var(--pri-d));padding:10px 16px;border-radius:11px;letter-spacing:-.02em;flex-shrink:0;box-shadow:var(--sh)}
|
||
.para-h{flex:1;min-width:0}
|
||
.para-h h2{font-family:'Outfit',sans-serif;font-size:1.6rem;font-weight:800;letter-spacing:-.01em;line-height:1.2;margin-bottom:4px}
|
||
.para-h-sub{color:var(--muted);font-size:.95rem}
|
||
|
||
.theory{display:grid;grid-template-columns:1fr;gap:14px;margin-bottom:24px}
|
||
@media(min-width:760px){.theory{grid-template-columns:repeat(2,1fr)}}
|
||
.t-card{background:var(--card);border:1.5px solid var(--border-2);border-radius:13px;padding:16px 18px;box-shadow:var(--sh);transition:border-color .15s}
|
||
.t-card:hover{border-color:var(--pri-l)}
|
||
.t-tag{display:inline-block;padding:3px 9px;background:var(--pri-soft);color:var(--pri-d);border-radius:6px;font-size:.7rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;margin-bottom:8px}
|
||
.t-title{font-family:'Outfit',sans-serif;font-size:1.02rem;font-weight:800;margin-bottom:6px;color:var(--text)}
|
||
.t-body{font-size:.92rem;color:var(--text);opacity:.9;line-height:1.6}
|
||
.t-body p{margin-bottom:8px}
|
||
.t-body ul{margin:6px 0 6px 20px}
|
||
.t-body li{margin-bottom:4px}
|
||
.t-body code{background:var(--card-2);padding:2px 6px;border-radius:5px;font-family:'JetBrains Mono',monospace;font-size:.86em}
|
||
|
||
.viz{background:var(--card);border:1.5px solid var(--border-2);border-radius:14px;padding:18px;margin-bottom:18px;box-shadow:var(--sh)}
|
||
.viz-title{font-family:'Outfit',sans-serif;font-size:.94rem;font-weight:800;color:var(--text);margin-bottom:10px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
||
.viz-title .badge{padding:2px 8px;background:var(--pri-soft);color:var(--pri-d);border-radius:5px;font-size:.7rem;letter-spacing:.04em}
|
||
.viz-cap{font-size:.84rem;color:var(--muted);margin-top:8px;line-height:1.55}
|
||
.viz-row{display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
|
||
.viz-cell{flex:1 1 200px;max-width:230px;text-align:center}
|
||
.viz-cell-label{font-size:.78rem;color:var(--muted);font-weight:700;margin-top:6px}
|
||
|
||
.rot-row{display:flex;gap:14px;flex-wrap:wrap;justify-content:center;margin-top:10px;font-size:.84rem;color:var(--muted)}
|
||
.rot-row label{display:inline-flex;align-items:center;gap:6px;font-weight:600}
|
||
|
||
.inter{background:var(--card);border:1.5px solid var(--border-2);border-radius:14px;padding:18px;margin-bottom:18px;box-shadow:var(--sh)}
|
||
.inter-h{display:flex;align-items:center;gap:10px;margin-bottom:12px}
|
||
.inter-icon{width:34px;height:34px;border-radius:9px;background:var(--pri-soft);color:var(--pri-d);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-family:'Outfit',sans-serif;font-weight:900;font-size:.96rem}
|
||
.inter-title{font-family:'Outfit',sans-serif;font-size:1rem;font-weight:800;flex:1}
|
||
.inter-progress{font-size:.78rem;color:var(--muted);font-weight:700;font-family:'JetBrains Mono',monospace}
|
||
|
||
.quiz{display:flex;gap:14px;align-items:center;flex-wrap:wrap}
|
||
.quiz-q{flex:1;min-width:200px;font-size:.95rem;font-weight:600;line-height:1.55}
|
||
.quiz-opts{display:flex;gap:8px;flex-wrap:wrap}
|
||
.quiz-opt{padding:8px 14px;background:var(--card-2);border:1.5px solid var(--border-2);border-radius:9px;font-weight:700;font-size:.88rem;cursor:pointer;color:var(--text);font-family:inherit;transition:all .15s}
|
||
.quiz-opt:hover{background:var(--pri-soft);border-color:var(--pri-l)}
|
||
.quiz-opt.correct{background:linear-gradient(135deg,#dcfce7,#bbf7d0);border-color:#16a34a;color:#166534;animation:pop .35s}
|
||
.quiz-opt.wrong{background:linear-gradient(135deg,#fee2e2,#fecaca);border-color:#dc2626;color:#991b1b;animation:shake .35s}
|
||
@keyframes pop{0%{transform:scale(1)}50%{transform:scale(1.07)}100%{transform:scale(1)}}
|
||
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}
|
||
|
||
.quiz-input{display:inline-flex;align-items:center;gap:8px;background:var(--card-2);border:1.5px solid var(--border-2);border-radius:9px;padding:4px 6px;transition:border-color .15s}
|
||
.quiz-input.correct{border-color:#16a34a;background:linear-gradient(135deg,#dcfce7,#bbf7d0)}
|
||
.quiz-input.wrong{border-color:#dc2626;background:linear-gradient(135deg,#fee2e2,#fecaca)}
|
||
.quiz-input input{background:transparent;border:none;outline:none;padding:6px 8px;font-family:'JetBrains Mono',monospace;font-size:.92rem;font-weight:700;color:var(--text);width:90px}
|
||
.quiz-input button{background:var(--pri);border:none;color:#fff;padding:6px 10px;border-radius:6px;cursor:pointer;font-weight:700;font-size:.82rem;font-family:inherit}
|
||
.quiz-input button:hover{filter:brightness(1.08)}
|
||
|
||
.quiz-feedback{margin-top:10px;padding:10px 14px;background:var(--card-2);border-radius:9px;font-size:.88rem;color:var(--muted);display:none}
|
||
.quiz-feedback.show{display:block}
|
||
.quiz-feedback.good{background:linear-gradient(135deg,#dcfce7,#f0fdf4);color:#166534;border-left:3px solid #16a34a}
|
||
.quiz-feedback.bad{background:linear-gradient(135deg,#fee2e2,#fef2f2);color:#991b1b;border-left:3px solid #dc2626}
|
||
|
||
.boss{background:linear-gradient(135deg,#1e1b4b 0%,#312e81 50%,#4338ca 100%);color:#fff;border-radius:18px;padding:24px;margin-bottom:24px;position:relative;overflow:hidden;box-shadow:0 16px 48px rgba(67,56,202,.30)}
|
||
.boss::before{content:'';position:absolute;inset:0;background:radial-gradient(circle at 20% 30%,rgba(255,255,255,.10),transparent 50%);pointer-events:none}
|
||
.boss-h{display:flex;align-items:center;gap:12px;margin-bottom:14px;position:relative;z-index:1;flex-wrap:wrap}
|
||
.boss-badge{padding:5px 12px;background:rgba(245,158,11,.32);border:1px solid rgba(251,191,36,.5);border-radius:99px;font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;letter-spacing:.06em;color:#fde68a;text-transform:uppercase}
|
||
.boss-title{font-family:'Outfit',sans-serif;font-size:1.2rem;font-weight:800;flex:1}
|
||
.boss-hp{margin-bottom:14px;position:relative;z-index:1}
|
||
.boss-hp-label{display:flex;justify-content:space-between;font-size:.78rem;font-weight:700;margin-bottom:5px;color:#e0e7ff}
|
||
.boss-hp-bar{height:12px;background:rgba(255,255,255,.10);border-radius:7px;overflow:hidden;border:1px solid rgba(255,255,255,.18)}
|
||
.boss-hp-fill{height:100%;background:linear-gradient(90deg,#f59e0b,#ef4444);transition:width .5s ease-out}
|
||
.boss-question{background:rgba(0,0,0,.32);border-radius:12px;padding:16px;margin-bottom:14px;position:relative;z-index:1;border:1px solid rgba(255,255,255,.10)}
|
||
.boss-stage-label{font-size:.74rem;color:#a5b4fc;font-weight:700;letter-spacing:.08em;text-transform:uppercase;margin-bottom:6px}
|
||
.boss-q{font-size:1.02rem;font-weight:700;margin-bottom:14px;line-height:1.55}
|
||
.boss-opts{display:flex;gap:8px;flex-wrap:wrap}
|
||
.boss-opt{padding:10px 16px;background:rgba(255,255,255,.10);border:1.5px solid rgba(255,255,255,.20);border-radius:9px;color:#fff;font-weight:700;font-size:.92rem;cursor:pointer;font-family:inherit;transition:all .15s}
|
||
.boss-opt:hover{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.4)}
|
||
.boss-opt.correct{background:linear-gradient(135deg,#16a34a,#22c55e);border-color:#86efac;animation:pop .35s}
|
||
.boss-opt.wrong{background:linear-gradient(135deg,#dc2626,#ef4444);border-color:#fca5a5;animation:shake .35s}
|
||
.boss-input{display:inline-flex;align-items:center;gap:6px;background:rgba(0,0,0,.36);border:1.5px solid rgba(255,255,255,.20);border-radius:9px;padding:4px 6px}
|
||
.boss-input.wrong{border-color:#fca5a5;animation:shake .35s}
|
||
.boss-input input{background:transparent;border:none;outline:none;color:#fff;font-family:'JetBrains Mono',monospace;font-size:.95rem;font-weight:700;padding:6px 8px;width:100px}
|
||
.boss-input button{background:#f59e0b;border:none;color:#fff;padding:6px 12px;border-radius:6px;cursor:pointer;font-weight:800;font-size:.82rem;font-family:inherit}
|
||
.boss-defeated{text-align:center;padding:16px;position:relative;z-index:1}
|
||
.boss-defeated-title{font-family:'Outfit',sans-serif;font-size:1.3rem;font-weight:900;color:#fde68a;margin-bottom:8px;letter-spacing:-.01em}
|
||
.boss-defeated-sub{font-size:.92rem;color:#c7d2fe;margin-bottom:14px}
|
||
.boss-defeated-xp{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;background:linear-gradient(135deg,#f59e0b,#dc2626);border-radius:99px;font-family:'Unbounded',sans-serif;font-weight:800;font-size:.86rem;letter-spacing:.06em;box-shadow:0 6px 20px rgba(245,158,11,.4)}
|
||
.boss.victory{background:linear-gradient(135deg,#15803d,#22c55e 50%,#86efac)}
|
||
.boss.victory::before{background:radial-gradient(circle at 50% 50%,rgba(254,240,138,.20),transparent 70%)}
|
||
|
||
.para-actions{display:flex;justify-content:center;margin-top:18px;gap:10px}
|
||
.mark-btn{padding:11px 22px;background:var(--pri);color:#fff;border:none;border-radius:11px;font-weight:800;font-size:.92rem;cursor:pointer;font-family:'Inter',sans-serif;display:inline-flex;align-items:center;gap:8px;transition:filter .15s,transform .15s;box-shadow:var(--sh)}
|
||
.mark-btn:hover{filter:brightness(1.10);transform:translateY(-1px)}
|
||
.mark-btn.done{background:linear-gradient(135deg,var(--good),#22c55e)}
|
||
|
||
.stub-card{background:linear-gradient(135deg,var(--pri-soft),transparent);border:1px dashed var(--pri-l);border-radius:14px;padding:24px;text-align:center;color:var(--pri-d);margin-bottom:24px}
|
||
.stub-card b{font-family:'Outfit',sans-serif;font-size:1.1rem;display:block;margin-bottom:4px}
|
||
.stub-card small{display:block;margin-top:6px;color:var(--muted);font-size:.84rem}
|
||
|
||
.foot{text-align:center;padding:24px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border-2);margin-top:30px}
|
||
|
||
@media (max-width:560px){
|
||
.hdr h1{font-size:1.35rem}
|
||
.hdr-sub{font-size:.85rem}
|
||
.para-num{font-size:1.3rem;padding:8px 12px}
|
||
.para-h h2{font-size:1.3rem}
|
||
.quiz{flex-direction:column;align-items:flex-start}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header class="hdr">
|
||
<div class="hdr-inner">
|
||
<div>
|
||
<a href="/textbook/geometry-10" class="hdr-back">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
|
||
К курсу
|
||
</a>
|
||
</div>
|
||
<div>
|
||
<h1>Раздел 1. Введение в стереометрию</h1>
|
||
<div class="hdr-sub">Пространственные фигуры · Аксиомы · Сечения</div>
|
||
</div>
|
||
<div class="hdr-side">
|
||
<span class="hdr-xp" id="hdr-xp">0 XP</span>
|
||
<button id="theme-btn" class="hdr-btn" title="Сменить тему">
|
||
<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>
|
||
|
||
<nav class="sec-nav">
|
||
<div class="sec-nav-inner">
|
||
<a class="sec-tab active" data-tab="1" href="#para-1"><span class="dot"></span>§1 Фигуры</a>
|
||
<a class="sec-tab" data-tab="2" href="#para-2"><span class="dot"></span>§2 Аксиомы</a>
|
||
<a class="sec-tab" data-tab="3" href="#para-3"><span class="dot"></span>§3 Сечения</a>
|
||
<a class="sec-tab" data-tab="final" href="#para-final"><span class="dot"></span>Финал</a>
|
||
</div>
|
||
</nav>
|
||
|
||
<main>
|
||
|
||
<section id="para-1" class="para">
|
||
<div class="para-head">
|
||
<div class="para-num">§ 1</div>
|
||
<div class="para-h">
|
||
<h2>Пространственные фигуры</h2>
|
||
<div class="para-h-sub">Многогранники и тела вращения · грани, рёбра, вершины · формула Эйлера</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">5 ОСНОВНЫХ ТЕЛ</span> Знакомство со стереометрией</div>
|
||
<div class="viz-row" id="viz1-solids"></div>
|
||
<div class="viz-cap">Стереометрия изучает фигуры в трёхмерном пространстве. Слева направо: <b>призма</b>, <b>пирамида</b>, <b>цилиндр</b>, <b>конус</b>, <b>шар</b>. Первые две — <b>многогранники</b> (все грани плоские), три остальные — <b>тела вращения</b>.</div>
|
||
</div>
|
||
|
||
<div class="theory">
|
||
<div class="t-card">
|
||
<span class="t-tag">1.1</span>
|
||
<div class="t-title">Многогранник: грани, рёбра, вершины</div>
|
||
<div class="t-body">
|
||
<p><b>Многогранник</b> — тело, ограниченное конечным числом плоских многоугольников.</p>
|
||
<ul>
|
||
<li><b>Грань</b> — каждый из этих многоугольников.</li>
|
||
<li><b>Ребро</b> — общая сторона двух соседних граней.</li>
|
||
<li><b>Вершина</b> — общая точка трёх или более рёбер.</li>
|
||
<li><b>Диагональ</b> — отрезок, соединяющий две вершины, не лежащие на одной грани.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">1.2</span>
|
||
<div class="t-title">Призма</div>
|
||
<div class="t-body">
|
||
<p><b>Призма</b> — многогранник, у которого две грани (<b>основания</b>) — равные многоугольники в параллельных плоскостях, а остальные грани (<b>боковые</b>) — параллелограммы.</p>
|
||
<p><b>Виды:</b> прямая (боковые рёбра ⊥ основанию) или наклонная; правильная — прямая с основанием в виде правильного $n$-угольника.</p>
|
||
<p>Параллелепипед — частный случай призмы (основание — параллелограмм).</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">1.3</span>
|
||
<div class="t-title">Пирамида</div>
|
||
<div class="t-body">
|
||
<p><b>Пирамида</b> — многогранник с одним основанием-многоугольником и боковыми гранями-треугольниками с общей <b>вершиной пирамиды</b>.</p>
|
||
<p>Правильная пирамида: основание — правильный $n$-угольник, вершина проектируется в его центр.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">1.4</span>
|
||
<div class="t-title">Тела вращения</div>
|
||
<div class="t-body">
|
||
<p><b>Цилиндр</b> — вращение прямоугольника вокруг одной из его сторон.</p>
|
||
<p><b>Конус</b> — вращение прямоугольного треугольника вокруг катета.</p>
|
||
<p><b>Шар</b> — вращение полукруга вокруг диаметра.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">1.5</span>
|
||
<div class="t-title">Формула Эйлера</div>
|
||
<div class="t-body">
|
||
<p>Для любого <b>выпуклого многогранника</b>:</p>
|
||
<p style="text-align:center;font-size:1.05rem;margin:8px 0">$$ В - Р + Г = 2 $$</p>
|
||
<p>где В — число вершин, Р — рёбер, Г — граней. Куб: $В=8, Р=12, Г=6 \Rightarrow 8-12+6=2$. ✓</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">1.6</span>
|
||
<div class="t-title">Изображение на плоскости</div>
|
||
<div class="t-body">
|
||
<p>Пространственные фигуры изображают на плоскости в параллельной проекции (чаще — <b>кабинетной</b>).</p>
|
||
<p>Видимые рёбра — <b>сплошной</b> линией, невидимые — <b>штриховой</b>.</p>
|
||
<p>Параллельные отрезки остаются параллельными, но длины и углы искажаются.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">КУБ</span> Грани · рёбра · вершины · диагональ</div>
|
||
<div id="viz1-cube"></div>
|
||
<div class="viz-cap">Куб $ABCDA_1B_1C_1D_1$. Видимые рёбра — сплошные, невидимые — штриховые. Подсвечена <span style="color:#dc2626;font-weight:800">пространственная диагональ $AC_1$</span> и одна <span style="color:#7c3aed;font-weight:800">боковая грань $ABB_1A_1$</span>.</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">ПРИЗМЫ</span> Прямая и наклонная</div>
|
||
<div class="viz-row">
|
||
<div class="viz-cell"><div id="viz1-prism-direct"></div><div class="viz-cell-label">Прямая (правильная)</div></div>
|
||
<div class="viz-cell"><div id="viz1-prism-oblique"></div><div class="viz-cell-label">Наклонная</div></div>
|
||
</div>
|
||
<div class="viz-cap">У прямой призмы боковые рёбра перпендикулярны основанию; у наклонной — нет. Правильная — прямая с правильным $n$-угольником в основании.</div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i1-solid">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">1</div>
|
||
<div class="inter-title">Узнай тело по описанию</div>
|
||
<div class="inter-progress" id="i1-solid-prog">0 / 6</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i1-solid-q"></div>
|
||
<div class="quiz-opts" id="i1-solid-opts"></div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i1-solid-fb"></div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i1-count">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">2</div>
|
||
<div class="inter-title">Сосчитай элементы</div>
|
||
<div class="inter-progress" id="i1-count-prog">0 / 6</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i1-count-q"></div>
|
||
<div class="quiz-input">
|
||
<input id="i1-count-in" type="text" inputmode="numeric" placeholder="?">
|
||
<button id="i1-count-go">OK</button>
|
||
</div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i1-count-fb"></div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i1-rot">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">3</div>
|
||
<div class="inter-title">Куб с разных сторон</div>
|
||
<div class="inter-progress" id="i1-rot-prog">смотри 3D</div>
|
||
</div>
|
||
<div id="i1-rot-viz" style="text-align:center"></div>
|
||
<div class="rot-row">
|
||
<label>Поворот X <input id="i1-rot-x" type="range" min="-60" max="60" value="0" step="1"> <span id="i1-rot-xv" style="font-family:JetBrains Mono,monospace;color:var(--pri-d)">0°</span></label>
|
||
<label>Поворот Y <input id="i1-rot-y" type="range" min="-60" max="60" value="0" step="1"> <span id="i1-rot-yv" style="font-family:JetBrains Mono,monospace;color:var(--pri-d)">0°</span></label>
|
||
</div>
|
||
<div class="viz-cap">Покрути куб — видимые рёбра останутся сплошными, невидимые — пунктирными. Это «кабинетная» проекция: $y$-ось уходит вглубь под $30°$ со сжатием $\tfrac{1}{2}$.</div>
|
||
</div>
|
||
|
||
<div class="boss" id="boss-1"></div>
|
||
|
||
<div class="para-actions">
|
||
<button class="mark-btn" id="mark-1">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
|
||
<span>Отметить §1 как изученный</span>
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="para-2" class="para">
|
||
<div class="para-head">
|
||
<div class="para-num">§ 2</div>
|
||
<div class="para-h">
|
||
<h2>Прямые и плоскости в пространстве</h2>
|
||
<div class="para-h-sub">Три аксиомы стереометрии и их следствия · 4 способа задания плоскости</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">АКСИОМЫ A1–A3</span> Основа стереометрии</div>
|
||
<div class="viz-row">
|
||
<div class="viz-cell"><div id="viz2-a1"></div><div class="viz-cell-label">A1: три точки</div></div>
|
||
<div class="viz-cell"><div id="viz2-a2"></div><div class="viz-cell-label">A2: прямая в плоскости</div></div>
|
||
<div class="viz-cell"><div id="viz2-a3"></div><div class="viz-cell-label">A3: пересечение</div></div>
|
||
</div>
|
||
<div class="viz-cap">Три аксиомы стереометрии: через 3 точки — единственная плоскость; прямая лежит в плоскости, если 2 её точки в ней; две плоскости пересекаются по прямой.</div>
|
||
</div>
|
||
|
||
<div class="theory">
|
||
<div class="t-card">
|
||
<span class="t-tag">A1</span>
|
||
<div class="t-title">Через три точки</div>
|
||
<div class="t-body">
|
||
<p>Через любые три точки, <b>не лежащие на одной прямой</b>, проходит <b>единственная</b> плоскость.</p>
|
||
<p>Если же точки коллинеарны — плоскостей бесконечно много (можно «вращать» вокруг прямой).</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">A2</span>
|
||
<div class="t-title">Прямая в плоскости</div>
|
||
<div class="t-body">
|
||
<p>Если две точки прямой лежат в плоскости, то и <b>вся прямая</b> лежит в этой плоскости.</p>
|
||
<p>Обозначение: $a \subset \alpha$ — «прямая $a$ лежит в плоскости $\alpha$».</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">A3</span>
|
||
<div class="t-title">Пересечение плоскостей</div>
|
||
<div class="t-body">
|
||
<p>Если две плоскости имеют общую точку, то они имеют <b>общую прямую</b>, на которой лежат все их общие точки.</p>
|
||
<p>Эту прямую называют <b>линией пересечения</b> плоскостей: $\alpha \cap \beta = l$.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">2.4</span>
|
||
<div class="t-title">Следствия из аксиом</div>
|
||
<div class="t-body">
|
||
<ul>
|
||
<li>Через <b>прямую и точку</b> вне её — единственная плоскость.</li>
|
||
<li>Через <b>две пересекающиеся</b> прямые — единственная плоскость.</li>
|
||
<li>Через <b>две параллельные</b> прямые — единственная плоскость.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">2.5</span>
|
||
<div class="t-title">4 способа задать плоскость</div>
|
||
<div class="t-body">
|
||
<ul>
|
||
<li>3 точки, не лежащие на одной прямой;</li>
|
||
<li>прямая и точка вне её;</li>
|
||
<li>две пересекающиеся прямые;</li>
|
||
<li>две параллельные прямые.</li>
|
||
</ul>
|
||
<p>Все эти способы — переформулировки аксиомы A1.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">2.6</span>
|
||
<div class="t-title">Обозначения</div>
|
||
<div class="t-body">
|
||
<ul>
|
||
<li>$A \in \alpha$ — точка $A$ принадлежит плоскости $\alpha$;</li>
|
||
<li>$a \subset \alpha$ — прямая $a$ лежит в $\alpha$;</li>
|
||
<li>$\alpha \cap \beta = c$ — плоскости пересекаются по прямой $c$;</li>
|
||
<li>$a \parallel b$ — прямые параллельны.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">СЛЕДСТВИЯ</span> 3 способа однозначно задать плоскость</div>
|
||
<div class="viz-row">
|
||
<div class="viz-cell"><div id="viz2-c1"></div><div class="viz-cell-label">Прямая + точка</div></div>
|
||
<div class="viz-cell"><div id="viz2-c2"></div><div class="viz-cell-label">Пересекающиеся прямые</div></div>
|
||
<div class="viz-cell"><div id="viz2-c3"></div><div class="viz-cell-label">Параллельные прямые</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i2-axiom">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">1</div>
|
||
<div class="inter-title">Какая аксиома или следствие?</div>
|
||
<div class="inter-progress" id="i2-axiom-prog">0 / 6</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i2-axiom-q"></div>
|
||
<div class="quiz-opts" id="i2-axiom-opts"></div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i2-axiom-fb"></div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i2-plane">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">2</div>
|
||
<div class="inter-title">Можно ли задать плоскость?</div>
|
||
<div class="inter-progress" id="i2-plane-prog">0 / 5</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i2-plane-q"></div>
|
||
<div class="quiz-opts" id="i2-plane-opts"></div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i2-plane-fb"></div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i2-count">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">3</div>
|
||
<div class="inter-title">Сколько плоскостей?</div>
|
||
<div class="inter-progress" id="i2-count-prog">0 / 5</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i2-count-q"></div>
|
||
<div class="quiz-opts" id="i2-count-opts"></div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i2-count-fb"></div>
|
||
</div>
|
||
|
||
<div class="boss" id="boss-2"></div>
|
||
|
||
<div class="para-actions">
|
||
<button class="mark-btn" id="mark-2">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
|
||
<span>Отметить §2 как изученный</span>
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="para-3" class="para">
|
||
<div class="para-head">
|
||
<div class="para-num">§ 3</div>
|
||
<div class="para-h">
|
||
<h2>Построения сечений</h2>
|
||
<div class="para-h-sub">Метод следов · сечения куба, призмы, пирамиды</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">МЕТОД 3 ТОЧЕК</span> Сечение куба плоскостью через $M$, $N$, $P$ — правильный шестиугольник</div>
|
||
<div id="viz3-hero" style="text-align:center"></div>
|
||
<div class="rot-row" style="margin-top:14px">
|
||
<button id="viz3-step-btn" class="mark-btn" style="padding:8px 18px;font-size:.84rem">Шаг построения →</button>
|
||
<span id="viz3-step-lab" style="display:inline-flex;align-items:center;font-family:JetBrains Mono,monospace;color:var(--pri-d);font-weight:700">Шаг 1 / 4</span>
|
||
</div>
|
||
<div class="viz-cap" id="viz3-cap">На рёбрах $AB$, $BC$, $CC_1$ куба отмечены середины $M$, $N$, $P$. Нажми «Шаг построения», чтобы увидеть, как через них проводится плоскость и какая фигура получится.</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">ТИПЫ СЕЧЕНИЙ КУБА</span> От треугольника до шестиугольника</div>
|
||
<div class="viz-row">
|
||
<div class="viz-cell"><div id="viz3-tri"></div><div class="viz-cell-label">Треугольник</div></div>
|
||
<div class="viz-cell"><div id="viz3-quad"></div><div class="viz-cell-label">Прямоугольник</div></div>
|
||
<div class="viz-cell"><div id="viz3-hex"></div><div class="viz-cell-label">Шестиугольник (max)</div></div>
|
||
</div>
|
||
<div class="viz-cap">Куб «теряет» одну грань при пересечении плоскостью — поэтому сечение имеет <b>от 3 до 6 сторон</b>. Тетраэдр (4 грани) — максимум 4-угольник. Призма с $n$-угольным основанием — максимум $(n+2)$-угольник.</div>
|
||
</div>
|
||
|
||
<div class="viz">
|
||
<div class="viz-title"><span class="badge">МЕТОД СЛЕДОВ</span> Как строится сечение, выходящее за пределы видимых граней</div>
|
||
<div id="viz3-trace" style="text-align:center"></div>
|
||
<div class="viz-cap">Пусть в кубе отмечены $M$, $N$ на верхних рёбрах и $K$ на боковом ребре. Тогда: 1) находим <span style="color:#dc2626;font-weight:800">след</span> плоскости сечения на основании (продолжая $MN$ и проводя прямую через $K$ параллельно ребру); 2) от следа достраиваем сечение, пересекая остальные рёбра.</div>
|
||
</div>
|
||
|
||
<div class="theory">
|
||
<div class="t-card">
|
||
<span class="t-tag">3.1</span>
|
||
<div class="t-title">Сечение многогранника</div>
|
||
<div class="t-body">
|
||
<p><b>Сечение</b> многогранника плоскостью $\sigma$ — это многоугольник, образованный пересечением плоскости со всеми гранями многогранника.</p>
|
||
<p>Его стороны — отрезки пересечения $\sigma$ с гранями; его вершины — точки, где $\sigma$ пересекает рёбра.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">3.2</span>
|
||
<div class="t-title">Метод следов</div>
|
||
<div class="t-body">
|
||
<p><b>Следом</b> называется линия пересечения плоскости сечения с одной из граней (обычно с плоскостью основания).</p>
|
||
<p>Зная след в плоскости основания и одну точку выше, можно построить пересечения с остальными гранями, продолжая прямые и применяя аксиому A2.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">3.3</span>
|
||
<div class="t-title">Параллельные сечения</div>
|
||
<div class="t-body">
|
||
<p>Если плоскость сечения <b>параллельна основанию</b> пирамиды, сечение — многоугольник, <b>подобный основанию</b> (с коэффициентом подобия, зависящим от высоты).</p>
|
||
<p>В призме параллельное основанию сечение даёт многоугольник, <b>равный основанию</b>.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="t-card">
|
||
<span class="t-tag">3.4</span>
|
||
<div class="t-title">Максимальное число сторон</div>
|
||
<div class="t-body">
|
||
<p>Плоскость может пересечь каждую грань не более чем по одному отрезку. Поэтому число сторон сечения не превосходит число граней многогранника.</p>
|
||
<ul>
|
||
<li>Куб (6 граней) → max <b>6 сторон</b> (правильный шестиугольник через 6 средин рёбер).</li>
|
||
<li>Тетраэдр (4 грани) → max <b>4 стороны</b>.</li>
|
||
<li>$n$-угольная призма ($n{+}2$ граней) → max $n{+}2$ сторон.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i3-type">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">1</div>
|
||
<div class="inter-title">Какой многоугольник получится в сечении?</div>
|
||
<div class="inter-progress" id="i3-type-prog">0 / 6</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i3-type-q"></div>
|
||
<div class="quiz-opts" id="i3-type-opts"></div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i3-type-fb"></div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i3-max">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">2</div>
|
||
<div class="inter-title">Максимальное число сторон сечения</div>
|
||
<div class="inter-progress" id="i3-max-prog">0 / 5</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i3-max-q"></div>
|
||
<div class="quiz-input">
|
||
<input id="i3-max-in" type="text" inputmode="numeric" placeholder="?">
|
||
<button id="i3-max-go">OK</button>
|
||
</div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i3-max-fb"></div>
|
||
</div>
|
||
|
||
<div class="inter" data-inter="i3-trace">
|
||
<div class="inter-h">
|
||
<div class="inter-icon">3</div>
|
||
<div class="inter-title">Метод следов: верно или нет?</div>
|
||
<div class="inter-progress" id="i3-trace-prog">0 / 5</div>
|
||
</div>
|
||
<div class="quiz">
|
||
<div class="quiz-q" id="i3-trace-q"></div>
|
||
<div class="quiz-opts" id="i3-trace-opts"></div>
|
||
</div>
|
||
<div class="quiz-feedback" id="i3-trace-fb"></div>
|
||
</div>
|
||
|
||
<div class="boss" id="boss-3"></div>
|
||
|
||
<div class="para-actions">
|
||
<button class="mark-btn" id="mark-3">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
|
||
<span>Отметить §3 как изученный</span>
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="para-final" class="para">
|
||
<div class="para-head">
|
||
<div class="para-num">★</div>
|
||
<div class="para-h">
|
||
<h2>Финал раздела 1</h2>
|
||
<div class="para-h-sub">4 интегральных босса · ачивка «Введение в стереометрию пройдено»</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="viz" style="background:linear-gradient(135deg,#dbeafe,#eff6ff);border-color:var(--pri-l)">
|
||
<div class="viz-title" style="color:var(--pri-d)"><span class="badge">ФИНАЛЬНОЕ ИСПЫТАНИЕ</span> Победи 4 боссов подряд</div>
|
||
<div class="viz-cap" style="color:var(--text-2);margin-top:0">Каждый босс — на одну тему: <b>элементы тел</b>, <b>аксиомы</b>, <b>сечения</b>, <b>сборная задача</b>. После победы над всеми 4 — получишь ачивку и +100 XP бонусом. Состояние сохраняется автоматически.</div>
|
||
</div>
|
||
|
||
<div class="boss" id="boss-f1"></div>
|
||
<div class="boss" id="boss-f2"></div>
|
||
<div class="boss" id="boss-f3"></div>
|
||
<div class="boss" id="boss-f4"></div>
|
||
|
||
<div id="celebration" style="display:none"></div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<footer class="foot">
|
||
Геометрия — 10 класс · Раздел 1 · LearnSpace
|
||
</footer>
|
||
|
||
<script>
|
||
'use strict';
|
||
|
||
(function(){
|
||
var saved = localStorage.getItem('geometry10_theme') || localStorage.getItem('theme') || 'light';
|
||
if (saved === 'dark') document.documentElement.classList.add('dark');
|
||
var lab = document.getElementById('theme-lab');
|
||
if (lab) lab.textContent = saved === 'dark' ? 'Светлая' : 'Тёмная';
|
||
document.getElementById('theme-btn').addEventListener('click', function(){
|
||
document.documentElement.classList.toggle('dark');
|
||
var dark = document.documentElement.classList.contains('dark');
|
||
localStorage.setItem('geometry10_theme', dark ? 'dark' : 'light');
|
||
localStorage.setItem('theme', dark ? 'dark' : 'light');
|
||
if (lab) lab.textContent = dark ? 'Светлая' : 'Тёмная';
|
||
});
|
||
})();
|
||
|
||
var STATE_KEY = 'geometry10_r1_state';
|
||
var STATE = (function(){
|
||
try { var raw = localStorage.getItem(STATE_KEY); if (raw) return JSON.parse(raw); } catch(e){}
|
||
return { read:[], bosses:{}, interactives:{} };
|
||
})();
|
||
function saveState(){ try { localStorage.setItem(STATE_KEY, JSON.stringify(STATE)); } catch(e){} }
|
||
function addXp(amount, reason){
|
||
var cur = parseInt(localStorage.getItem('geometry10_xp') || '0', 10) || 0;
|
||
cur += amount;
|
||
localStorage.setItem('geometry10_xp', String(cur));
|
||
updateXpBadge();
|
||
if (window.LS && window.LS.xp && typeof window.LS.xp.toast === 'function'){
|
||
window.LS.xp.toast('+' + amount + ' XP — ' + (reason || ''));
|
||
}
|
||
}
|
||
function updateXpBadge(){
|
||
var el = document.getElementById('hdr-xp');
|
||
if (el) el.textContent = (parseInt(localStorage.getItem('geometry10_xp')||'0',10)||0) + ' XP';
|
||
}
|
||
updateXpBadge();
|
||
|
||
var syncTimer = null;
|
||
function syncProgress(){
|
||
if (syncTimer) clearTimeout(syncTimer);
|
||
syncTimer = setTimeout(function(){
|
||
if (!window.LS || typeof window.LS.api !== 'function') return;
|
||
window.LS.api('/api/textbooks/geometry-10-r1/progress', {
|
||
method:'POST',
|
||
body: JSON.stringify({ read: STATE.read })
|
||
}).catch(function(){});
|
||
}, 600);
|
||
}
|
||
|
||
function markRead(paraNum){
|
||
if (STATE.read.indexOf(paraNum) < 0){
|
||
STATE.read.push(paraNum);
|
||
saveState();
|
||
syncProgress();
|
||
}
|
||
refreshTabs();
|
||
refreshMarkBtn(paraNum);
|
||
}
|
||
function refreshMarkBtn(n){
|
||
var btn = document.getElementById('mark-' + n);
|
||
if (!btn) return;
|
||
if (STATE.read.indexOf(n) >= 0){
|
||
btn.classList.add('done');
|
||
btn.querySelector('span').textContent = '§' + n + ' изучен';
|
||
}
|
||
}
|
||
function refreshTabs(){
|
||
document.querySelectorAll('.sec-tab').forEach(function(t){
|
||
var n = t.getAttribute('data-tab');
|
||
if (n === '1' || n === '2' || n === '3'){
|
||
if (STATE.read.indexOf(parseInt(n,10)) >= 0) t.classList.add('read');
|
||
else t.classList.remove('read');
|
||
} else if (n === 'final'){
|
||
var allBeat = ['f1','f2','f3','f4'].every(function(k){
|
||
return STATE.bosses && STATE.bosses[k] && STATE.bosses[k].defeated;
|
||
});
|
||
if (allBeat) t.classList.add('read');
|
||
}
|
||
});
|
||
}
|
||
|
||
function buildHeroSolids(){
|
||
if (!window.STEREO3D) return setTimeout(buildHeroSolids, 80);
|
||
var S = window.STEREO3D;
|
||
var defs = [
|
||
{ label:'Призма (6-уг)', fn:function(sc){sc.addPrism({n:6,baseRadius:1.1,height:1.8,color:'#dbeafe'});} },
|
||
{ label:'Пирамида (4-уг)', fn:function(sc){sc.addPyramid({n:4,baseRadius:1.2,height:1.9,color:'#fee2e2'});} },
|
||
{ label:'Цилиндр', fn:function(sc){sc.addCylinder({segments:28,baseRadius:1.0,height:1.9,color:'#d1fae5'});} },
|
||
{ label:'Конус', fn:function(sc){sc.addCone({segments:28,baseRadius:1.1,height:2.0,color:'#fef3c7'});} },
|
||
{ label:'Шар', fn:function(sc){sc.addSphere({center:[0,0,0],radius:1.2,color:'#ede9fe'});} }
|
||
];
|
||
var row = document.getElementById('viz1-solids');
|
||
if (!row) return;
|
||
row.innerHTML = '';
|
||
for (var i = 0; i < defs.length; i++){
|
||
var sc = new S.Scene(180, 170, {view:'CABINET', scale:34, bg:'transparent', border:'none'});
|
||
defs[i].fn(sc);
|
||
var cell = document.createElement('div');
|
||
cell.className = 'viz-cell';
|
||
cell.innerHTML = sc.render() + '<div class="viz-cell-label">' + defs[i].label + '</div>';
|
||
row.appendChild(cell);
|
||
}
|
||
}
|
||
|
||
function buildAnnotatedCube(){
|
||
if (!window.STEREO3D) return setTimeout(buildAnnotatedCube, 80);
|
||
var S = window.STEREO3D;
|
||
var sc = new S.Scene(420, 320, {view:'CABINET', scale:55});
|
||
sc.addCube({center:[0,0,0], size:2.0, labels:true});
|
||
sc.addEdge([-1,-1,-1],[+1,+1,+1], {stroke:'#dc2626', width:3, dash:'5 3'});
|
||
sc.addFace([[-1,-1,-1],[1,-1,-1],[1,-1,1],[-1,-1,1]], {fill:'#a78bfa', opacity:0.30, stroke:'none'});
|
||
document.getElementById('viz1-cube').innerHTML = sc.render();
|
||
}
|
||
|
||
function buildPrismDirect(){
|
||
if (!window.STEREO3D) return setTimeout(buildPrismDirect, 80);
|
||
var S = window.STEREO3D;
|
||
var sc = new S.Scene(220, 220, {view:'CABINET', scale:36});
|
||
sc.addPrism({n:6, baseRadius:1.2, height:2.0, color:'#dbeafe'});
|
||
document.getElementById('viz1-prism-direct').innerHTML = sc.render();
|
||
}
|
||
function buildPrismOblique(){
|
||
if (!window.STEREO3D) return setTimeout(buildPrismOblique, 80);
|
||
var S = window.STEREO3D;
|
||
var sc = new S.Scene(220, 220, {view:'CABINET', scale:36});
|
||
var n = 6, r = 1.2, h = 2.0, shift = 0.7;
|
||
var bottom = [], top = [];
|
||
for (var i = 0; i < n; i++){
|
||
var a = 2 * Math.PI * i / n - Math.PI/2;
|
||
bottom.push([r*Math.cos(a), r*Math.sin(a), -h/2]);
|
||
top.push([r*Math.cos(a) + shift, r*Math.sin(a), +h/2]);
|
||
}
|
||
var verts = bottom.concat(top);
|
||
var faces = [];
|
||
var bi = []; for (var k = 0; k < n; k++) bi.push(k);
|
||
var ti = []; for (var k2 = 0; k2 < n; k2++) ti.push(k2 + n);
|
||
faces.push(bi); faces.push(ti.slice().reverse());
|
||
for (var j = 0; j < n; j++){
|
||
var jj = (j+1) % n;
|
||
faces.push([j, jj, jj+n, j+n]);
|
||
}
|
||
var edges = [];
|
||
for (var e = 0; e < n; e++){
|
||
var ee = (e+1) % n;
|
||
edges.push([e, ee]);
|
||
edges.push([e+n, ee+n]);
|
||
edges.push([e, e+n]);
|
||
}
|
||
sc._addPolyhedron(verts, faces, edges, [], {color:'#fef3c7', opacity:0.4});
|
||
document.getElementById('viz1-prism-oblique').innerHTML = sc.render();
|
||
}
|
||
|
||
function buildRotCube(){
|
||
if (!window.STEREO3D) return setTimeout(buildRotCube, 80);
|
||
var S = window.STEREO3D;
|
||
var holder = document.getElementById('i1-rot-viz');
|
||
var rx = document.getElementById('i1-rot-x');
|
||
var ry = document.getElementById('i1-rot-y');
|
||
var rxv = document.getElementById('i1-rot-xv');
|
||
var ryv = document.getElementById('i1-rot-yv');
|
||
function draw(){
|
||
var ax = parseFloat(rx.value) * Math.PI / 180;
|
||
var ay = parseFloat(ry.value) * Math.PI / 180;
|
||
rxv.textContent = rx.value + '°';
|
||
ryv.textContent = ry.value + '°';
|
||
var sc = new S.Scene(360, 280, {view:'CABINET', scale:56, rotX:ax, rotY:ay});
|
||
sc.addCube({center:[0,0,0], size:2.0, labels:true, color:'#dbeafe'});
|
||
holder.innerHTML = sc.render();
|
||
}
|
||
rx.addEventListener('input', draw);
|
||
ry.addEventListener('input', draw);
|
||
draw();
|
||
}
|
||
|
||
function buildAxiomVizes(){
|
||
if (!window.STEREO3D) return setTimeout(buildAxiomVizes, 80);
|
||
var S = window.STEREO3D;
|
||
(function(){
|
||
var sc = new S.Scene(220, 200, {view:'CABINET', scale:42});
|
||
sc.addPlane([0,0,0], [0,0,1], {size:2.0, label:'α'});
|
||
sc.addVertex([-1.0, -0.6, 0], 'A', {dx:-14, dy:-8, color:'#dc2626'});
|
||
sc.addVertex([+1.0, -0.4, 0], 'B', {dx:8, dy:-8, color:'#dc2626'});
|
||
sc.addVertex([+0.2, +1.0, 0], 'C', {dx:8, dy:-8, color:'#dc2626'});
|
||
document.getElementById('viz2-a1').innerHTML = sc.render();
|
||
})();
|
||
(function(){
|
||
var sc = new S.Scene(220, 200, {view:'CABINET', scale:42});
|
||
sc.addPlane([0,0,0], [0,0,1], {size:2.0, label:'α'});
|
||
sc.addEdge([-1.5, -0.8, 0], [+1.5, +0.8, 0], {stroke:'#dc2626', width:2.6});
|
||
sc.addLabel('a', [+1.5, +0.8, 0], {dx:14, dy:-4, color:'#dc2626', fontSize:15, anchor:'start'});
|
||
sc.addVertex([-1.0, -0.5, 0], 'M', {dx:-16, dy:-8, color:'#1e3a8a'});
|
||
sc.addVertex([+1.0, +0.5, 0], 'N', {dx:8, dy:-8, color:'#1e3a8a'});
|
||
document.getElementById('viz2-a2').innerHTML = sc.render();
|
||
})();
|
||
(function(){
|
||
var sc = new S.Scene(220, 200, {view:'CABINET', scale:42});
|
||
sc.addPlane([0,0,0], [0,0,1], {size:1.6, label:'α', opacity:0.20});
|
||
sc.addPlane([0,0,0], [Math.cos(Math.PI/4),0,Math.sin(Math.PI/4)], {size:1.6, label:'β', opacity:0.22, fill:'#fde047'});
|
||
sc.addEdge([-1.4, 0, 0], [+1.4, 0, 0], {stroke:'#dc2626', width:2.8});
|
||
sc.addLabel('l', [+1.4, 0, 0], {dx:14, dy:-4, color:'#dc2626', fontSize:15, anchor:'start'});
|
||
document.getElementById('viz2-a3').innerHTML = sc.render();
|
||
})();
|
||
(function(){
|
||
var sc = new S.Scene(220, 200, {view:'CABINET', scale:42});
|
||
sc.addPlane([0,0,0], [0,0,1], {size:2.0, label:'α'});
|
||
sc.addEdge([-1.5, -0.4, 0], [+1.5, +0.4, 0], {stroke:'#1e3a8a', width:2.4});
|
||
sc.addLabel('a', [+1.5, +0.4, 0], {dx:14, dy:-4, color:'#1e3a8a', fontSize:14, anchor:'start'});
|
||
sc.addVertex([+0.4, -0.9, 0], 'M', {dx:8, dy:-8, color:'#dc2626'});
|
||
document.getElementById('viz2-c1').innerHTML = sc.render();
|
||
})();
|
||
(function(){
|
||
var sc = new S.Scene(220, 200, {view:'CABINET', scale:42});
|
||
sc.addPlane([0,0,0], [0,0,1], {size:2.0, label:'α'});
|
||
sc.addEdge([-1.5, -0.8, 0], [+1.5, +0.8, 0], {stroke:'#1e3a8a', width:2.4});
|
||
sc.addEdge([-1.0, +0.9, 0], [+1.1, -1.0, 0], {stroke:'#dc2626', width:2.4});
|
||
sc.addVertex([+0.05, 0.04, 0], 'O', {dx:8, dy:-10, color:'#0b1d33'});
|
||
sc.addLabel('a', [+1.5, +0.8, 0], {dx:12, dy:-4, color:'#1e3a8a', fontSize:14, anchor:'start'});
|
||
sc.addLabel('b', [+1.1, -1.0, 0], {dx:12, dy:-4, color:'#dc2626', fontSize:14, anchor:'start'});
|
||
document.getElementById('viz2-c2').innerHTML = sc.render();
|
||
})();
|
||
(function(){
|
||
var sc = new S.Scene(220, 200, {view:'CABINET', scale:42});
|
||
sc.addPlane([0,0,0], [0,0,1], {size:2.0, label:'α'});
|
||
sc.addEdge([-1.5, -0.6, 0], [+1.5, -0.6, 0], {stroke:'#1e3a8a', width:2.4});
|
||
sc.addEdge([-1.5, +0.6, 0], [+1.5, +0.6, 0], {stroke:'#dc2626', width:2.4});
|
||
sc.addLabel('a', [+1.5, -0.6, 0], {dx:12, dy:-4, color:'#1e3a8a', fontSize:14, anchor:'start'});
|
||
sc.addLabel('b', [+1.5, +0.6, 0], {dx:12, dy:-4, color:'#dc2626', fontSize:14, anchor:'start'});
|
||
document.getElementById('viz2-c3').innerHTML = sc.render();
|
||
})();
|
||
}
|
||
|
||
/* ===== §3 SVGs ===== */
|
||
var SECTION_STEP = 0;
|
||
function buildSectionHero(){
|
||
if (!window.STEREO3D) return setTimeout(buildSectionHero, 80);
|
||
var S = window.STEREO3D;
|
||
var sc = new S.Scene(440, 360, {view:'CABINET', scale:60});
|
||
sc.addCube({center:[0,0,0], size:2.0, labels:true, color:'#dbeafe', opacity:0.18});
|
||
|
||
// 3 заданные точки (шаг ≥ 1)
|
||
if (SECTION_STEP >= 1){
|
||
sc.addVertex([0,-1,-1], 'M', {dx:-14, dy:14, color:'#dc2626'});
|
||
sc.addVertex([1, 0,-1], 'N', {dx:10, dy:14, color:'#dc2626'});
|
||
sc.addVertex([1, 1, 0], 'P', {dx:14, dy:-2, color:'#dc2626'});
|
||
}
|
||
|
||
// Шаг 2: добавляем рёбра первой грани и продолжение
|
||
if (SECTION_STEP >= 2){
|
||
sc.addEdge([0,-1,-1],[1, 0,-1], {stroke:'#dc2626', width:2.6}); // M-N на нижней грани
|
||
sc.addEdge([1, 0,-1],[1, 1, 0], {stroke:'#dc2626', width:2.6}); // N-P на правой грани
|
||
}
|
||
|
||
// Шаг 3: остальные стороны (полный шестиугольник)
|
||
if (SECTION_STEP >= 3){
|
||
// P-R на задней грани, R на C1D1: R=(0,1,1)
|
||
sc.addEdge([1, 1, 0],[0, 1, 1], {stroke:'#dc2626', width:2.6});
|
||
// R-S на верхней грани, S на D1A1: S=(-1,0,1)
|
||
sc.addEdge([0, 1, 1],[-1, 0, 1], {stroke:'#dc2626', width:2.6});
|
||
// S-Q на левой грани, Q на AA1: Q=(-1,-1,0)
|
||
sc.addEdge([-1, 0, 1],[-1,-1, 0], {stroke:'#dc2626', width:2.6});
|
||
// Q-M на передней грани
|
||
sc.addEdge([-1,-1, 0],[ 0,-1,-1], {stroke:'#dc2626', width:2.6});
|
||
sc.addVertex([0, 1, 1], 'R', {dx:-12, dy:-10, color:'#dc2626'});
|
||
sc.addVertex([-1, 0, 1], 'S', {dx:-22, dy:-4, color:'#dc2626'});
|
||
sc.addVertex([-1,-1, 0], 'Q', {dx:-22, dy:6, color:'#dc2626'});
|
||
}
|
||
|
||
// Шаг 4: заливка многоугольника (правильный шестиугольник)
|
||
if (SECTION_STEP >= 4){
|
||
sc.addFace([[0,-1,-1],[1,0,-1],[1,1,0],[0,1,1],[-1,0,1],[-1,-1,0]],
|
||
{fill:'#fca5a5', opacity:0.45, stroke:'#dc2626', strokeWidth:2});
|
||
}
|
||
|
||
document.getElementById('viz3-hero').innerHTML = sc.render();
|
||
var lab = document.getElementById('viz3-step-lab');
|
||
if (lab) lab.textContent = 'Шаг ' + (SECTION_STEP + 1) + ' / 4';
|
||
var cap = document.getElementById('viz3-cap');
|
||
var capTexts = [
|
||
'На рёбрах $AB$, $BC$, $CC_1$ куба отмечены середины $M$, $N$, $P$. Нажми «Шаг построения», чтобы увидеть, как через них проводится плоскость и какая фигура получится.',
|
||
'Точки $M$, $N$, $P$ определяют плоскость (3 неколлинеарные точки). По аксиоме A2 — отрезки $MN$ и $NP$ лежат на гранях куба, попадая в плоскость сечения.',
|
||
'Продолжая прямые в плоскостях соседних граней, находим ещё 3 точки пересечения с рёбрами: $R$ на $C_1D_1$, $S$ на $D_1A_1$, $Q$ на $AA_1$.',
|
||
'Готовый многоугольник $MNPRSQ$ — <b>правильный шестиугольник</b>. Это классическое сечение куба плоскостью через 6 средин рёбер, лежащих на трёх парах противоположных граней.'
|
||
];
|
||
if (cap) cap.innerHTML = capTexts[SECTION_STEP];
|
||
tryKatex(cap);
|
||
}
|
||
|
||
function buildSectionTypes(){
|
||
if (!window.STEREO3D) return setTimeout(buildSectionTypes, 80);
|
||
var S = window.STEREO3D;
|
||
|
||
// Триангольное сечение (угловое)
|
||
(function(){
|
||
var sc = new S.Scene(220, 220, {view:'CABINET', scale:40});
|
||
sc.addCube({center:[0,0,0], size:2.0, labels:false, color:'#dbeafe', opacity:0.18});
|
||
sc.addFace([[-0.4,-1,-1],[1,0.4,-1],[1,-1,0.4]], {fill:'#fde047', opacity:0.55, stroke:'#d97706', strokeWidth:2});
|
||
sc.addEdge([-0.4,-1,-1],[1,0.4,-1], {stroke:'#d97706', width:2.4});
|
||
sc.addEdge([1,0.4,-1],[1,-1,0.4], {stroke:'#d97706', width:2.4});
|
||
sc.addEdge([1,-1,0.4],[-0.4,-1,-1], {stroke:'#d97706', width:2.4});
|
||
document.getElementById('viz3-tri').innerHTML = sc.render();
|
||
})();
|
||
|
||
// Прямоугольник (плоскость пересекает 4 параллельных ребра)
|
||
(function(){
|
||
var sc = new S.Scene(220, 220, {view:'CABINET', scale:40});
|
||
sc.addCube({center:[0,0,0], size:2.0, labels:false, color:'#dbeafe', opacity:0.18});
|
||
// Плоскость y = 0 → сечение — прямоугольник (-1,0,-1),(1,0,-1),(1,0,1),(-1,0,1)
|
||
sc.addFace([[-1,0,-1],[1,0,-1],[1,0,1],[-1,0,1]], {fill:'#86efac', opacity:0.55, stroke:'#059669', strokeWidth:2});
|
||
sc.addEdge([-1,0,-1],[1,0,-1], {stroke:'#059669', width:2.4});
|
||
sc.addEdge([1,0,-1],[1,0,1], {stroke:'#059669', width:2.4});
|
||
sc.addEdge([1,0,1],[-1,0,1], {stroke:'#059669', width:2.4});
|
||
sc.addEdge([-1,0,1],[-1,0,-1], {stroke:'#059669', width:2.4});
|
||
document.getElementById('viz3-quad').innerHTML = sc.render();
|
||
})();
|
||
|
||
// Шестиугольник (правильный, как в hero)
|
||
(function(){
|
||
var sc = new S.Scene(220, 220, {view:'CABINET', scale:40});
|
||
sc.addCube({center:[0,0,0], size:2.0, labels:false, color:'#dbeafe', opacity:0.18});
|
||
sc.addFace([[0,-1,-1],[1,0,-1],[1,1,0],[0,1,1],[-1,0,1],[-1,-1,0]],
|
||
{fill:'#fca5a5', opacity:0.55, stroke:'#dc2626', strokeWidth:2});
|
||
document.getElementById('viz3-hex').innerHTML = sc.render();
|
||
})();
|
||
}
|
||
|
||
function buildMethodOfTraces(){
|
||
if (!window.STEREO3D) return setTimeout(buildMethodOfTraces, 80);
|
||
var S = window.STEREO3D;
|
||
var sc = new S.Scene(440, 360, {view:'CABINET', scale:60});
|
||
sc.addCube({center:[0,0,0], size:2.0, labels:true, color:'#dbeafe', opacity:0.18});
|
||
|
||
// Точки M на A1B1, N на B1C1, K на CC1
|
||
var M = [-0.3, -1, 1];
|
||
var N = [1, 0.3, 1];
|
||
var K = [1, 1, -0.4];
|
||
sc.addVertex(M, 'M', {dx:-14, dy:-8, color:'#dc2626'});
|
||
sc.addVertex(N, 'N', {dx:12, dy:-8, color:'#dc2626'});
|
||
sc.addVertex(K, 'K', {dx:14, dy:6, color:'#dc2626'});
|
||
|
||
// Сечение M-N-K и достроенное
|
||
sc.addEdge(M, N, {stroke:'#dc2626', width:2.4});
|
||
sc.addEdge(N, K, {stroke:'#dc2626', width:2.4});
|
||
|
||
// След плоскости сечения на нижней грани (z=-1)
|
||
// Прямая MN продолжена до плоскости z=-1. Параметризуем M + t(N-M):
|
||
// M=(-0.3,-1,1), N=(1,0.3,1). z всегда 1 — параллельна нижней. Используем K и линию из K параллельную MN.
|
||
// Возьмём точки на нижней грани: проекции M и N сдвинуты по вертикали (z=−1). Для иллюстрации проведём след — прямую на нижней грани.
|
||
var TraceA = [-0.3, -1, -1];
|
||
var TraceB = [1, 0.3, -1];
|
||
sc.addEdge(TraceA, TraceB, {stroke:'#d97706', width:2.4, dash:'5 3'});
|
||
sc.addLabel('след', [-0.5, -0.4, -1], {color:'#d97706', fontSize:13, dy:14});
|
||
|
||
// Соединяем K с точкой на нижней (визуальная подсказка)
|
||
var Kproj = [1, 1, -1];
|
||
sc.addEdge(K, Kproj, {stroke:'#94a3b8', width:1.2, dash:'4 3'});
|
||
|
||
document.getElementById('viz3-trace').innerHTML = sc.render();
|
||
}
|
||
|
||
/* ===== Quiz items §3 ===== */
|
||
var i3TypeItems = [
|
||
{ q:'Плоскость пересекает три ребра, выходящие из одной вершины куба, в точках близко к вершине. Какое сечение?', opts:['Треугольник','Четырёхугольник','Шестиугольник','Невозможно'], correct:0, explain:'Угловой срез куба даёт треугольник (3 ребра — 3 точки — 3 стороны).' },
|
||
{ q:'Плоскость параллельна одной из граней куба. Какое сечение?', opts:['Треугольник','Квадрат','Шестиугольник','Эллипс'], correct:1, explain:'Параллельное основанию сечение куба — квадрат, равный основанию.' },
|
||
{ q:'Плоскость проходит через 6 средин рёбер, лежащих на 3 парах противоположных граней. Какое сечение?', opts:['Треугольник','Прямоугольник','Правильный шестиугольник','Окружность'], correct:2, explain:'Через 6 средин получается правильный шестиугольник — классическое сечение куба.' },
|
||
{ q:'Может ли сечение куба быть пятиугольником?', opts:['Да','Нет','Только при наклоне'], correct:0, explain:'Да: плоскость, пересекающая 5 граней куба из 6, даёт 5-угольник.' },
|
||
{ q:'Сечение тетраэдра — это всегда $n$-угольник, где $n \\le$ ?', opts:['3','4','5','6'], correct:1, explain:'У тетраэдра 4 грани ⇒ максимум 4-угольное сечение.' },
|
||
{ q:'Сечение плоскостью, параллельной основанию пирамиды, подобно чему?', opts:['Боковой грани','Основанию','Высоте','Не подобно'], correct:1, explain:'Параллельное основанию сечение пирамиды подобно основанию.' }
|
||
];
|
||
|
||
var i3MaxItems = [
|
||
{ q:'Максимальное число сторон сечения куба?', answer:'6', explain:'Куб имеет 6 граней — плоскость пересечёт их максимум по 6 отрезкам.' },
|
||
{ q:'Максимальное число сторон сечения тетраэдра?', answer:'4', explain:'У тетраэдра 4 грани ⇒ максимум 4-угольник.' },
|
||
{ q:'Максимальное число сторон сечения шестиугольной призмы?', answer:'8', explain:'У 6-уг. призмы $6+2=8$ граней ⇒ максимум 8-угольник.' },
|
||
{ q:'Сечение пятиугольной пирамиды — максимум $n$-угольник. Найди $n$.', answer:'5', explain:'У 5-уг. пирамиды $5+1=6$ граней, но плоскость не может пересечь основание и его параллельную плоскость — максимум 5 сторон.' },
|
||
{ q:'У многогранника $Г = 10$ граней. Максимальное число сторон сечения?', answer:'10', explain:'Не больше числа граней — то есть 10.' }
|
||
];
|
||
|
||
var i3TraceItems = [
|
||
{ q:'Следом плоскости сечения называется линия её пересечения с одной из граней.', opts:['Верно','Неверно'], correct:0, explain:'Точно так. След — обычно с плоскостью основания.' },
|
||
{ q:'Если плоскость параллельна основанию пирамиды, она имеет след на основании.', opts:['Верно','Неверно'], correct:1, explain:'Параллельные плоскости не пересекаются — следа на основании нет.' },
|
||
{ q:'Зная след в основании и одну точку выше, можно построить всё сечение.', opts:['Верно','Неверно'], correct:0, explain:'Это и есть суть метода следов.' },
|
||
{ q:'След проводится с помощью аксиомы A3 о пересечении плоскостей.', opts:['Верно','Неверно'], correct:0, explain:'Да: след — это прямая пересечения плоскости сечения с плоскостью основания.' },
|
||
{ q:'Сечение всегда лежит в одной плоскости.', opts:['Верно','Неверно'], correct:0, explain:'По определению — плоское сечение лежит в одной (секущей) плоскости.' }
|
||
];
|
||
|
||
function runQuizMC(opts){
|
||
var state = STATE.interactives[opts.id] || { idx: 0, solved: 0 };
|
||
var qEl = document.getElementById(opts.id + '-q');
|
||
var optsEl = document.getElementById(opts.id + '-opts');
|
||
var fbEl = document.getElementById(opts.id + '-fb');
|
||
var progEl = document.getElementById(opts.id + '-prog');
|
||
|
||
function render(){
|
||
if (state.solved >= opts.items.length){
|
||
qEl.innerHTML = '<b style="color:var(--good)">Все задания решены!</b> +' + (opts.xpPerAll || 10) + ' XP.';
|
||
optsEl.innerHTML = '';
|
||
fbEl.classList.remove('show');
|
||
progEl.textContent = opts.items.length + ' / ' + opts.items.length;
|
||
if (!state.awarded){
|
||
state.awarded = true;
|
||
STATE.interactives[opts.id] = state;
|
||
saveState();
|
||
addXp(opts.xpPerAll || 10, opts.title || 'тренажёр');
|
||
}
|
||
return;
|
||
}
|
||
var item = opts.items[state.idx % opts.items.length];
|
||
qEl.innerHTML = item.q;
|
||
optsEl.innerHTML = '';
|
||
fbEl.classList.remove('show');
|
||
for (var i = 0; i < item.opts.length; i++){
|
||
(function(i){
|
||
var btn = document.createElement('button');
|
||
btn.className = 'quiz-opt';
|
||
btn.innerHTML = item.opts[i];
|
||
btn.addEventListener('click', function(){
|
||
var correct = (i === item.correct);
|
||
if (correct){
|
||
btn.classList.add('correct');
|
||
state.solved++;
|
||
state.idx++;
|
||
STATE.interactives[opts.id] = state;
|
||
saveState();
|
||
progEl.textContent = state.solved + ' / ' + opts.items.length;
|
||
fbEl.className = 'quiz-feedback show good';
|
||
fbEl.innerHTML = '<b>Верно.</b> ' + (item.explain || '');
|
||
tryKatex(fbEl);
|
||
setTimeout(render, 900);
|
||
} else {
|
||
btn.classList.add('wrong');
|
||
fbEl.className = 'quiz-feedback show bad';
|
||
fbEl.innerHTML = '<b>Не так.</b> ' + (item.explain || '');
|
||
tryKatex(fbEl);
|
||
}
|
||
});
|
||
optsEl.appendChild(btn);
|
||
})(i);
|
||
}
|
||
progEl.textContent = state.solved + ' / ' + opts.items.length;
|
||
tryKatex(qEl);
|
||
}
|
||
render();
|
||
}
|
||
|
||
function runQuizInput(opts){
|
||
var state = STATE.interactives[opts.id] || { idx:0, solved:0 };
|
||
var qEl = document.getElementById(opts.id + '-q');
|
||
var inEl = document.getElementById(opts.id + '-in');
|
||
var goEl = document.getElementById(opts.id + '-go');
|
||
var fbEl = document.getElementById(opts.id + '-fb');
|
||
var progEl = document.getElementById(opts.id + '-prog');
|
||
var box = inEl.parentNode;
|
||
|
||
function render(){
|
||
if (state.solved >= opts.items.length){
|
||
qEl.innerHTML = '<b style="color:var(--good)">Все задания решены!</b> +' + (opts.xpPerAll || 10) + ' XP.';
|
||
inEl.value = ''; inEl.disabled = true; goEl.disabled = true;
|
||
progEl.textContent = opts.items.length + ' / ' + opts.items.length;
|
||
box.className = 'quiz-input correct';
|
||
if (!state.awarded){
|
||
state.awarded = true;
|
||
STATE.interactives[opts.id] = state;
|
||
saveState();
|
||
addXp(opts.xpPerAll || 10, opts.title || 'тренажёр');
|
||
}
|
||
return;
|
||
}
|
||
var item = opts.items[state.idx % opts.items.length];
|
||
qEl.innerHTML = item.q;
|
||
inEl.value = ''; inEl.disabled = false; goEl.disabled = false;
|
||
fbEl.classList.remove('show');
|
||
box.className = 'quiz-input';
|
||
progEl.textContent = state.solved + ' / ' + opts.items.length;
|
||
tryKatex(qEl);
|
||
}
|
||
function check(){
|
||
var item = opts.items[state.idx % opts.items.length];
|
||
var v = (inEl.value || '').trim().toLowerCase().replace(/\s+/g,'');
|
||
var ans = String(item.answer).toLowerCase().replace(/\s+/g,'');
|
||
if (v === ans){
|
||
box.className = 'quiz-input correct';
|
||
state.solved++;
|
||
state.idx++;
|
||
STATE.interactives[opts.id] = state;
|
||
saveState();
|
||
fbEl.className = 'quiz-feedback show good';
|
||
fbEl.innerHTML = '<b>Верно.</b> ' + (item.explain || '');
|
||
tryKatex(fbEl);
|
||
setTimeout(render, 900);
|
||
} else {
|
||
box.className = 'quiz-input wrong';
|
||
fbEl.className = 'quiz-feedback show bad';
|
||
fbEl.innerHTML = '<b>Не так.</b> ' + (item.explain || '');
|
||
tryKatex(fbEl);
|
||
}
|
||
}
|
||
goEl.addEventListener('click', check);
|
||
inEl.addEventListener('keydown', function(e){ if (e.key === 'Enter') check(); });
|
||
render();
|
||
}
|
||
|
||
var i1SolidItems = [
|
||
{ q:'Тело с двумя равными $n$-угольными гранями в параллельных плоскостях и $n$ параллелограммами по бокам.', opts:['Призма','Пирамида','Цилиндр','Конус'], correct:0, explain:'Это определение призмы.' },
|
||
{ q:'Тело с одной многоугольной гранью и треугольными боковыми гранями с общей вершиной.', opts:['Призма','Пирамида','Цилиндр','Конус'], correct:1, explain:'Пирамида: одно основание + треугольные боковые.' },
|
||
{ q:'Тело, полученное вращением прямоугольника вокруг одной из его сторон.', opts:['Шар','Цилиндр','Конус','Призма'], correct:1, explain:'Цилиндр — тело вращения прямоугольника.' },
|
||
{ q:'Тело, полученное вращением прямоугольного треугольника вокруг катета.', opts:['Конус','Цилиндр','Шар','Пирамида'], correct:0, explain:'Конус — вращение прямоугольного треугольника вокруг катета.' },
|
||
{ q:'Тело, полученное вращением полукруга вокруг диаметра.', opts:['Цилиндр','Конус','Шар','Тор'], correct:2, explain:'Шар — вращение полукруга вокруг диаметра.' },
|
||
{ q:'Многогранник, у которого все 4 грани — равные правильные треугольники.', opts:['Куб','Тетраэдр','Октаэдр','Икосаэдр'], correct:1, explain:'Правильный тетраэдр: 4 равносторонних треугольника.' }
|
||
];
|
||
|
||
var i1CountItems = [
|
||
{ q:'Сколько рёбер у шестиугольной призмы?', answer:'18', explain:'У $n$-угольной призмы $3n$ рёбер. При $n=6$: $3 \\cdot 6 = 18$.' },
|
||
{ q:'Сколько граней у пятиугольной пирамиды?', answer:'6', explain:'$n+1$ грань: $5+1=6$.' },
|
||
{ q:'Сколько вершин у куба?', answer:'8', explain:'У куба 8 вершин (по 4 на каждом из двух квадратных оснований).' },
|
||
{ q:'Сколько пространственных диагоналей у параллелепипеда?', answer:'4', explain:'4 диагонали — каждая соединяет противоположные вершины.' },
|
||
{ q:'Многогранник: $В=6, Г=8$. Найди $Р$ по формуле Эйлера.', answer:'12', explain:'$6 - Р + 8 = 2 \\Rightarrow Р = 12$. Это октаэдр.' },
|
||
{ q:'Сколько рёбер у 7-угольной пирамиды? (формула $2n$)', answer:'14', explain:'$2 \\cdot 7 = 14$ рёбер.' }
|
||
];
|
||
|
||
var i2AxiomItems = [
|
||
{ q:'«Через три точки $A, B, C$, не лежащие на одной прямой, проведена плоскость.»', opts:['A1','A2','A3','Следствие'], correct:0, explain:'Это формулировка A1.' },
|
||
{ q:'«Точки $M, N \\in \\alpha$, значит и вся прямая $MN \\subset \\alpha$.»', opts:['A1','A2','A3','Следствие'], correct:1, explain:'Аксиома A2.' },
|
||
{ q:'«Плоскости $\\alpha$ и $\\beta$ имеют общую точку $P$ — у них есть прямая пересечения.»', opts:['A1','A2','A3','Следствие'], correct:2, explain:'Аксиома A3.' },
|
||
{ q:'«Через прямую $a$ и точку $M \\notin a$ проходит единственная плоскость.»', opts:['A1','A2','A3','Следствие'], correct:3, explain:'Следствие из A1.' },
|
||
{ q:'«Через две пересекающиеся прямые проходит единственная плоскость.»', opts:['A1','A2','A3','Следствие'], correct:3, explain:'Следствие из A1.' },
|
||
{ q:'«Если две точки прямой лежат в плоскости — прямая лежит в плоскости.»', opts:['A1','A2','A3','Следствие'], correct:1, explain:'Точная формулировка A2.' }
|
||
];
|
||
|
||
var i2PlaneItems = [
|
||
{ q:'Даны 3 точки, не лежащие на одной прямой. Можно задать плоскость?', opts:['Да, единственную','Да, бесконечно','Нельзя'], correct:0, explain:'A1: 3 неколлинеарные точки задают единственную плоскость.' },
|
||
{ q:'Даны 3 точки на одной прямой. Сколько плоскостей через них?', opts:['Одна','Бесконечно','Ни одной'], correct:1, explain:'Плоскостей бесконечно много (вращаются вокруг прямой).' },
|
||
{ q:'Через 2 пересекающиеся прямые проходит:', opts:['Одна плоскость','Две','Бесконечно'], correct:0, explain:'Следствие: единственная.' },
|
||
{ q:'Даны 2 скрещивающиеся прямые. Можно ли провести через них одну плоскость?', opts:['Да','Нет','Иногда'], correct:1, explain:'Скрещивающиеся не лежат в одной плоскости — это и есть определение.' },
|
||
{ q:'Через прямую и точку вне её проходит:', opts:['Одна плоскость','Две','Бесконечно'], correct:0, explain:'Следствие: единственная.' }
|
||
];
|
||
|
||
var i2CountItems = [
|
||
{ q:'Сколько плоскостей через 4 точки общего положения (никакие 3 — не на одной прямой, не все в одной плоскости)?', opts:['1','3','4','6'], correct:2, explain:'Каждые 3 из 4 определяют плоскость: $C_4^3 = 4$.' },
|
||
{ q:'Через 2 параллельные прямые проходит:', opts:['1 плоскость','2','Бесконечно'], correct:0, explain:'Единственная плоскость.' },
|
||
{ q:'Через сколько точек, не лежащих на одной прямой, проходит не более 1 плоскости?', opts:['2','3','4','5'], correct:1, explain:'3 точки задают плоскость однозначно.' },
|
||
{ q:'Сколько общих точек у двух различных пересекающихся плоскостей?', opts:['Одна','Конечное число','Бесконечно (по прямой)'], correct:2, explain:'A3: пересечение по прямой ⇒ бесконечно точек.' },
|
||
{ q:'Сколько плоскостей содержат данную прямую $l$?', opts:['Одна','Две','Бесконечно'], correct:2, explain:'Через прямую — бесконечно плоскостей.' }
|
||
];
|
||
|
||
var BOSS_DEFS = {
|
||
1: {
|
||
title:'§1 — Пространственные фигуры',
|
||
xp:60,
|
||
stages:[
|
||
{ q:'Сколько рёбер у пятиугольной призмы?', type:'input', a:'15', explain:'$3n = 3 \\cdot 5 = 15$ рёбер.' },
|
||
{ q:'Сколько вершин у $n$-угольной пирамиды при $n=8$?', type:'input', a:'9', explain:'$n+1 = 9$ вершин.' },
|
||
{ q:'Какое тело получится при вращении прямоугольника вокруг стороны?', type:'mc', opts:['Шар','Цилиндр','Конус','Призма'], correct:1, explain:'Цилиндр.' },
|
||
{ q:'Сколько пространственных диагоналей у куба?', type:'input', a:'4', explain:'Куб имеет 4 пространственные диагонали.' },
|
||
{ q:'У многогранника $В=12$, $Р=30$. Сколько граней по Эйлеру?', type:'input', a:'20', explain:'$12 - 30 + Г = 2 \\Rightarrow Г = 20$. Икосаэдр.' }
|
||
]
|
||
},
|
||
2: {
|
||
title:'§2 — Прямые и плоскости',
|
||
xp:65,
|
||
stages:[
|
||
{ q:'Через сколько плоскостей проходит прямая?', type:'mc', opts:['1','2','3','Бесконечно'], correct:3, explain:'Через прямую — бесконечно плоскостей.' },
|
||
{ q:'Через 3 точки на одной прямой — сколько плоскостей?', type:'mc', opts:['1','2','3','Бесконечно'], correct:3, explain:'Точки коллинеарны ⇒ бесконечно плоскостей.' },
|
||
{ q:'Если две плоскости имеют общую точку — они пересекаются по…', type:'mc', opts:['Точке','Прямой','Плоскости','Не пересекаются'], correct:1, explain:'A3: пересечение — прямая.' },
|
||
{ q:'Сколько способов однозначно задать плоскость?', type:'mc', opts:['2','3','4','5'], correct:2, explain:'4 способа: 3 точки, прямая + точка, 2 пересек., 2 парал.' },
|
||
{ q:'Сколько плоскостей задают 4 точки общего положения?', type:'input', a:'4', explain:'$C_4^3 = 4$ тройки точек.' }
|
||
]
|
||
},
|
||
3: {
|
||
title:'§3 — Построения сечений',
|
||
xp:70,
|
||
stages:[
|
||
{ q:'Сечением куба может ли быть шестиугольник?', type:'mc', opts:['Да','Нет','Только наклонный'], correct:0, explain:'Да: классическое сечение через 6 средин рёбер.' },
|
||
{ q:'Максимальное число сторон сечения куба?', type:'input', a:'6', explain:'6 граней ⇒ max 6 сторон.' },
|
||
{ q:'Максимальное число сторон сечения треугольной пирамиды (тетраэдра)?', type:'input', a:'4', explain:'4 грани тетраэдра ⇒ max 4 стороны.' },
|
||
{ q:'Плоскость, параллельная основанию пирамиды, даёт сечение, $?$ основанию.', type:'mc', opts:['Равное','Подобное','Перпендикулярное','Совпадающее'], correct:1, explain:'Подобное основанию (коэффициент подобия зависит от высоты).' },
|
||
{ q:'Какое сечение даёт плоскость куба, проходящая через 6 средин рёбер на 3 парах противоположных граней?', type:'mc', opts:['Квадрат','Треугольник','Правильный шестиугольник','Эллипс'], correct:2, explain:'Правильный шестиугольник.' }
|
||
]
|
||
}
|
||
};
|
||
|
||
var FINAL_BOSS_DEFS = {
|
||
f1: {
|
||
title:'Босс 1 · Элементы тел',
|
||
xp:35,
|
||
stages:[
|
||
{ q:'Сколько рёбер у 7-угольной призмы?', type:'input', a:'21', explain:'$3n = 21$.' },
|
||
{ q:'Сколько граней у 6-угольной пирамиды?', type:'input', a:'7', explain:'$n+1=7$.' },
|
||
{ q:'Сколько вершин у тетраэдра?', type:'input', a:'4', explain:'4 вершины.' },
|
||
{ q:'$В=20, Р=30$. Сколько граней по Эйлеру?', type:'input', a:'12', explain:'$20-30+Г=2 \\Rightarrow Г=12$. Это додекаэдр.' }
|
||
]
|
||
},
|
||
f2: {
|
||
title:'Босс 2 · Аксиомы',
|
||
xp:35,
|
||
stages:[
|
||
{ q:'Через прямую и точку вне её проходит:', type:'mc', opts:['1 плоскость','2','Бесконечно'], correct:0, explain:'Единственная.' },
|
||
{ q:'Две плоскости пересекаются по:', type:'mc', opts:['Точке','Прямой','Плоскости','Не пересекаются'], correct:1, explain:'По прямой (A3).' },
|
||
{ q:'Если две точки прямой лежат в плоскости, то…', type:'mc', opts:['Прямая параллельна плоскости','Вся прямая лежит в плоскости','Прямая пересекает плоскость','Утверждение неверно'], correct:1, explain:'A2.' },
|
||
{ q:'Скрещивающиеся прямые лежат в одной плоскости?', type:'mc', opts:['Да','Нет','Иногда'], correct:1, explain:'По определению — нет.' }
|
||
]
|
||
},
|
||
f3: {
|
||
title:'Босс 3 · Сечения',
|
||
xp:35,
|
||
stages:[
|
||
{ q:'Может ли быть сечением куба пятиугольник?', type:'mc', opts:['Да','Нет','Только правильный'], correct:0, explain:'Да: плоскость пересекает 5 граней из 6.' },
|
||
{ q:'Максимум сторон у сечения 4-угольной призмы (параллелепипеда)?', type:'input', a:'6', explain:'$n+2=4+2=6$.' },
|
||
{ q:'Сечение параллельное основанию призмы:', type:'mc', opts:['Подобное основанию','Равное основанию','Меньше основания','Перпендикулярно основанию'], correct:1, explain:'У призмы — равное основанию.' },
|
||
{ q:'След плоскости сечения — это:', type:'mc', opts:['Точка','Линия пересечения с гранью','Касательная','Высота сечения'], correct:1, explain:'Линия пересечения секущей плоскости с гранью (обычно — с основанием).' }
|
||
]
|
||
},
|
||
f4: {
|
||
title:'Босс 4 · Сборная',
|
||
xp:45,
|
||
stages:[
|
||
{ q:'Сколько рёбер пересечёт плоскость, если сечение куба — шестиугольник?', type:'input', a:'6', explain:'Каждая сторона сечения — пересечение с одним ребром (или гранью). 6 сторон ⇒ 6 рёбер.' },
|
||
{ q:'У многогранника $В=8, Р=12, Г=6$. Что это?', type:'mc', opts:['Тетраэдр','Куб','Октаэдр','Додекаэдр'], correct:1, explain:'Куб: $8-12+6=2$ ✓.' },
|
||
{ q:'В пирамиде с 5-угольным основанием сечение, параллельное основанию, имеет:', type:'mc', opts:['3 стороны','4 стороны','5 сторон','6 сторон'], correct:2, explain:'Подобно основанию — тоже 5-угольник.' },
|
||
{ q:'Сколько плоскостей задают вершины тетраэдра?', type:'input', a:'4', explain:'$C_4^3 = 4$ грани (плоскости).' },
|
||
{ q:'У призмы $n$ боковых рёбер. У 9-угольной — сколько?', type:'input', a:'9', explain:'Ровно $n=9$.' }
|
||
]
|
||
}
|
||
};
|
||
|
||
function renderFinalBoss(id){
|
||
var def = FINAL_BOSS_DEFS[id];
|
||
if (!def) return;
|
||
var el = document.getElementById('boss-' + id);
|
||
if (!el) return;
|
||
if (!STATE.bosses) STATE.bosses = {};
|
||
var st = STATE.bosses[id] || { stage:0, defeated:false };
|
||
STATE.bosses[id] = st;
|
||
if (st.defeated){
|
||
el.classList.add('victory');
|
||
el.innerHTML = '<div class="boss-defeated">'
|
||
+ '<div class="boss-defeated-title">' + def.title + ' побеждён!</div>'
|
||
+ '<span class="boss-defeated-xp">+' + def.xp + ' XP</span>'
|
||
+ '</div>';
|
||
checkFinalComplete();
|
||
return;
|
||
}
|
||
el.classList.remove('victory');
|
||
var total = def.stages.length;
|
||
var stage = def.stages[st.stage];
|
||
var hp = Math.round((1 - st.stage/total) * 100);
|
||
var optsHtml;
|
||
if (stage.type === 'mc'){
|
||
optsHtml = '<div class="boss-opts">';
|
||
for (var i = 0; i < stage.opts.length; i++){
|
||
optsHtml += '<button class="boss-opt" data-i="' + i + '">' + stage.opts[i] + '</button>';
|
||
}
|
||
optsHtml += '</div>';
|
||
} else {
|
||
optsHtml = '<div class="boss-input"><input type="text" id="boss-' + id + '-in" inputmode="text" placeholder="ответ"><button id="boss-' + id + '-go">Атака</button></div>';
|
||
}
|
||
el.innerHTML = '<div class="boss-h">'
|
||
+ '<span class="boss-badge">Финал</span>'
|
||
+ '<span class="boss-title">' + def.title + '</span>'
|
||
+ '</div>'
|
||
+ '<div class="boss-hp"><div class="boss-hp-label"><span>HP босса</span><span>' + hp + '%</span></div>'
|
||
+ '<div class="boss-hp-bar"><div class="boss-hp-fill" style="width:' + hp + '%"></div></div></div>'
|
||
+ '<div class="boss-question">'
|
||
+ '<div class="boss-stage-label">Этап ' + (st.stage+1) + ' / ' + total + '</div>'
|
||
+ '<div class="boss-q">' + stage.q + '</div>'
|
||
+ optsHtml + '</div>';
|
||
|
||
if (stage.type === 'mc'){
|
||
el.querySelectorAll('.boss-opt').forEach(function(btn){
|
||
btn.addEventListener('click', function(){
|
||
var i = parseInt(btn.getAttribute('data-i'), 10);
|
||
var ok = (i === stage.correct);
|
||
if (ok){
|
||
btn.classList.add('correct');
|
||
setTimeout(function(){ advanceFinalBoss(id); }, 600);
|
||
} else {
|
||
btn.classList.add('wrong');
|
||
setTimeout(function(){ btn.classList.remove('wrong'); }, 600);
|
||
}
|
||
});
|
||
});
|
||
} else {
|
||
var inEl = document.getElementById('boss-' + id + '-in');
|
||
var goEl = document.getElementById('boss-' + id + '-go');
|
||
var box = inEl.parentNode;
|
||
function attack(){
|
||
var v = (inEl.value || '').trim().toLowerCase().replace(/\s+/g,'');
|
||
var a = String(stage.a).toLowerCase().replace(/\s+/g,'');
|
||
if (v === a){
|
||
inEl.style.background = 'rgba(34,197,94,.25)';
|
||
setTimeout(function(){ advanceFinalBoss(id); }, 500);
|
||
} else {
|
||
box.classList.add('wrong');
|
||
inEl.style.background = 'rgba(220,38,38,.25)';
|
||
setTimeout(function(){ box.classList.remove('wrong'); inEl.style.background=''; }, 600);
|
||
}
|
||
}
|
||
goEl.addEventListener('click', attack);
|
||
inEl.addEventListener('keydown', function(e){ if (e.key === 'Enter') attack(); });
|
||
}
|
||
|
||
tryKatex(el);
|
||
}
|
||
|
||
function advanceFinalBoss(id){
|
||
var st = STATE.bosses[id];
|
||
var def = FINAL_BOSS_DEFS[id];
|
||
st.stage++;
|
||
if (st.stage >= def.stages.length){
|
||
st.defeated = true;
|
||
saveState();
|
||
addXp(def.xp, def.title);
|
||
} else {
|
||
saveState();
|
||
}
|
||
renderFinalBoss(id);
|
||
}
|
||
|
||
function checkFinalComplete(){
|
||
var allBeat = ['f1','f2','f3','f4'].every(function(k){
|
||
return STATE.bosses[k] && STATE.bosses[k].defeated;
|
||
});
|
||
if (!allBeat) return;
|
||
var cel = document.getElementById('celebration');
|
||
if (!cel) return;
|
||
if (cel.dataset.shown === '1') return;
|
||
cel.dataset.shown = '1';
|
||
cel.style.display = 'block';
|
||
cel.innerHTML = '<div class="boss victory" style="text-align:center;padding:40px 24px">'
|
||
+ '<div style="font-family:Unbounded,sans-serif;font-size:1.8rem;font-weight:900;color:#fef3c7;letter-spacing:-.01em;margin-bottom:8px">★ Раздел 1 пройден! ★</div>'
|
||
+ '<div style="font-size:1rem;color:#dcfce7;margin-bottom:16px">Все 4 финальных босса побеждены. Введение в стереометрию — освоено.</div>'
|
||
+ '<span class="boss-defeated-xp" style="font-size:1rem;padding:10px 22px">+ 100 XP бонус + ачивка «stereo10_r1_master»</span>'
|
||
+ '</div>';
|
||
// ачивка + бонус
|
||
var achKey = 'geometry10_achievements';
|
||
var raw = localStorage.getItem(achKey);
|
||
var list = [];
|
||
try { list = raw ? JSON.parse(raw) : []; } catch(e){}
|
||
if (list.indexOf('stereo10_r1_master') < 0){
|
||
list.push('stereo10_r1_master');
|
||
localStorage.setItem(achKey, JSON.stringify(list));
|
||
addXp(100, 'ачивка: Введение в стереометрию');
|
||
}
|
||
}
|
||
|
||
function renderBoss(num){
|
||
var def = BOSS_DEFS[num];
|
||
if (!def) return;
|
||
var el = document.getElementById('boss-' + num);
|
||
if (!el) return;
|
||
var st = STATE.bosses[num] || { stage:0, defeated:false };
|
||
STATE.bosses[num] = st;
|
||
if (st.defeated){
|
||
el.classList.add('victory');
|
||
el.innerHTML = '<div class="boss-defeated">'
|
||
+ '<div class="boss-defeated-title">Босс §' + num + ' побеждён!</div>'
|
||
+ '<div class="boss-defeated-sub">' + def.title + '</div>'
|
||
+ '<span class="boss-defeated-xp">+' + def.xp + ' XP</span>'
|
||
+ '</div>';
|
||
return;
|
||
}
|
||
el.classList.remove('victory');
|
||
var total = def.stages.length;
|
||
var stage = def.stages[st.stage];
|
||
var hp = Math.round((1 - st.stage/total) * 100);
|
||
var optsHtml;
|
||
if (stage.type === 'mc'){
|
||
optsHtml = '<div class="boss-opts">';
|
||
for (var i = 0; i < stage.opts.length; i++){
|
||
optsHtml += '<button class="boss-opt" data-i="' + i + '">' + stage.opts[i] + '</button>';
|
||
}
|
||
optsHtml += '</div>';
|
||
} else {
|
||
optsHtml = '<div class="boss-input"><input type="text" id="boss-' + num + '-in" inputmode="text" placeholder="ответ"><button id="boss-' + num + '-go">Атака</button></div>';
|
||
}
|
||
el.innerHTML = '<div class="boss-h">'
|
||
+ '<span class="boss-badge">Босс</span>'
|
||
+ '<span class="boss-title">' + def.title + '</span>'
|
||
+ '</div>'
|
||
+ '<div class="boss-hp"><div class="boss-hp-label"><span>HP босса</span><span>' + hp + '%</span></div>'
|
||
+ '<div class="boss-hp-bar"><div class="boss-hp-fill" style="width:' + hp + '%"></div></div></div>'
|
||
+ '<div class="boss-question">'
|
||
+ '<div class="boss-stage-label">Этап ' + (st.stage+1) + ' / ' + total + '</div>'
|
||
+ '<div class="boss-q">' + stage.q + '</div>'
|
||
+ optsHtml + '</div>';
|
||
|
||
if (stage.type === 'mc'){
|
||
el.querySelectorAll('.boss-opt').forEach(function(btn){
|
||
btn.addEventListener('click', function(){
|
||
var i = parseInt(btn.getAttribute('data-i'), 10);
|
||
var ok = (i === stage.correct);
|
||
if (ok){
|
||
btn.classList.add('correct');
|
||
setTimeout(function(){ advanceBoss(num); }, 600);
|
||
} else {
|
||
btn.classList.add('wrong');
|
||
setTimeout(function(){ btn.classList.remove('wrong'); }, 600);
|
||
}
|
||
});
|
||
});
|
||
} else {
|
||
var inEl = document.getElementById('boss-' + num + '-in');
|
||
var goEl = document.getElementById('boss-' + num + '-go');
|
||
var box = inEl.parentNode;
|
||
function attack(){
|
||
var v = (inEl.value || '').trim().toLowerCase().replace(/\s+/g,'');
|
||
var a = String(stage.a).toLowerCase().replace(/\s+/g,'');
|
||
if (v === a){
|
||
box.classList.remove('wrong');
|
||
inEl.style.background = 'rgba(34,197,94,.25)';
|
||
setTimeout(function(){ advanceBoss(num); }, 500);
|
||
} else {
|
||
box.classList.add('wrong');
|
||
inEl.style.background = 'rgba(220,38,38,.25)';
|
||
setTimeout(function(){ box.classList.remove('wrong'); inEl.style.background=''; }, 600);
|
||
}
|
||
}
|
||
goEl.addEventListener('click', attack);
|
||
inEl.addEventListener('keydown', function(e){ if (e.key === 'Enter') attack(); });
|
||
}
|
||
|
||
tryKatex(el);
|
||
}
|
||
|
||
function advanceBoss(num){
|
||
var st = STATE.bosses[num];
|
||
var def = BOSS_DEFS[num];
|
||
st.stage++;
|
||
if (st.stage >= def.stages.length){
|
||
st.defeated = true;
|
||
saveState();
|
||
addXp(def.xp, 'босс §' + num);
|
||
} else {
|
||
saveState();
|
||
}
|
||
renderBoss(num);
|
||
}
|
||
|
||
function tryKatex(scope){
|
||
if (!window.renderMathInElement) return;
|
||
try {
|
||
window.renderMathInElement(scope || document.body, {
|
||
delimiters: [
|
||
{left:'$$', right:'$$', display:true},
|
||
{left:'$', right:'$', display:false},
|
||
{left:'\\(', right:'\\)', display:false},
|
||
{left:'\\[', right:'\\]', display:true}
|
||
],
|
||
throwOnError: false
|
||
});
|
||
} catch(e){}
|
||
}
|
||
|
||
function start(){
|
||
buildHeroSolids();
|
||
buildAnnotatedCube();
|
||
buildPrismDirect();
|
||
buildPrismOblique();
|
||
buildRotCube();
|
||
buildAxiomVizes();
|
||
buildSectionHero();
|
||
buildSectionTypes();
|
||
buildMethodOfTraces();
|
||
|
||
// Кнопка «Шаг построения»
|
||
var stepBtn = document.getElementById('viz3-step-btn');
|
||
if (stepBtn){
|
||
stepBtn.addEventListener('click', function(){
|
||
SECTION_STEP = (SECTION_STEP + 1) % 4;
|
||
buildSectionHero();
|
||
stepBtn.querySelector ? null : null;
|
||
stepBtn.textContent = SECTION_STEP === 3 ? 'Сначала' : 'Шаг построения →';
|
||
});
|
||
}
|
||
|
||
runQuizMC({ id:'i1-solid', items:i1SolidItems, xpPerAll:12, title:'узнавание тел' });
|
||
runQuizInput({ id:'i1-count', items:i1CountItems, xpPerAll:15, title:'счёт элементов' });
|
||
runQuizMC({ id:'i2-axiom', items:i2AxiomItems, xpPerAll:12, title:'аксиомы' });
|
||
runQuizMC({ id:'i2-plane', items:i2PlaneItems, xpPerAll:10, title:'задание плоскости' });
|
||
runQuizMC({ id:'i2-count', items:i2CountItems, xpPerAll:10, title:'счёт плоскостей' });
|
||
runQuizMC({ id:'i3-type', items:i3TypeItems, xpPerAll:14, title:'тип сечения' });
|
||
runQuizInput({ id:'i3-max', items:i3MaxItems, xpPerAll:14, title:'max сторон сечения' });
|
||
runQuizMC({ id:'i3-trace', items:i3TraceItems, xpPerAll:10, title:'метод следов' });
|
||
|
||
renderBoss(1);
|
||
renderBoss(2);
|
||
renderBoss(3);
|
||
renderFinalBoss('f1');
|
||
renderFinalBoss('f2');
|
||
renderFinalBoss('f3');
|
||
renderFinalBoss('f4');
|
||
checkFinalComplete();
|
||
|
||
document.getElementById('mark-1').addEventListener('click', function(){ markRead(1); });
|
||
document.getElementById('mark-2').addEventListener('click', function(){ markRead(2); });
|
||
document.getElementById('mark-3').addEventListener('click', function(){ markRead(3); });
|
||
refreshMarkBtn(1); refreshMarkBtn(2); refreshMarkBtn(3);
|
||
refreshTabs();
|
||
|
||
var tabs = document.querySelectorAll('.sec-tab[data-tab]');
|
||
var sections = ['para-1','para-2','para-3','para-final'];
|
||
function onScroll(){
|
||
var y = window.scrollY + 100;
|
||
var active = 0;
|
||
for (var i = 0; i < sections.length; i++){
|
||
var el = document.getElementById(sections[i]);
|
||
if (!el) continue;
|
||
if (el.offsetTop <= y) active = i;
|
||
}
|
||
tabs.forEach(function(t,j){ if (j === active) t.classList.add('active'); else t.classList.remove('active'); });
|
||
}
|
||
window.addEventListener('scroll', onScroll, {passive:true});
|
||
|
||
setTimeout(function(){ tryKatex(document.body); }, 50);
|
||
}
|
||
|
||
if (document.readyState === 'loading'){
|
||
document.addEventListener('DOMContentLoaded', start);
|
||
} else {
|
||
start();
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|