diff --git a/frontend/textbooks/geometry_10_r1.html b/frontend/textbooks/geometry_10_r1.html index ef5cf61..cdb45a0 100644 --- a/frontend/textbooks/geometry_10_r1.html +++ b/frontend/textbooks/geometry_10_r1.html @@ -195,8 +195,8 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px}
§1 Фигуры §2 Аксиомы - §3 Сечения - Финал + §3 Сечения + Финал
@@ -503,10 +503,124 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px}
Метод следов · сечения куба, призмы, пирамиды
-
- В разработке (Волна W2) - Параграф появится в следующей волне: сложная анимированная визуализация построения сечений многогранников. - Сейчас сосредоточься на §1 и §2 — они дают контекст для §3. + +
+
МЕТОД 3 ТОЧЕК Сечение куба плоскостью через $M$, $N$, $P$ — правильный шестиугольник
+
+
+ + Шаг 1 / 4 +
+
На рёбрах $AB$, $BC$, $CC_1$ куба отмечены середины $M$, $N$, $P$. Нажми «Шаг построения», чтобы увидеть, как через них проводится плоскость и какая фигура получится.
+
+ +
+
ТИПЫ СЕЧЕНИЙ КУБА От треугольника до шестиугольника
+
+
Треугольник
+
Прямоугольник
+
Шестиугольник (max)
+
+
Куб «теряет» одну грань при пересечении плоскостью — поэтому сечение имеет от 3 до 6 сторон. Тетраэдр (4 грани) — максимум 4-угольник. Призма с $n$-угольным основанием — максимум $(n+2)$-угольник.
+
+ +
+
МЕТОД СЛЕДОВ Как строится сечение, выходящее за пределы видимых граней
+
+
Пусть в кубе отмечены $M$, $N$ на верхних рёбрах и $K$ на боковом ребре. Тогда: 1) находим след плоскости сечения на основании (продолжая $MN$ и проводя прямую через $K$ параллельно ребру); 2) от следа достраиваем сечение, пересекая остальные рёбра.
+
+ +
+
+ 3.1 +
Сечение многогранника
+
+

Сечение многогранника плоскостью $\sigma$ — это многоугольник, образованный пересечением плоскости со всеми гранями многогранника.

+

Его стороны — отрезки пересечения $\sigma$ с гранями; его вершины — точки, где $\sigma$ пересекает рёбра.

+
+
+ +
+ 3.2 +
Метод следов
+
+

Следом называется линия пересечения плоскости сечения с одной из граней (обычно с плоскостью основания).

+

Зная след в плоскости основания и одну точку выше, можно построить пересечения с остальными гранями, продолжая прямые и применяя аксиому A2.

+
+
+ +
+ 3.3 +
Параллельные сечения
+
+

Если плоскость сечения параллельна основанию пирамиды, сечение — многоугольник, подобный основанию (с коэффициентом подобия, зависящим от высоты).

+

В призме параллельное основанию сечение даёт многоугольник, равный основанию.

+
+
+ +
+ 3.4 +
Максимальное число сторон
+
+

Плоскость может пересечь каждую грань не более чем по одному отрезку. Поэтому число сторон сечения не превосходит число граней многогранника.

+
    +
  • Куб (6 граней) → max 6 сторон (правильный шестиугольник через 6 средин рёбер).
  • +
  • Тетраэдр (4 грани) → max 4 стороны.
  • +
  • $n$-угольная призма ($n{+}2$ граней) → max $n{+}2$ сторон.
  • +
+
+
+
+ +
+
+
1
+
Какой многоугольник получится в сечении?
+
0 / 6
+
+
+
+
+
+
+
+ +
+
+
2
+
Максимальное число сторон сечения
+
0 / 5
+
+
+
+
+ + +
+
+
+
+ +
+
+
3
+
Метод следов: верно или нет?
+
0 / 5
+
+
+
+
+
+
+
+ +
+ +
+
@@ -515,14 +629,21 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px}

Финал раздела 1

-
4 интегральных босса · ачивка «Введение в стереометрию пройдено!»
+
4 интегральных босса · ачивка «Введение в стереометрию пройдено»
-
- Откроется после §3 (Волна W2) - Финал содержит 4 босса (элементы тел, аксиомы, сечения, сборная задача) и спецачивку. - До этого момента — побеждай боссов §1 и §2, чтобы заработать XP. + +
+
ФИНАЛЬНОЕ ИСПЫТАНИЕ Победи 4 боссов подряд
+
Каждый босс — на одну тему: элементы тел, аксиомы, сечения, сборная задача. После победы над всеми 4 — получишь ачивку и +100 XP бонусом. Состояние сохраняется автоматически.
+ +
+
+
+
+ + @@ -601,9 +722,14 @@ function refreshMarkBtn(n){ function refreshTabs(){ document.querySelectorAll('.sec-tab').forEach(function(t){ var n = t.getAttribute('data-tab'); - if (n === '1' || n === '2'){ + 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'); } }); } @@ -758,6 +884,160 @@ function buildAxiomVizes(){ })(); } +/* ===== §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$ — правильный шестиугольник. Это классическое сечение куба плоскостью через 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'); @@ -939,9 +1219,184 @@ var BOSS_DEFS = { { 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 = '
' + + '
' + def.title + ' побеждён!
' + + '+' + def.xp + ' XP' + + '
'; + 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 = '
'; + for (var i = 0; i < stage.opts.length; i++){ + optsHtml += ''; + } + optsHtml += '
'; + } else { + optsHtml = '
'; + } + el.innerHTML = '
' + + 'Финал' + + '' + def.title + '' + + '
' + + '
HP босса' + hp + '%
' + + '
' + + '
' + + '
Этап ' + (st.stage+1) + ' / ' + total + '
' + + '
' + stage.q + '
' + + optsHtml + '
'; + + 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 = '
' + + '
★ Раздел 1 пройден! ★
' + + '
Все 4 финальных босса побеждены. Введение в стереометрию — освоено.
' + + '+ 100 XP бонус + ачивка «stereo10_r1_master»' + + '
'; + // ачивка + бонус + 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; @@ -1057,19 +1512,43 @@ function start(){ 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); }); - refreshMarkBtn(1); refreshMarkBtn(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]');