From 1c93eb668e2535ae086baae191a409845d5d3f07 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 29 May 2026 09:10:01 +0300 Subject: [PATCH] =?UTF-8?q?feat(alg9=20phase5=20final):=20=D0=B8=D1=82?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=D0=B2=D0=B0=D1=8F=20=D1=88=D0=BF=D0=B0=D1=80?= =?UTF-8?q?=D0=B3=D0=B0=D0=BB=D0=BA=D0=B0=20+=207=20=D0=B1=D0=BE=D1=81?= =?UTF-8?q?=D1=81=D0=BE=D0=B2=20+=20=D0=B0=D1=87=D0=B8=D0=B2=D0=BA=D0=B0?= =?UTF-8?q?=20=C2=AB=D0=9C=D0=B0=D0=B3=D0=B8=D1=81=D1=82=D1=80=20=D0=B0?= =?UTF-8?q?=D0=BB=D0=B3=D0=B5=D0=B1=D1=80=D1=8B=209=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/textbooks/algebra_9_hub.html | 472 +++++++++++++++++++++++++- 1 file changed, 470 insertions(+), 2 deletions(-) diff --git a/frontend/textbooks/algebra_9_hub.html b/frontend/textbooks/algebra_9_hub.html index 6b3fe72..812d301 100644 --- a/frontend/textbooks/algebra_9_hub.html +++ b/frontend/textbooks/algebra_9_hub.html @@ -8,6 +8,9 @@ Алгебра 9 класс — учебник + + + @@ -229,6 +316,103 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px} +
+ + +
+ +
+ + Шпаргалка курса +
+ +
+
+
+ Гл. 1 + Рациональные выражения +
+
    +
  • ОДЗ: $Q(x) \ne 0$
  • +
  • Сокращение: $\dfrac{AC}{BC} = \dfrac{A}{B}$ — только МНОЖИТЕЛЬ
  • +
  • НОЗ — общий знаменатель дробей
  • +
+
+
+
+ Гл. 2 + Функции +
+
    +
  • $y = f(x)$, $D(f)$, $E(f)$
  • +
  • Возр./убыв., нули, экстремумы
  • +
  • Чёт./нечёт.: $f(-x) = \pm f(x)$
  • +
  • Сдвиги: $y = f(x - a) + b$
  • +
+
+
+
+ Гл. 3 + Дробно-рациональные +
+
    +
  • $\dfrac{P}{Q} = 0$: $P = 0,\ Q \ne 0$
  • +
  • Окружность: $(x-a)^2 + (y-b)^2 = R^2$
  • +
  • Метод интервалов: знаки на прямой
  • +
+
+
+
+ Гл. 4 + Прогрессии +
+
    +
  • Арифм.: $a_n = a_1 + (n-1)d$, $S_n = \dfrac{a_1 + a_n}{2} \cdot n$
  • +
  • Геом.: $b_n = b_1 q^{n-1}$, $S_n = \dfrac{b_1(q^n - 1)}{q - 1}$
  • +
  • Беск. убыв.: $S = \dfrac{b_1}{1 - q}$ при $|q| < 1$
  • +
+
+
+ +
+ + 7 интегрированных боссов +
+ +
+
Боссов побеждено: 0 / 7
+
+
+ +
+ +
+
+ +
+
+
Магистр алгебры 9 разблокирован!
+
Вы прошли всю итоговую проверку курса. +50 XP, ачивка получена.
+
+ + К каталогу учебников + + +
+ +
+
+
@@ -320,14 +504,298 @@ function renderProgress(children) { xpBadge.textContent = xp + ' XP'; } - if (totalRead >= TOTAL) { + var mastered = localStorage.getItem(FIN_ACH_KEY) === '1'; + if (totalRead >= TOTAL || mastered) { var strip = document.getElementById('ach-strip'); var sub = document.getElementById('ach-sub'); if (strip) strip.classList.add('lit'); - if (sub) sub.textContent = 'Выполнено! Вы прочитали весь курс алгебры 9 класса.'; + if (sub) { + if (mastered) sub.textContent = 'Выполнено! Вы — Магистр алгебры 9.'; + else sub.textContent = 'Выполнено! Вы прочитали весь курс алгебры 9 класса.'; + } } } +/* COURSE FINAL — lazy bosses */ +var FIN_BOSS_KEY = 'algebra9_course_bosses'; +var FIN_ACH_KEY = 'algebra9_course_master'; + +var FIN_BOSSES = [ + { + n: 1, + title: 'Эльдер Метод Интервалов', + tag: '§ 3 + § 13', + q: 'Решите неравенство $\\dfrac{x^2 - 4}{x + 3} \\le 0$. Сколько целых значений $x \\in [-5;\\,5]$ удовлетворяют ему?', + hint: 'Разложите: $x^2 - 4 = (x-2)(x+2)$. Корни числителя $\\pm 2$ (закрашены), корень знаменателя $-3$ (выколота). Метод интервалов на отрезке $[-5;\\,5]$.', + ans: 7 + }, + { + n: 2, + title: 'Геометр Прогрессий', + tag: '§ 18 + § 7', + q: 'Функция $f(n) = 2n - 1$ задаёт последовательность нечётных чисел. Найдите $S_{10}$ — сумму первых 10 её членов.', + hint: 'Это арифм. прогрессия: $a_1 = 1,\\ a_{10} = 19$. Формула $S_n = \\dfrac{a_1 + a_n}{2}\\cdot n$.', + ans: 100 + }, + { + n: 3, + title: 'Окружность Корней', + tag: '§ 3 + § 10', + q: 'При каком значении $x$ равны функции $y = \\dfrac{x + 2}{x - 3}$ и $y = \\dfrac{6}{x - 3}$?', + hint: 'Знаменатели равны, ОДЗ $x \\ne 3$. Приравняйте числители: $x + 2 = 6$.', + ans: 4 + }, + { + n: 4, + title: 'Сдвиг Параболы', + tag: '§ 9 + § 10', + q: 'Парабола $y = (x - 2)^2 + 3$ пересекается с прямой $y = 4$. Сколько корней у получившегося уравнения?', + hint: '$(x - 2)^2 + 3 = 4 \\Rightarrow (x - 2)^2 = 1$. Это квадратное уравнение.', + ans: 2 + }, + { + n: 5, + title: 'Беск. Убывающая', + tag: '§ 19 + § 1', + q: 'Превратите бесконечную периодическую дробь $0{,}(142857)$ в обыкновенную и введите её знаменатель в несократимом виде.', + hint: 'Числитель — период 142857, знаменатель — 999999. Сократите: $142857 \\cdot 7 = 999999$.', + ans: 7 + }, + { + n: 6, + title: 'Логистика Расстояний', + tag: '§ 12 + § 6', + q: 'Точки $A(0;\\,0)$ и $B(6;\\,8)$ лежат на окружности с центром $C(3;\\,4)$. Чему равен радиус?', + hint: '$R = |CA| = \\sqrt{(3-0)^2 + (4-0)^2}$.', + ans: 5 + }, + { + n: 7, + title: 'Магистр Алгебры', + tag: 'синтез всех глав', + q: 'В арифм. прогрессии $a_1 = 2$, $a_5 = 14$. Найдите знаменатель геом. прогрессии $b_n$, у которой $b_1 = a_1 = 2$, $b_3 = a_5 + 4 = 18$ и $q > 0$.', + hint: 'Из $b_3 = b_1\\cdot q^2$ выразите $q^2$ и возьмите положительный корень.', + ans: 3 + } +]; + +function loadFinBossState(){ + try { return JSON.parse(localStorage.getItem(FIN_BOSS_KEY) || '{}') || {}; } + catch(e) { return {}; } +} +function saveFinBossState(s){ + try { localStorage.setItem(FIN_BOSS_KEY, JSON.stringify(s)); } catch(e){} +} + +function finRenderKatex(root){ + if (typeof window.renderMathInElement !== 'function') return; + try { + window.renderMathInElement(root, { + delimiters: [ + {left: '$$', right: '$$', display: true}, + {left: '$', right: '$', display: false} + ], + throwOnError: false + }); + } catch(e){} +} + +function updateFinBossBar(state){ + var won = 0; + for (var k in state) if (state[k]) won++; + var lab = document.getElementById('fin-boss-lab'); + var fill = document.getElementById('fin-boss-fill'); + if (lab) lab.textContent = 'Боссов побеждено: ' + won + ' / ' + FIN_BOSSES.length; + if (fill) fill.style.width = Math.round(won * 100 / FIN_BOSSES.length) + '%'; + return won; +} + +function maybeUnlockMaster(state){ + if (localStorage.getItem(FIN_ACH_KEY) === '1') return; + var won = 0; + for (var k in state) if (state[k]) won++; + if (won < FIN_BOSSES.length) return; + + localStorage.setItem(FIN_ACH_KEY, '1'); + + /* +50 XP */ + var xp = parseInt(localStorage.getItem('algebra9_xp') || '0', 10) || 0; + localStorage.setItem('algebra9_xp', String(xp + 50)); + + /* trigger global XP system if available */ + try { + if (window.LS && typeof window.LS.addXp === 'function') { + window.LS.addXp(50, 'algebra9-master'); + } else if (typeof window.addXp === 'function') { + window.addXp(50, 'algebra9-master'); + } + } catch(e){} + + /* confetti */ + try { if (typeof window.confetti === 'function') window.confetti({particleCount: 160, spread: 90, origin: {y: .6}}); } catch(e){} + + /* light up ach-strip */ + var strip = document.getElementById('ach-strip'); + var sub = document.getElementById('ach-sub'); + if (strip) strip.classList.add('lit'); + if (sub) sub.textContent = 'Выполнено! Вы — Магистр алгебры 9.'; + + /* show CTA */ + var cta = document.getElementById('final-cta'); + if (cta) cta.classList.add('show'); + + /* refresh XP badge */ + var xpBadge = document.getElementById('hero-xp-badge'); + if (xpBadge) { + var newXp = parseInt(localStorage.getItem('algebra9_xp') || '0', 10) || 0; + xpBadge.style.display = ''; + xpBadge.textContent = newXp + ' XP'; + } +} + +function buildFinBoss(b, state){ + var solvedClass = state[b.n] ? ' solved' : ''; + return '
' + + '
' + + '' + b.tag + '' + + 'Босс ' + b.n + '. ' + b.title + '' + + '
' + + '
' + b.q + '
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + b.hint + '
' + + '
' + (state[b.n] ? 'Победа! +15 XP. Босс уже повержен.' : '') + '
' + + '
'; +} + +function bindFinBoss(b){ + var state = loadFinBossState(); + var goBtn = document.getElementById('fin-boss-' + b.n + '-go'); + var hintBtn = document.getElementById('fin-boss-' + b.n + '-hint'); + var inp = document.getElementById('fin-boss-' + b.n + '-inp'); + var fb = document.getElementById('fin-boss-' + b.n + '-fb'); + var hintTx = document.getElementById('fin-boss-' + b.n + '-hinttxt'); + var card = document.getElementById('fin-boss-' + b.n + '-card'); + if (!goBtn) return; + + if (hintBtn) hintBtn.addEventListener('click', function(){ + if (hintTx) hintTx.classList.toggle('show'); + }); + + if (state[b.n]) return; /* already solved */ + + goBtn.addEventListener('click', function(){ + var v = parseFloat((inp.value || '').replace(',', '.')); + if (isNaN(v)) { + fb.className = 'boss-fb fail'; + fb.textContent = 'Введите число.'; + return; + } + if (Math.abs(v - b.ans) < 1e-9) { + fb.className = 'boss-fb ok'; + fb.textContent = 'Победа! +15 XP. Босс повержен.'; + card.classList.add('solved'); + goBtn.disabled = true; + inp.disabled = true; + + var s = loadFinBossState(); + if (!s[b.n]) { + s[b.n] = true; + saveFinBossState(s); + + /* +15 XP */ + var xp = parseInt(localStorage.getItem('algebra9_xp') || '0', 10) || 0; + localStorage.setItem('algebra9_xp', String(xp + 15)); + try { + if (window.LS && typeof window.LS.addXp === 'function') window.LS.addXp(15, 'fin-boss-' + b.n); + else if (typeof window.addXp === 'function') window.addXp(15, 'fin-boss-' + b.n); + } catch(e){} + + var xpBadge = document.getElementById('hero-xp-badge'); + if (xpBadge) { + var nXp = parseInt(localStorage.getItem('algebra9_xp') || '0', 10) || 0; + xpBadge.style.display = ''; + xpBadge.textContent = nXp + ' XP'; + } + + updateFinBossBar(s); + maybeUnlockMaster(s); + } + } else { + fb.className = 'boss-fb fail'; + fb.textContent = 'Не то. Перепроверь решение и попробуй снова.'; + } + }); + + inp.addEventListener('keydown', function(e){ + if (e.key === 'Enter') { e.preventDefault(); goBtn.click(); } + }); +} + +var FIN_BOSSES_RENDERED = false; +function renderFinBosses(){ + if (FIN_BOSSES_RENDERED) return; + var cont = document.getElementById('fin-bosses-container'); + if (!cont) return; + var state = loadFinBossState(); + var html = ''; + for (var i = 0; i < FIN_BOSSES.length; i++) html += buildFinBoss(FIN_BOSSES[i], state); + cont.innerHTML = html; + for (var j = 0; j < FIN_BOSSES.length; j++) bindFinBoss(FIN_BOSSES[j]); + + var wrap = document.getElementById('course-final'); + finRenderKatex(wrap); + + updateFinBossBar(state); + + /* if already mastered: show CTA */ + if (localStorage.getItem(FIN_ACH_KEY) === '1') { + var cta = document.getElementById('final-cta'); + if (cta) cta.classList.add('show'); + var strip = document.getElementById('ach-strip'); + var sub = document.getElementById('ach-sub'); + if (strip) strip.classList.add('lit'); + if (sub) sub.textContent = 'Выполнено! Вы — Магистр алгебры 9.'; + } + + FIN_BOSSES_RENDERED = true; +} + +(function bindFinalAccordion(){ + var head = document.getElementById('final-head'); + var wrap = document.getElementById('course-final'); + if (!head || !wrap) return; + + function toggle(){ + var willOpen = !wrap.classList.contains('open'); + wrap.classList.toggle('open'); + head.setAttribute('aria-expanded', willOpen ? 'true' : 'false'); + if (willOpen) { + renderFinBosses(); + /* always re-render cheat-sheet KaTeX on first open */ + finRenderKatex(wrap); + } + } + + head.addEventListener('click', toggle); + head.addEventListener('keydown', function(e){ + if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); } + }); +})(); + +/* sync ach-strip + CTA on load if already mastered */ +(function syncMasterOnLoad(){ + if (localStorage.getItem(FIN_ACH_KEY) === '1') { + var strip = document.getElementById('ach-strip'); + var sub = document.getElementById('ach-sub'); + if (strip) strip.classList.add('lit'); + if (sub) sub.textContent = 'Выполнено! Вы — Магистр алгебры 9.'; + } +})(); + function loadProgress() { if (typeof window.LS === 'undefined' || typeof window.LS.api !== 'function') { renderProgress([]);