From 34dd19739076cd6960b9954714228e7a01006a96 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 29 May 2026 08:29:18 +0300 Subject: [PATCH] =?UTF-8?q?feat(alg9=20ch2=20final):=20=D0=A4=D0=B8=D0=BD?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=93=D0=BB=D0=B0=D0=B2=D1=8B=202=20=C2=AB?= =?UTF-8?q?=D0=A4=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=C2=BB=20(5=20=D0=B1?= =?UTF-8?q?=D0=BE=D1=81=D1=81=D0=BE=D0=B2=20+=20=D0=B0=D1=87=D0=B8=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/textbooks/algebra_9_ch2.html | 219 +++++++++++++++++++++++--- 1 file changed, 201 insertions(+), 18 deletions(-) diff --git a/frontend/textbooks/algebra_9_ch2.html b/frontend/textbooks/algebra_9_ch2.html index 335fbec..a264694 100644 --- a/frontend/textbooks/algebra_9_ch2.html +++ b/frontend/textbooks/algebra_9_ch2.html @@ -241,7 +241,7 @@ a{color:inherit;text-decoration:none}
§ 7

Свойства функции

§ 8

Чётные и нечётные функции

§ 9

Сдвиги графиков

-
Финал главы

Итоги. 4 боссов главы 2

+
Финал главы

Итоги. 5 боссов главы 2

@@ -353,7 +353,7 @@ const PARAS = [ { id:'p7', num:'§ 7', name:'Свойства функции', sub:'нули, монотонность, экстр.' }, { id:'p8', num:'§ 8', name:'Чётные и нечётные функции', sub:'симметрия графика' }, { id:'p9', num:'§ 9', name:'Сдвиги графиков', sub:'$y=f(x)+b$, $y=f(x \pm a)$' }, - { id:'final2', num:'★', name:'Финал главы', sub:'Итоги · 4 боссов', final:true } + { id:'final2', num:'★', name:'Финал главы', sub:'Итоги · 5 боссов', final:true } ]; function buildParaSelector(){ @@ -388,7 +388,7 @@ const SIDEBARS = { p7:{title:'Шпаргалка \xA77',rows:[['Нуль','$f(x_0) = 0$'],['Возрастает','при бо́льшем $x$ — бо́льшее $f(x)$'],['Убывает','при бо́льшем $x$ — меньшее $f(x)$'],['$y_{max}$','наиб. значение на промежутке']]}, p8:{title:'Шпаргалка \xA78',rows:[['Чётная','$f(-x) = f(x)$ — симм. отн. $Oy$'],['Нечётная','$f(-x) = -f(x)$ — симм. отн. $O$'],['Ни та, ни др.','общий случай']]}, p9:{title:'Шпаргалка \xA79',rows:[['$f(x) + b$','сдвиг вверх на $b$'],['$f(x) - b$','сдвиг вниз на $b$'],['$f(x - a)$','сдвиг вправо на $a$'],['$f(x + a)$','сдвиг влево на $a$']]}, - final2:{title:'Финал главы',rows:[['§§6–9','теория главы 2'],['Боссов','4'],['Награда','+100 XP']]} + final2:{title:'Финал главы',rows:[['§§6–9','теория главы 2'],['Боссов','5'],['Награда','+100 XP']]} }; const TIPS=[ @@ -396,7 +396,7 @@ const TIPS=[ {sec:'p7',html:'Нули функции — это решения уравнения $f(x) = 0$.'}, {sec:'p8',html:'Чётная функция: $f(-x) = f(x)$. Нечётная: $f(-x) = -f(x)$.'}, {sec:'p9',html:'$y = f(x) + b$ — сдвиг по $Oy$. $y = f(x - a)$ — сдвиг по $Ox$ вправо на $a$.'}, - {sec:'final2',html:'4 босса главы 2.'} + {sec:'final2',html:'5 боссов главы 2.'} ]; function buildSidebar(id){ @@ -1802,21 +1802,204 @@ function buildP9(){ } function buildFinal2(){ - const root = document.getElementById('final2-body'); - root.innerHTML = ` -
-
- ${ICONS.theory} - В разработке - + const box = document.getElementById('final2-body'); + let html = ''; + + /* Часть А — Шпаргалка главы (4 mini-карточки) */ + html += `
+
+ ${ICONS.theory} + Шпаргалка главы 2 + Итог +
+
+

Все ключевые правила главы — в одном месте. Просмотри перед боссами!

+
+
+
§ 6 · Функция
+
$y = f(x)$. $D(f)$ — область определения, $E(f)$ — область значений. 3 способа: формула, таблица, график.
+
+
+
§ 7 · Свойства
+
Возрастает / убывает; нули — $f(x) = 0$; знакопостоянство; экстремумы ($y_{max}$, $y_{min}$).
+
+
+
§ 8 · Чётность
+
Чётная: $f(-x) = f(x)$ — симм. отн. $Oy$. Нечётная: $f(-x) = -f(x)$ — симм. отн. $O$.
+
+
+
§ 9 · Сдвиги
+
$y = f(x - a) + b$ — вправо на $a$, вверх на $b$. Минус в скобке — вправо!
+
-
-

Содержание финала главы Финал главы — в разработке будет добавлено в следующих обновлениях.

-

Боссы и итоговые задания будут добавлены в Phase 1.

-
-
` + secNav('p9', null) + readButton('final2'); - renderMath(root); - wireReadBtn('final2'); +
+
`; + + /* Часть Б — 5 боссов */ + html += `
+
+ ${ICONS.rule} + Боссы главы 2 + 5 +
+
+

5 интегрированных задач. Каждая комбинирует несколько тем главы 2. За каждого побеждённого босса — +10 XP. Победишь всех — +50 XP бонус и ачивка «Магистр функций»!

+
+
`; + + html += '
'; + + html += `
+
Прогресс по боссам
+
0 / 5 боссов побеждено
+
+
+
+ +
`; + + html += secNav('p9', null); + + box.innerHTML = html; + renderMath(box); + + /* Боссы */ + const BOSSES = [ + { + n:1, color:'#10b981', + title:'Грифон Областей', + tag:'§ 6 + § 7', + q:'Дана функция $f(x) = \\dfrac{1}{x - 4}$. Сколько целых значений $x$ из промежутка $[1;\\ 7]$ принадлежат $D(f)$?', + ans:6, + hint:'$D(f):\\ x \\ne 4$. На $[1;7]$ целые: $1, 2, 3, 4, 5, 6, 7$ — исключаем $4$. Остаётся 6 значений.' + }, + { + n:2, color:'#0891b2', + title:'Феникс Симметрии', + tag:'§ 7 + § 8', + q:'Функция $f(x) = x^3 - 3x$. Найди $f(2)$, затем $f(-2)$. Введи значение $f(-2)$.', + ans:-2, + hint:'$f(2) = 8 - 6 = 2$. Функция нечётная: $f(-x) = -f(x)$. Значит $f(-2) = -f(2) = -2$.' + }, + { + n:3, color:'#7c3aed', + title:'Кракен Сдвигов', + tag:'§ 9 + § 6', + q:'График $y = (x - 3)^2 - 5$ — парабола. Найди её вершину $(x_0;\\ y_0)$ и введи сумму $x_0 + y_0$.', + ans:-2, + hint:'$y = (x - 3)^2 - 5$ — сдвиг параболы $y=x^2$ вправо на $3$ и вниз на $5$. Вершина $(3;\\ -5)$. Сумма: $3 + (-5) = -2$.' + }, + { + n:4, color:'#dc2626', + title:'Минотавр Свойств', + tag:'§ 7 + § 9', + q:'Сколько нулей у функции $y = (x + 2)^2 - 1$?', + ans:2, + hint:'$(x+2)^2 - 1 = 0 \\Rightarrow (x+2)^2 = 1 \\Rightarrow x + 2 = \\pm 1 \\Rightarrow x = -1$ или $x = -3$. 2 нуля.' + }, + { + n:5, color:'#f59e0b', + title:'Мастер Функций', + tag:'§§ 6–9 — синтез', + q:'Дана $f(x) = (x + 1)^2 - 4$. Найди: а) $f(0)$; б) оба нуля функции. Введи сумму всех трёх чисел: $f(0) + x_1 + x_2$.', + ans:-5, + hint:'$f(0) = 1 - 4 = -3$. Нули: $(x+1)^2 = 4 \\Rightarrow x = 1$ или $x = -3$. Сумма: $-3 + 1 + (-3) = -5$.' + }, + ]; + + const cont = document.getElementById('ch2-bosses-container'); + const STATE_KEY = 'algebra9_ch2_bosses'; + const BOSS_STATE = (function(){ + try{ const s = localStorage.getItem(STATE_KEY); if(s) return JSON.parse(s); }catch(e){} + return BOSSES.map(()=>({defeated:false})); + })(); + function saveBosses(){ try{ localStorage.setItem(STATE_KEY, JSON.stringify(BOSS_STATE)); }catch(e){} } + + cont.innerHTML = BOSSES.map((b, idx)=>{ + return '
' + +'
' + +'' + +'
Босс '+b.n+': '+b.title+'
' + +'
'+b.tag+'
' + +'
' + +'
'+b.q+'
' + +'
' + +'ответ =' + +'' + +'' + +'' + +'
' + +'' + +'
'; + }).join(''); + renderMath(cont); + + function refreshOverall(){ + const won = BOSS_STATE.filter(s => s.defeated).length; + const txt = document.getElementById('ch2-boss-overall'); + const fill = document.getElementById('ch2-boss-overall-fill'); + if(txt) txt.textContent = won + ' / ' + BOSSES.length + ' боссов побеждено'; + if(fill) fill.style.width = (won * 100 / BOSSES.length) + '%'; + if(won >= BOSSES.length){ + const reward = document.getElementById('ch2-final-reward'); + if(reward && reward.style.display === 'none'){ + reward.style.display = 'block'; + if(!STATE.achievements.has('ch2_done')){ + achievement('ch2_done','Магистр функций'); + addXp(50, 'ch2-bonus'); + bumpProgress('final2', 30); + if(window.confetti){ try{ confetti(); }catch(e){} } + } + } + } + } + + BOSSES.forEach((b, idx)=>{ + const card = document.getElementById('boss2-'+b.n+'-card'); + const goBtn = document.getElementById('boss2-'+b.n+'-go'); + const hintBtn = document.getElementById('boss2-'+b.n+'-hint'); + const ansInp = document.getElementById('boss2-'+b.n+'-ans'); + if(BOSS_STATE[idx].defeated){ + card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))'; + goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.textContent = '✓ Повержен'; + ansInp.disabled = true; + } + goBtn.addEventListener('click', ()=>{ + if(BOSS_STATE[idx].defeated) return; + const fb = document.getElementById('boss2-'+b.n+'-fb'); + const val = parseInt(ansInp.value, 10); + if(isNaN(val)){ feedback(fb, false, '✗ Введи целое число.'); return; } + if(val === b.ans){ + BOSS_STATE[idx].defeated = true; saveBosses(); + feedback(fb, true, '✓ Босс '+b.n+' повержен! +10 XP. '+b.hint); + addXp(10, 'boss-ch2-'+b.n); + bumpProgress('final2', 18); + goBtn.disabled = true; goBtn.style.opacity = .55; goBtn.textContent = '✓ Повержен'; + ansInp.disabled = true; + card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))'; + refreshOverall(); + } else { + feedback(fb, false, '✗ Промах. Попробуй ещё. Подсказка доступна.'); + } + }); + hintBtn.addEventListener('click', ()=>{ + const fb = document.getElementById('boss2-'+b.n+'-fb'); + fb.className = 'feedback ok'; + fb.innerHTML = 'Подсказка: '+b.hint; + fb.style.display = 'block'; + fb.style.background = 'var(--warn-bg)'; + fb.style.color = '#92400e'; + fb.style.borderLeftColor = 'var(--warn)'; + renderMath(fb); + }); + ansInp.addEventListener('keydown', e=>{ if(e.key === 'Enter') goBtn.click(); }); + }); + + refreshOverall(); } /* ===== Search ===== */