From 3869cebe959b3fbcb549f3dfc1432db715c512ad Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 29 May 2026 15:36:58 +0300 Subject: [PATCH] =?UTF-8?q?feat(geom10=20W9):=20=D0=A4=D0=B8=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=20=D0=A0=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB=D0=B0=204=20+=20?= =?UTF-8?q?=D0=9C=D0=95=D0=93=D0=90-=D0=90=D0=A7=D0=98=D0=92=D0=9A=D0=90?= =?UTF-8?q?=20stereo10=5Fmaster=20(=D0=93=D0=B5=D0=BE=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D1=8F=2010=20=D0=BF=D1=80=D0=BE=D0=B9=D0=B4=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0!)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Финал R4: - Босс 1 Координаты и расстояния (4 этапа, +30 XP) - Босс 2 Векторы (4 этапа, +30 XP) - Босс 3 Скалярное произведение (4 этапа, +35 XP) - Босс 4 Сборная (5 этапов, +55 XP — диагональ куба √3, 2√3; cos углов диагоналей) - Celebration: ачивка stereo10_r4_master + 120 XP бонус ГЛАВНАЯ МЕХАНИКА: если в localStorage есть все 4 ачивки разделов (stereo10_r1_master + stereo10_r2_master + stereo10_r3_master + stereo10_r4_master) автоматически выдаётся МЕГА-АЧИВКА stereo10_master + 200 XP супер-бонус. Если каких-то ачивок нет — celebration показывает список недостающих разделов. sec-nav: финал-таб разблокирован, refreshTabs учитывает {f1..f4}. ИТОГ: Геометрия 10 полностью завершена. - 4 раздела, 14 параграфов - ~140 интерактивов (квизы MC + input + tnp/слайдеры) - 4 финала, 20+ боссов - 5 ачивок: r1..r4 + master - stereo3d.js (~650 строк) для всех 3D-рисунков --- frontend/textbooks/geometry_10_r4.html | 221 ++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 6 deletions(-) diff --git a/frontend/textbooks/geometry_10_r4.html b/frontend/textbooks/geometry_10_r4.html index 2019d9b..a1ad0ac 100644 --- a/frontend/textbooks/geometry_10_r4.html +++ b/frontend/textbooks/geometry_10_r4.html @@ -197,7 +197,7 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px} §12 Векторы §13 a·b §14 Применение - Финал + Финал @@ -761,19 +761,26 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px} -

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

-
4 интегральных босса · ачивка «Геометрия 10 пройдена!» — главная награда курса
+
4 интегральных босса · ачивка «Геометрия 10 пройдена!»
-
- Откроется в Волне W9 - Финальное испытание: 4 босса (координаты/расстояния, векторы, скалярное произведение, сборная) + спецачивка stereo10_master + 120 XP бонус. + +
+
ФИНАЛЬНОЕ ИСПЫТАНИЕ Победи 4 боссов подряд
+
Каждый босс — на одну тему: координаты и расстояния, векторы, скалярное произведение, сборная задача. После победы — ачивка stereo10_r4_master и +120 XP. Если у тебя уже есть все три ачивки stereo10_r1_master, stereo10_r2_master, stereo10_r3_master — получишь главную ачивку курса stereo10_master «Геометрия 10 пройдена!» + 200 XP мега-бонус.
+ +
+
+
+
+ +
@@ -855,6 +862,11 @@ function refreshTabs(){ if (n === '11' || n === '12' || n === '13' || n === '14'){ 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'); } }); } @@ -1266,6 +1278,198 @@ var BOSS_DEFS = { } }; +var FINAL_BOSS_DEFS = { + f1: { + title:'Босс 1 · Координаты и расстояния', + xp:30, + stages:[ + { q:'$A(0;0;0)$, $B(2;2;1)$. $|AB|$ = ?', type:'input', a:'3', explain:'$\\sqrt{4+4+1}=3$.' }, + { q:'Точка $M(0;3;0)$ лежит на:', type:'mc', opts:['Оси $Ox$','Оси $Oy$','Оси $Oz$','В плоскости $Oxz$'], correct:1, explain:'На оси $Oy$.' }, + { q:'Середина $A(2;4;0)$ и $B(0;0;6)$ (формат x;y;z)?', type:'input', a:['1;2;3','1,2,3'], explain:'$(1;2;3)$.' }, + { q:'$|OM|$, если $M(1;2;2)$.', type:'input', a:'3', explain:'$\\sqrt{1+4+4}=3$.' } + ] + }, + f2: { + title:'Босс 2 · Векторы', + xp:30, + stages:[ + { q:'$\\vec{a}=(2;3;-1), \\vec{b}=(1;-2;4)$. $\\vec{a}+\\vec{b}$ (x;y;z)?', type:'input', a:['3;1;3'], explain:'$(3;1;3)$.' }, + { q:'$A(1;2;3), B(4;3;5)$. $\\vec{AB}$ (x;y;z)?', type:'input', a:['3;1;2'], explain:'$(4-1; 3-2; 5-3) = (3;1;2)$.' }, + { q:'$|\\vec{a}|$, если $\\vec{a}=(2;2;1)$.', type:'input', a:'3', explain:'$\\sqrt{4+4+1}=3$.' }, + { q:'$\\vec{a}=(2;4;6), \\vec{b}=(1;2;3)$. Коллинеарны?', type:'mc', opts:['Да','Нет'], correct:0, explain:'$\\vec{a}=2\\vec{b}$ — да.' } + ] + }, + f3: { + title:'Босс 3 · Скалярное произведение', + xp:35, + stages:[ + { q:'$\\vec{a}=(1;-2;3), \\vec{b}=(2;1;1)$. $\\vec{a}\\cdot\\vec{b}$ = ?', type:'input', a:'3', explain:'$2-2+3=3$.' }, + { q:'$\\vec{a}\\cdot\\vec{b}=0$ означает:', type:'mc', opts:['Коллинеарны','Перпендикулярны','Равны'], correct:1, explain:'$\\perp$.' }, + { q:'$\\vec{a}=(1;1;0), \\vec{b}=(1;0;1)$. $\\cos\\varphi$ = ?', type:'input', a:['1/2','0.5'], explain:'$\\cos = \\frac{1}{\\sqrt{2}\\cdot\\sqrt{2}} = \\frac{1}{2}$.' }, + { q:'$\\vec{a}\\cdot\\vec{a}$ при $\\vec{a}=(3;0;4)$ = ?', type:'input', a:'25', explain:'$9+0+16=25 = |\\vec{a}|^2$, $|\\vec{a}|=5$.' } + ] + }, + f4: { + title:'Босс 4 · Сборная', + xp:55, + stages:[ + { q:'Куб с ребром 1 в координатах: $A(0;0;0)$. Длина диагонали $AC_1$?', type:'input', a:['√3','sqrt(3)','sqrt3','1.73','1.732'], explain:'$\\sqrt{3}$.' }, + { q:'Куб (ребро 1). $\\cos$ угла между $\\vec{AB_1}=(1;0;1)$ и $\\vec{AD_1}=(0;1;1)$?', type:'input', a:['1/2','0.5'], explain:'$\\cos = \\frac{0+0+1}{\\sqrt{2}\\cdot\\sqrt{2}} = \\frac{1}{2}$.' }, + { q:'Угол между этими векторами в градусах?', type:'input', a:'60', explain:'$\\cos\\varphi = \\frac{1}{2} \\Rightarrow \\varphi = 60°$.' }, + { q:'Условие $\\vec{a}\\cdot\\vec{b} < 0$ означает, что угол $\\varphi$ …', type:'mc', opts:['Острый','Прямой','Тупой'], correct:2, explain:'Тупой ($\\cos < 0$).' }, + { q:'Куб (ребро 2), $A(0;0;0)$. $|AC_1|$?', type:'input', a:['2√3','2sqrt(3)','2sqrt3','3.46','3.464'], explain:'$\\sqrt{4+4+4}=2\\sqrt{3}$.' } + ] + } +}; + +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 = normalizeAns(inEl.value); + var answers = Array.isArray(stage.a) ? stage.a.map(normalizeAns) : [normalizeAns(stage.a)]; + if (answers.indexOf(v) >= 0){ + 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'; + + // Раздел 4 пройден + var achKey = 'geometry10_achievements'; + var raw = localStorage.getItem(achKey); + var list = []; + try { list = raw ? JSON.parse(raw) : []; } catch(e){} + if (list.indexOf('stereo10_r4_master') < 0){ + list.push('stereo10_r4_master'); + localStorage.setItem(achKey, JSON.stringify(list)); + addXp(120, 'ачивка: Раздел 4 пройден'); + } + + // Проверяем мега-достижение — все 4 ачивки разделов + var hasAll = ['stereo10_r1_master','stereo10_r2_master','stereo10_r3_master','stereo10_r4_master'] + .every(function(a){ return list.indexOf(a) >= 0; }); + + var megaHtml = ''; + if (hasAll && list.indexOf('stereo10_master') < 0){ + list.push('stereo10_master'); + localStorage.setItem(achKey, JSON.stringify(list)); + addXp(200, 'МЕГА-АЧИВКА: Геометрия 10 пройдена!'); + megaHtml = '
' + + '
★★★ ГЕОМЕТРИЯ 10 ПРОЙДЕНА! ★★★
' + + '
Все 4 раздела освоены. Стереометрия — твоя сила. Главная ачивка курса stereo10_master + 200 XP мега-бонус.
' + + '+ 200 XP МЕГА-БОНУС' + + '
'; + } else if (hasAll) { + megaHtml = '
★ Главная ачивка stereo10_master уже получена. Геометрия 10 пройдена!
'; + } else { + var missing = []; + if (list.indexOf('stereo10_r1_master') < 0) missing.push('R1'); + if (list.indexOf('stereo10_r2_master') < 0) missing.push('R2'); + if (list.indexOf('stereo10_r3_master') < 0) missing.push('R3'); + if (missing.length){ + megaHtml = '
До главной ачивки stereo10_master осталось пройти финалы разделов: ' + missing.join(', ') + '.
'; + } + } + + cel.innerHTML = '
' + + '
★ Раздел 4 пройден! ★
' + + '
Все 4 финальных босса побеждены. Координаты и векторы — освоены.
' + + '+ 120 XP бонус + ачивка «stereo10_r4_master»' + + '
' + megaHtml; +} + function renderBoss(num){ var def = BOSS_DEFS[num]; if (!def) return; @@ -1402,6 +1606,11 @@ function start(){ renderBoss(12); renderBoss(13); renderBoss(14); + renderFinalBoss('f1'); + renderFinalBoss('f2'); + renderFinalBoss('f3'); + renderFinalBoss('f4'); + checkFinalComplete(); document.getElementById('mark-11').addEventListener('click', function(){ markRead(11); }); document.getElementById('mark-12').addEventListener('click', function(){ markRead(12); });