From 7f045737d3a57b26ec594cb6bef2be3624ce07fc Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 29 May 2026 15:26:04 +0300 Subject: [PATCH] =?UTF-8?q?feat(geom10=20W7):=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=203=20?= =?UTF-8?q?=E2=80=94=205=20=D0=B1=D0=BE=D1=81=D1=81=D0=BE=D0=B2=20+=20?= =?UTF-8?q?=D0=B0=D1=87=D0=B8=D0=B2=D0=BA=D0=B0=20stereo10=5Fr3=5Fmaster?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Босс 1 Прямая ⊥ плоскость (4 этапа, +30 XP) - Босс 2 Расстояния (4 этапа, +30 XP) - Босс 3 Угол + ТТП (4 этапа, +35 XP, поддержка √2/2, 1/√3 и т.п.) - Босс 4 ⊥-плоскости (4 этапа, +30 XP) - Босс 5 Сборная (5 этапов, +45 XP — диагональ куба √3, sin угла 1/√3) - Celebration: ачивка stereo10_r3_master + 130 XP бонус - sec-nav: финал-таб разблокирован, refreshTabs учитывает {f1..f5} - Состояние: STATE.bosses{f1..f5} + geometry10_achievements в localStorage --- frontend/textbooks/geometry_10_r3.html | 211 ++++++++++++++++++++++++- 1 file changed, 206 insertions(+), 5 deletions(-) diff --git a/frontend/textbooks/geometry_10_r3.html b/frontend/textbooks/geometry_10_r3.html index 0c916b1..6038eac 100644 --- a/frontend/textbooks/geometry_10_r3.html +++ b/frontend/textbooks/geometry_10_r3.html @@ -194,7 +194,7 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px} §8 Расстояния §9 Угол §10 Пл-сти ⊥ - Финал + Финал @@ -731,7 +731,6 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px} -
@@ -740,10 +739,19 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 80px}
5 интегральных боссов · ачивка «Перпендикулярность освоена»
-
- Откроется в Волне W7 - Финал содержит 5 боссов и спецачивку stereo10_r3_master. + +
+
ФИНАЛЬНОЕ ИСПЫТАНИЕ Победи 5 боссов подряд
+
Каждый босс — на одну тему: прямая⊥плоскость, расстояния, угол наклонной + ТТП, ⊥-плоскости, сборная задача. После победы над всеми — ачивка stereo10_r3_master и +130 XP бонусом.
+ +
+
+
+
+
+ +
@@ -825,6 +833,11 @@ function refreshTabs(){ if (n === '7' || n === '8' || n === '9' || n === '10'){ 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','f5'].every(function(k){ + return STATE.bosses && STATE.bosses[k] && STATE.bosses[k].defeated; + }); + if (allBeat) t.classList.add('read'); } }); } @@ -1329,6 +1342,188 @@ var BOSS_DEFS = { } }; +var FINAL_BOSS_DEFS = { + f1: { + title:'Босс 1 · Прямая ⊥ плоскость', + xp:30, + stages:[ + { q:'Признак $l \\perp \\alpha$: $l$ перпендикулярна двум $?$ прямым в $\\alpha$.', type:'mc', opts:['Параллельным','Пересекающимся','Произвольным'], correct:1, explain:'Двум ПЕРЕСЕКАЮЩИМСЯ прямым.' }, + { q:'Через точку проходит сколько прямых, перпендикулярных данной плоскости?', type:'input', a:'1', explain:'Единственная.' }, + { q:'Если $l \\perp \\alpha$ и $a \\subset \\alpha$, то $l$ и $a$…', type:'mc', opts:['Параллельны','Перпендикулярны','Скрещиваются'], correct:1, explain:'$l$ перпендикулярна любой прямой плоскости.' }, + { q:'Куб: ребро $DD_1$ перпендикулярно плоскости $ABCD$?', type:'mc', opts:['Да','Нет','Зависит'], correct:0, explain:'Все боковые рёбра ⊥ основанию.' } + ] + }, + f2: { + title:'Босс 2 · Расстояния', + xp:30, + stages:[ + { q:'Куб с ребром $3$. Расстояние от $A$ до плоскости $A_1B_1C_1D_1$?', type:'input', a:'3', explain:'Длина $AA_1 = 3$.' }, + { q:'Куб с ребром $1$. Расстояние между скрещ. рёбрами $AB$ и $D_1C_1$?', type:'input', a:['√2','sqrt(2)','sqrt2','1.41','1.414'], explain:'Диагональ грани $\\sqrt{2}$.' }, + { q:'Расстояние между скрещ. прямыми реализуется на каком отрезке?', type:'mc', opts:['Любом','Общем перпендикуляре','Биссектрисе','Касательной'], correct:1, explain:'Общий перпендикуляр.' }, + { q:'Перпендикуляр из точки на плоскость … любой наклонной из той же точки.', type:'mc', opts:['Длиннее','Короче','Равен'], correct:1, explain:'Короче (кратчайший отрезок).' } + ] + }, + f3: { + title:'Босс 3 · Угол + ТТП', + xp:35, + stages:[ + { q:'Что такое проекция наклонной $AB$ на плоскость $\\alpha$ (где $AH \\perp \\alpha$, $H \\in \\alpha$)?', type:'mc', opts:['$AH$','$HB$','$AB$'], correct:1, explain:'Проекция — отрезок $HB$.' }, + { q:'Угол между прямой и плоскостью — это угол между прямой и…', type:'mc', opts:['Перпендикуляром','Проекцией','Любой прямой'], correct:1, explain:'Наклонная и её проекция.' }, + { q:'ТТП: $AH \\perp \\alpha, BC \\subset \\alpha, HB \\perp BC$. Что верно?', type:'mc', opts:['$AB \\perp BC$','$AB \\parallel BC$','Ничего'], correct:0, explain:'$AB \\perp BC$.' }, + { q:'Куб (ребро 1): $\\tg$ угла между диагональю $AC_1$ и плоскостью $ABCD$?', type:'input', a:['1/√2','1/sqrt(2)','√2/2','sqrt(2)/2','0.707'], explain:'$\\tg \\varphi = \\frac{1}{\\sqrt{2}}$.' } + ] + }, + f4: { + title:'Босс 4 · ⊥-плоскости', + xp:30, + stages:[ + { q:'Двугранный угол — это…', type:'mc', opts:['Угол наклонной','2 полуплоскости с общим ребром','Угол прямых'], correct:1, explain:'Полуплоскости + общее ребро.' }, + { q:'Признак $\\alpha \\perp \\beta$: $\\alpha$ содержит прямую, $?$ к $\\beta$.', type:'mc', opts:['Параллельную','Перпендикулярную','Произвольную'], correct:1, explain:'Перпендикулярную $\\beta$.' }, + { q:'Сколько граней куба перпендикулярно одной заданной грани?', type:'input', a:'4', explain:'4 смежные.' }, + { q:'Линейный угол двугранного угла зависит от выбора точки на ребре?', type:'mc', opts:['Да','Нет'], correct:1, explain:'Не зависит.' } + ] + }, + f5: { + title:'Босс 5 · Сборная', + xp:45, + stages:[ + { q:'Куб с ребром $1$. Расстояние от $A$ до $C_1$? (длина диагонали куба)', type:'input', a:['√3','sqrt(3)','sqrt3','1.73','1.732'], explain:'Диагональ куба $= a\\sqrt{3}$.' }, + { q:'Куб (ребро 1): $\\sin$ угла между $AC_1$ и плоскостью $ABCD$?', type:'input', a:['1/√3','1/sqrt(3)','√3/3','sqrt(3)/3','0.577'], explain:'$\\sin \\varphi = \\frac{AA_1}{AC_1} = \\frac{1}{\\sqrt{3}}$.' }, + { q:'Если $l_1 \\perp \\alpha$ и $l_2 \\perp \\alpha$, то $l_1$ и $l_2$ — …', type:'mc', opts:['$\\parallel$','$\\perp$','Скрещиваются'], correct:0, explain:'Параллельны.' }, + { q:'В пирамиде высота $SO \\perp$ основание. Применяем ТТП: $OB \\perp BC \\Rightarrow$ ?', type:'mc', opts:['$SB \\perp BC$','$SB \\parallel BC$','Ничего'], correct:0, explain:'По ТТП: $SB \\perp BC$.' }, + { q:'Куб: диагональная плоскость $BDD_1B_1$ и грань $ABCD$ — это…', type:'mc', opts:['Параллельны','Перпендикулярны','Под $45°$'], correct:1, explain:'$BB_1 \\subset BDD_1B_1$ и $BB_1 \\perp ABCD$ ⇒ перпендикулярны.' } + ] + } +}; + +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 + '
'; + + function normalizeAns(s){ + return String(s||'').toLowerCase() + .replace(/\s+/g,'') + .replace(/°/g,'') + .replace(/sqrt/g,'√') + .replace(/корень/g,'√') + .replace(/,/g,'.'); + } + + 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','f5'].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 = '
' + + '
★ Раздел 3 пройден! ★
' + + '
Все 5 финальных боссов побеждены. Перпендикулярность — освоена.
' + + '+ 130 XP бонус + ачивка «stereo10_r3_master»' + + '
'; + var achKey = 'geometry10_achievements'; + var raw = localStorage.getItem(achKey); + var list = []; + try { list = raw ? JSON.parse(raw) : []; } catch(e){} + if (list.indexOf('stereo10_r3_master') < 0){ + list.push('stereo10_r3_master'); + localStorage.setItem(achKey, JSON.stringify(list)); + addXp(130, 'ачивка: Перпендикулярность освоена'); + } +} + function renderBoss(num){ var def = BOSS_DEFS[num]; if (!def) return; @@ -1476,6 +1671,12 @@ function start(){ renderBoss(8); renderBoss(9); renderBoss(10); + renderFinalBoss('f1'); + renderFinalBoss('f2'); + renderFinalBoss('f3'); + renderFinalBoss('f4'); + renderFinalBoss('f5'); + checkFinalComplete(); document.getElementById('mark-7').addEventListener('click', function(){ markRead(7); }); document.getElementById('mark-8').addEventListener('click', function(){ markRead(8); });