From e2f0bb61afefdd5f12122b508df056fa874cb895 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 29 May 2026 12:26:14 +0300 Subject: [PATCH] =?UTF-8?q?feat(alg11=20ch3=20wave4=20+=20final):=20=C2=A7?= =?UTF-8?q?10=20=C2=AB=D0=9B=D0=BE=D0=B3=D0=B0=D1=80=D0=B8=D1=84=D0=BC?= =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B5=20=D0=BD=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B5=D0=BD=D1=81=D1=82=D0=B2=D0=B0=C2=BB=20+=20?= =?UTF-8?q?=D0=A4=D0=B8=D0=BD=D0=B0=D0=BB=20=D0=93=D0=BB=D0=B0=D0=B2=D1=8B?= =?UTF-8?q?=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/textbooks/algebra_11_ch3.html | 771 ++++++++++++++++++++++++- 1 file changed, 757 insertions(+), 14 deletions(-) diff --git a/frontend/textbooks/algebra_11_ch3.html b/frontend/textbooks/algebra_11_ch3.html index 127d2bc..819395b 100644 --- a/frontend/textbooks/algebra_11_ch3.html +++ b/frontend/textbooks/algebra_11_ch3.html @@ -1952,31 +1952,774 @@ function buildP9(){ function buildP10(){ const box = document.getElementById('p10-body'); let html = ''; - html += makeCard('theory', 'В разработке', '10.0', ` -

Содержание параграфа Логарифмические неравенства будет добавлено в Phase 1+.

-

Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.

-

Ключевая формула: $\log_a f > b$

- `); - html += secNavFor('p10'); + + /* === ТЕОРИЯ === */ + + html += makeCard('theory', 'Основное правило и ОДЗ', '10.1', ` +

Логарифмическим неравенством называется неравенство, в котором переменная содержится под знаком логарифма. Простейший вид:

+

$\\log_a f(x) > \\log_a g(x)$  (или $<$, $\\ge$, $\\le$).

+

Здесь $a > 0$, $a \\ne 1$. Подход к решению опирается на монотонность логарифмической функции (см. §8):

+

+ $\\log_a f(x) > \\log_a g(x) \\;\\Leftrightarrow\\; \\begin{cases} f(x) > g(x), & \\text{если } a > 1 \\\\\\\\ f(x) < g(x), & \\text{если } 0 < a < 1 \\end{cases}$ +

+

Кроме того всегда требуем положительности выражений под логарифмами (ОДЗ):

+

+ $\\begin{cases} f(x) > 0 \\\\\\\\ g(x) > 0 \\end{cases}$ +

+

Запомни:

+ +
Почему знак меняется при $0 < a < 1$?
+

Функция $y = \\log_a x$ при $0 < a < 1$ строго убывает: чем больше $x$, тем меньше $y$.

+

Поэтому неравенство $\\log_a f > \\log_a g$ означает $f < g$: чтобы $\\log$ был больше, аргумент должен быть меньше.

+
`); + + html += makeCard('rule', 'Алгоритм решения', '10.2', ` +

Шаги для решения неравенства $\\log_a f(x) \\gtrless \\log_a g(x)$:

+
    +
  1. Записать ОДЗ: $f(x) > 0$ и $g(x) > 0$.
  2. +
  3. Привести обе части к одному основанию (если нужно).
  4. +
  5. Использовать правило монотонности: при $a > 1$ сохранить знак, при $0 < a < 1$ — изменить.
  6. +
  7. Решить полученное алгебраическое неравенство.
  8. +
  9. Пересечь ответ с ОДЗ — это и есть финальное решение.
  10. +
+
+

Пример 1. $\\log_2 (x - 1) > 3$.

+

ОДЗ: $x - 1 > 0 \\Rightarrow x > 1$.

+

Перепишем $3 = \\log_2 8$: $\\log_2 (x - 1) > \\log_2 8$. $\\;a = 2 > 1$ — знак сохраняется:

+

$x - 1 > 8 \\Rightarrow x > 9$.

+

Пересечение с ОДЗ ($x > 1$): $x > 9$.

+

Ответ: $x \\in (9; +\\infty)$.

+
+

Пример 2. $\\log_{1/3} (x - 2) > -2$.

+

ОДЗ: $x - 2 > 0 \\Rightarrow x > 2$.

+

Перепишем $-2 = \\log_{1/3} 9$ (т.к. $(1/3)^{-2} = 9$): $\\log_{1/3} (x - 2) > \\log_{1/3} 9$. $\\;a = 1/3 < 1$ — знак меняется:

+

$x - 2 < 9 \\Rightarrow x < 11$.

+

Пересечение с ОДЗ: $2 < x < 11$.

+

Ответ: $x \\in (2; 11)$.

`); + + html += makeCard('example', 'Замена переменной и графический метод', '10.3', ` +

Метод замены. При наличии в неравенстве $\\log_a x$ и $\\log_a^2 x$ выполняют подстановку $t = \\log_a x$ — и получают квадратное неравенство относительно $t$.

+

Пример. $\\log_2^2 x - 3 \\log_2 x + 2 \\le 0$.

+

ОДЗ: $x > 0$. Замена $t = \\log_2 x$: $t^2 - 3t + 2 \\le 0$.

+

Корни уравнения $t^2 - 3t + 2 = 0$: $t_1 = 1$, $t_2 = 2$. Парабола ветвями вверх $\\le 0$ между корнями: $t \\in [1; 2]$.

+

Обратно: $1 \\le \\log_2 x \\le 2 \\Leftrightarrow 2^1 \\le x \\le 2^2 \\Leftrightarrow 2 \\le x \\le 4$.

+

Ответ: $x \\in [2; 4]$.

+
+

Графический метод. Если неравенство нельзя свести к одному основанию или замене — используем графики. Строим $y = \\log_a f(x)$ и $y = \\log_a g(x)$ (или константу) на одной координатной плоскости и смотрим, где один график выше другого.

+

Когда применять? Когда $f$ и $g$ имеют разную природу (например, степенная и логарифмическая). Метод не даёт точный ответ, но позволяет понять число и расположение решений.

+

Пример. $\\log_2 x < 3 - x$. Строим $y = \\log_2 x$ (растёт) и $y = 3 - x$ (убывает). Точка пересечения примерно при $x \\approx 2$. При $x < 2$ кривая логарифма ниже прямой — это и есть решение. Уточнение: проверяем $x = 2$: $\\log_2 2 = 1$, $3 - 2 = 1$. Значит ответ $x \\in (0; 2)$.

`); + + /* === ИНТЕРАКТИВЫ === */ + + /* IV1 — пошаговый решатель неравенств с числовой прямой */ + html += `
+
ИНТЕРАКТИВ 1
Решатель логарифмических неравенств
+
Выбери задачу ползунком и нажимай «Следующий шаг ▶». Особое внимание — ОДЗ и правилу монотонности. После шага «Ответ» появится визуализация на числовой прямой. Просмотри все 5 задач — получишь XP.
+
+ +
+
+
+
+
+ + + +
+
`; + + /* IV2 — калькулятор log_a (kx + b) ⋚ c */ + html += `
+
ИНТЕРАКТИВ 2
Калькулятор $\\log_a (kx + b) \\gtrless c$
+
Введи основание $a$, коэффициенты $k$, $b$, правую часть $c$ и выбери знак — калькулятор решит неравенство с учётом монотонности и ОДЗ, покажет числовую прямую.
+
+ $a$ = + + $k$ = + + $b$ = + + + $c$ = + + +
+
+ Примеры: + + + + +
+
+
+ +
`; + + /* IV3 — знак сохраняется или меняется? */ + html += `
+
ИНТЕРАКТИВ 3
Знак меняется или сохраняется?
+
Дано логарифмическое неравенство. Определи: при переходе к выражениям под логарифмом знак сохраняется ($a > 1$) или меняется ($0 < a < 1$)? 8 заданий.
+
Задача 1 / 8Очки: 0 / 8
+
+
+ +
+
`; + + /* IV4 — тренажёр неравенств */ + html += `
+
ИНТЕРАКТИВ 4
Тренажёр неравенств
+
Реши неравенство и введи число — указанную границу интервала ответа. 6 задач.
+
Задача 1 / 6Очки: 0 / 6
+
+
+ ответ = + + + +
+ +
`; + + html += secNav('p9', 'final3'); html += readButton('p10'); + box.innerHTML = html; renderMath(box); + + /* Хелпер: рисует числовую прямую с интервалом */ + function drawAxis(lo, hi, segs){ + // segs: [{a, b, closedA, closedB, color}] + // a/b могут быть -Infinity / +Infinity + const W = 480, H = 80; + const padL = 40, padR = 40; + const ax = padL, bx = W - padR; + const y0 = 46; + const range = hi - lo; + function xpos(v){ + if(v === -Infinity) return ax; + if(v === +Infinity) return bx; + return ax + (v - lo) / range * (bx - ax); + } + let svg = ''; + // ось + svg += ''; + // стрелки + svg += ''; + svg += ''; + // деления + const ticks = []; + for(let v = Math.ceil(lo); v <= Math.floor(hi); v++) ticks.push(v); + ticks.forEach(v => { + const x = xpos(v); + svg += ''; + svg += ''+v+''; + }); + // интервалы + segs.forEach(s => { + const x1 = xpos(s.a), x2 = xpos(s.b); + const color = s.color || '#7c3aed'; + svg += ''; + // концы + if(s.a !== -Infinity){ + if(s.closedA) svg += ''; + else svg += ''; + } + if(s.b !== +Infinity){ + if(s.closedB) svg += ''; + else svg += ''; + } + }); + svg += ''; + return svg; + } + + /* === IV1 — пошаговый решатель неравенств === */ + (function(){ + const TASKS = [ + { + q: '$\\log_2 (x - 1) > 3$', + steps: [ + 'ОДЗ: $x - 1 > 0 \\Rightarrow x > 1$.', + 'Переписываем правую часть: $3 = \\log_2 2^3 = \\log_2 8$. Неравенство: $\\log_2 (x - 1) > \\log_2 8$.', + 'Учитываем монотонность: $a = 2 > 1$, знак сохраняется: $x - 1 > 8$.', + 'Решаем: $x > 9$.', + 'Пересечение с ОДЗ ($x > 1$): $x > 9$.', + 'Ответ: $x \\in (9; +\\infty)$.' + ], + axis: { lo: 0, hi: 14, segs: [{a:9, b:+Infinity, closedA:false, color:'#7c3aed'}] } + }, + { + q: '$\\log_{1/3} (x - 2) > -2$', + steps: [ + 'ОДЗ: $x - 2 > 0 \\Rightarrow x > 2$.', + 'Переписываем: $-2 = \\log_{1/3} (1/3)^{-2} = \\log_{1/3} 9$. Неравенство: $\\log_{1/3} (x - 2) > \\log_{1/3} 9$.', + 'Учитываем монотонность: $a = 1/3 < 1$, знак меняется: $x - 2 < 9$.', + 'Решаем: $x < 11$.', + 'Пересечение с ОДЗ ($x > 2$): $2 < x < 11$.', + 'Ответ: $x \\in (2; 11)$.' + ], + axis: { lo: 0, hi: 14, segs: [{a:2, b:11, closedA:false, closedB:false, color:'#7c3aed'}] } + }, + { + q: '$\\log_5 (2x + 1) < 1$', + steps: [ + 'ОДЗ: $2x + 1 > 0 \\Rightarrow x > -\\dfrac{1}{2}$.', + 'Переписываем: $1 = \\log_5 5$. Неравенство: $\\log_5 (2x + 1) < \\log_5 5$.', + 'Учитываем монотонность: $a = 5 > 1$, знак сохраняется: $2x + 1 < 5$.', + 'Решаем: $2x < 4 \\Rightarrow x < 2$.', + 'Пересечение с ОДЗ ($x > -1/2$): $-\\dfrac{1}{2} < x < 2$.', + 'Ответ: $x \\in \\left(-\\dfrac{1}{2};\\,2\\right)$.' + ], + axis: { lo: -3, hi: 5, segs: [{a:-0.5, b:2, closedA:false, closedB:false, color:'#7c3aed'}] } + }, + { + q: '$\\log_2^2 x - 3 \\log_2 x + 2 \\le 0$', + steps: [ + 'ОДЗ: $x > 0$.', + 'Замена $t = \\log_2 x$: $t^2 - 3t + 2 \\le 0$.', + 'Корни уравнения: $t = 1, t = 2$. Парабола ветвями вверх $\\le 0$ между корнями: $1 \\le t \\le 2$.', + 'Обратно: $1 \\le \\log_2 x \\le 2 \\Leftrightarrow 2 \\le x \\le 4$.', + '$[2; 4] \\subset (0; +\\infty)$ — ОДЗ выполняется.', + 'Ответ: $x \\in [2; 4]$.' + ], + axis: { lo: 0, hi: 6, segs: [{a:2, b:4, closedA:true, closedB:true, color:'#7c3aed'}] } + }, + { + q: '$\\lg (x + 1) \\le 1$', + steps: [ + 'ОДЗ: $x + 1 > 0 \\Rightarrow x > -1$.', + 'Переписываем: $1 = \\lg 10$. Неравенство: $\\lg (x + 1) \\le \\lg 10$.', + 'Учитываем монотонность: $a = 10 > 1$, знак сохраняется: $x + 1 \\le 10$.', + 'Решаем: $x \\le 9$.', + 'Пересечение с ОДЗ ($x > -1$): $-1 < x \\le 9$.', + 'Ответ: $x \\in (-1; 9]$.' + ], + axis: { lo: -3, hi: 12, segs: [{a:-1, b:9, closedA:false, closedB:true, color:'#7c3aed'}] } + } + ]; + const sn = document.getElementById('p10-iv1-sn'); + const nL = document.getElementById('p10-iv1-n'); + const qEl = document.getElementById('p10-iv1-q'); + const stepsEl = document.getElementById('p10-iv1-steps'); + const axisEl = document.getElementById('p10-iv1-axis'); + const nextBtn = document.getElementById('p10-iv1-next'); + const allBtn = document.getElementById('p10-iv1-all'); + const resetBtn = document.getElementById('p10-iv1-reset'); + const seen = new Set(); + let _done = false; + let cur = 0, shown = 0; + + function render(){ + const t = TASKS[cur]; + nL.textContent = (cur + 1); + qEl.innerHTML = t.q; + stepsEl.innerHTML = t.steps.map((s, i) => { + const visible = i < shown; + const isLast = i === t.steps.length - 1 && visible; + const bg = isLast ? '#dcfce7' : 'var(--card)'; + const brd = isLast ? '2px solid #16a34a' : '1px solid var(--border)'; + return '
Шаг '+(i+1)+':'+s+'
'; + }).join(''); + renderMath(qEl); + renderMath(stepsEl); + if(shown >= t.steps.length){ + axisEl.innerHTML = drawAxis(t.axis.lo, t.axis.hi, t.axis.segs); + seen.add(cur); + if(!_done && seen.size >= 5){ _done = true; addXp(10, 'p10-iv1'); bumpProgress('p10', 15); } + } else { + axisEl.innerHTML = ''; + } + } + function load(n){ cur = Math.max(0, Math.min(TASKS.length - 1, n)); shown = 1; render(); } + sn.addEventListener('input', () => load((+sn.value) - 1)); + nextBtn.addEventListener('click', () => { + if(shown < TASKS[cur].steps.length){ shown++; render(); } + }); + allBtn.addEventListener('click', () => { shown = TASKS[cur].steps.length; render(); }); + resetBtn.addEventListener('click', () => { shown = 1; render(); }); + load(0); + })(); + + /* === IV2 — калькулятор log_a (kx + b) ⋚ c === */ + (function(){ + const aI = document.getElementById('p10-iv2-a'); + const kI = document.getElementById('p10-iv2-k'); + const bI = document.getElementById('p10-iv2-b'); + const cI = document.getElementById('p10-iv2-c'); + const sSel = document.getElementById('p10-iv2-sign'); + const go = document.getElementById('p10-iv2-go'); + const out = document.getElementById('p10-iv2-out'); + const axisEl = document.getElementById('p10-iv2-axis'); + const fb = document.getElementById('p10-iv2-fb'); + const used = new Set(); + let _done = false; + + document.querySelectorAll('#p10-iv2 [data-set]').forEach(btn => { + btn.addEventListener('click', () => { + const v = btn.dataset.set.split(','); + aI.value = v[0]; kI.value = v[1]; bI.value = v[2]; sSel.value = v[3]; cI.value = v[4]; + calc(); + }); + }); + + function aLabel(a){ + if(Math.abs(a - 10) < 1e-9) return '\\lg'; + if(Math.abs(a - 1/3) < 1e-3) return '\\log_{1/3}'; + if(Math.abs(a - 0.5) < 1e-9) return '\\log_{1/2}'; + return '\\log_{' + (+a.toFixed(4)) + '}'; + } + function fxLabel(k, b){ + let s = ''; + if(k === 1) s = 'x'; + else if(k === -1) s = '-x'; + else s = k + 'x'; + if(b > 0) s += ' + ' + b; + else if(b < 0) s += ' - ' + (-b); + return s; + } + function signStr(s){ + return {gt:'>', lt:'<', ge:'\\ge', le:'\\le'}[s]; + } + function flipSign(s){ + return {gt:'lt', lt:'gt', ge:'le', le:'ge'}[s]; + } + function isStrict(s){ return s === 'gt' || s === 'lt'; } + + function calc(){ + const a = parseFloat(aI.value); + const k = parseFloat(kI.value); + const b = parseFloat(bI.value); + const c = parseFloat(cI.value); + const s = sSel.value; + if(![a,k,b,c].every(isFinite)){ feedback(fb, false, '✗ Введи все четыре числа.'); return; } + if(a <= 0 || Math.abs(a - 1) < 1e-9){ feedback(fb, false, '✗ Основание $a$ должно быть $> 0$ и $\\ne 1$.'); return; } + if(k === 0){ feedback(fb, false, '✗ При $k = 0$ выражение под логарифмом не зависит от $x$.'); return; } + + const fx = fxLabel(k, b); + const eq = '$' + aLabel(a) + '(' + fx + ') ' + signStr(s) + ' ' + c + '$'; + let html = '
Неравенство: '+eq+'
'; + + // ОДЗ: kx + b > 0 + const odzBound = -b / k; + const odzDir = k > 0 ? 'gt' : 'lt'; + const odzStr = k > 0 ? '$x > ' + (+odzBound.toFixed(4)) + '$' : '$x < ' + (+odzBound.toFixed(4)) + '$'; + html += '
Шаг 1. ОДЗ: $' + fx + ' > 0 \\Rightarrow$ ' + odzStr + '.
'; + + // Шаг 2: перевод правой части a^c + const ac = Math.pow(a, c); + html += '
Шаг 2. Переписываем правую часть: $' + c + ' = ' + aLabel(a) + ' ' + a + '^{' + c + '} = ' + aLabel(a) + ' ' + (+ac.toFixed(4)) + '$.
'; + + // Шаг 3: монотонность + let curSign = s; + let monoText; + if(a > 1){ + monoText = '$a = ' + a + ' > 1$ — знак сохраняется'; + } else { + monoText = '$0 < a = ' + (+a.toFixed(4)) + ' < 1$ — знак меняется'; + curSign = flipSign(curSign); + } + html += '
Шаг 3. Монотонность: ' + monoText + '. Переход: $' + fx + ' ' + signStr(curSign) + ' ' + (+ac.toFixed(4)) + '$.
'; + + // Шаг 4: решить относительно x + // kx + b [sign] ac => kx [sign] ac - b => x [sign|flip if k<0] (ac - b)/k + const rhs = (ac - b) / k; + let finalSign = curSign; + if(k < 0) finalSign = flipSign(finalSign); + html += '
Шаг 4. Решаем: $kx ' + signStr(curSign) + ' ' + (+ac.toFixed(4)) + ' - (' + b + ')'; + if(k < 0) html += '$, делим на $k = ' + k + ' < 0$ — знак меняется: $x ' + signStr(finalSign) + ' ' + (+rhs.toFixed(4)) + '$.
'; + else html += ' \\Rightarrow x ' + signStr(finalSign) + ' ' + (+rhs.toFixed(4)) + '$.'; + + // Шаг 5: пересечь с ОДЗ + // Решение исходного: x [finalSign] rhs. ОДЗ: x [odzDir] odzBound. + // Найдём интервал пересечения + function rangeFromIneq(dir, bound){ + // dir in {gt, lt, ge, le} + if(dir === 'gt') return {lo: bound, hi: +Infinity, closedLo: false, closedHi: false}; + if(dir === 'ge') return {lo: bound, hi: +Infinity, closedLo: true, closedHi: false}; + if(dir === 'lt') return {lo: -Infinity, hi: bound, closedLo: false, closedHi: false}; + if(dir === 'le') return {lo: -Infinity, hi: bound, closedLo: false, closedHi: true}; + } + const r1 = rangeFromIneq(finalSign, rhs); + const r2 = rangeFromIneq(odzDir, odzBound); + const lo = Math.max(r1.lo, r2.lo); + const hi = Math.min(r1.hi, r2.hi); + const closedLo = (lo === r1.lo ? r1.closedLo : false) && (lo === r2.lo ? r2.closedLo : false) || (lo === r1.lo && lo !== r2.lo && r1.closedLo) || (lo === r2.lo && lo !== r1.lo && r2.closedLo); + // Простая логика: closedLo true только если lo пришёл из границы, которая closed; ОДЗ всегда строгое, так что closedLo возможен только если lo === rhs && finalSign in {ge, le} + let cLo = false, cHi = false; + if(lo === r1.lo) cLo = r1.closedLo; + if(lo === r2.lo) cLo = cLo && r2.closedLo; + if(hi === r1.hi) cHi = r1.closedHi; + if(hi === r2.hi) cHi = cHi && r2.closedHi; + // Однако если lo берётся только из одной стороны (другая = -Inf), то closed зависит только от той стороны. + if(r1.lo === -Infinity) cLo = r2.closedLo; + if(r2.lo === -Infinity) cLo = r1.closedLo; + if(r1.hi === +Infinity) cHi = r2.closedHi; + if(r2.hi === +Infinity) cHi = r1.closedHi; + + if(lo >= hi && !(lo === hi && cLo && cHi)){ + html += '
Шаг 5. Пересечение пустое — решений нет.
'; + html += '
Ответ: $x \\in \\varnothing$.
'; + axisEl.innerHTML = ''; + } else { + // Сформируем строку интервала + const lp = (lo === -Infinity) ? '(-\\infty' : ((cLo ? '[' : '(') + (+lo.toFixed(4))); + const rp = (hi === +Infinity) ? '+\\infty)' : ((+hi.toFixed(4)) + (cHi ? ']' : ')')); + html += '
Шаг 5. Пересечение исходного и ОДЗ: $' + lp + ';\\, ' + rp + '$.
'; + html += '
Ответ: $x \\in ' + lp + ';\\, ' + rp + '$.
'; + + // Визуализация + const lo2 = (lo === -Infinity) ? Math.floor(hi) - 5 : Math.floor(lo) - 2; + const hi2 = (hi === +Infinity) ? Math.ceil(lo) + 5 : Math.ceil(hi) + 2; + const segLo = (lo === -Infinity) ? -Infinity : lo; + const segHi = (hi === +Infinity) ? +Infinity : hi; + axisEl.innerHTML = drawAxis(lo2, hi2, [{a:segLo, b:segHi, closedA:cLo, closedB:cHi, color:'#7c3aed'}]); + } + + out.innerHTML = html; + renderMath(out); + feedback(fb, true, '✓ Решено.'); + used.add(aI.value+','+kI.value+','+bI.value+','+sSel.value+','+cI.value); + if(!_done && used.size >= 4){ _done = true; addXp(10, 'p10-iv2'); bumpProgress('p10', 15); } + } + go.addEventListener('click', calc); + [aI, kI, bI, cI].forEach(i => i.addEventListener('keydown', e => { if(e.key === 'Enter') calc(); })); + sSel.addEventListener('change', calc); + calc(); + })(); + + /* === IV3 — знак сохраняется или меняется? === */ + (function(){ + const OPTS = ['Сохраняется', 'Меняется']; + const Q = [ + { q: '$\\log_2 (x - 1) > \\log_2 5$', ans: 0, hint: 'Основание $a = 2 > 1$ — функция возрастает, знак сохраняется.' }, + { q: '$\\log_{1/3} (x + 2) < \\log_{1/3} 7$', ans: 1, hint: 'Основание $a = 1/3 < 1$ — функция убывает, знак меняется.' }, + { q: '$\\log_5 x > 2$', ans: 0, hint: 'Перепишем $2 = \\log_5 25$. $a = 5 > 1$ — знак сохраняется.' }, + { q: '$\\log_{0{,}5} (x - 1) \\ge 3$', ans: 1, hint: 'Основание $a = 0{,}5 < 1$ — знак меняется.' }, + { q: '$\\lg (2x) > 1$', ans: 0, hint: '$\\lg = \\log_{10}$, $a = 10 > 1$ — знак сохраняется.' }, + { q: '$\\log_{1/2} x \\le 4$', ans: 1, hint: 'Основание $a = 1/2 < 1$ — знак меняется.' }, + { q: '$\\log_3 (x + 4) > 0$', ans: 0, hint: 'Основание $a = 3 > 1$ — знак сохраняется. (А $0 = \\log_3 1$.)' }, + { q: '$\\log_{0{,}1} x \\ge -1$', ans: 1, hint: 'Основание $a = 0{,}1 < 1$ — знак меняется.' }, + ]; + let i = 0, score = 0; + const qEl = document.getElementById('p10-iv3-q'); + const oEl = document.getElementById('p10-iv3-opts'); + const fb = document.getElementById('p10-iv3-fb'); + const iEl = document.getElementById('p10-iv3-i'); + const sEl = document.getElementById('p10-iv3-s'); + + function show(){ + if(i >= Q.length){ + qEl.innerHTML = 'Готово! Результат: '+score+' / '+Q.length; + oEl.innerHTML = ''; + if(score === Q.length){ addXp(15, 'p10-iv3'); bumpProgress('p10', 25); } + else if(score >= 6){ addXp(8, 'p10-iv3'); bumpProgress('p10', 15); } + return; + } + iEl.textContent = (i + 1); + sEl.textContent = score; + const item = Q[i]; + qEl.innerHTML = item.q; + oEl.innerHTML = OPTS.map((o, k) => '').join(''); + fb.style.display = 'none'; + renderMath(qEl); + oEl.querySelectorAll('button').forEach(b => { + b.addEventListener('click', () => { + const k = +b.dataset.k; + if(k === item.ans){ score++; feedback(fb, true, '✓ Верно! '+item.hint+' Дальше ▶'); } + else feedback(fb, false, '✗ Неверно. Правильно: '+OPTS[item.ans]+'. '+item.hint+' Дальше ▶'); + sEl.textContent = score; + oEl.querySelectorAll('button').forEach(x => x.disabled = true); + i++; + setTimeout(show, 1700); + }); + }); + } + document.getElementById('p10-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); }); + show(); + })(); + + /* === IV4 — тренажёр неравенств === */ + (function(){ + const Q = [ + { q: '$\\log_2 (x - 1) > 3$ — введи нижнюю границу интервала ответа', ans: 9, hint: 'ОДЗ $x > 1$. $x - 1 > 8 \\Rightarrow x > 9$. Ответ $(9; +\\infty)$, граница — $9$.' }, + { q: '$\\log_{1/3} (x - 2) > -2$ — введи верхнюю границу интервала ответа', ans: 11, hint: 'ОДЗ $x > 2$. $-2 = \\log_{1/3} 9$, знак меняется: $x - 2 < 9 \\Rightarrow x < 11$. Ответ $(2; 11)$, верхняя граница — $11$.' }, + { q: '$\\log_5 x < 2$ — введи верхнюю границу интервала ответа', ans: 25, hint: 'ОДЗ $x > 0$. $2 = \\log_5 25$, знак сохраняется: $x < 25$. Ответ $(0; 25)$, верхняя граница — $25$.' }, + { q: '$\\log_{1/2} (x - 3) \\ge -2$ — введи верхнюю границу интервала ответа', ans: 7, hint: 'ОДЗ $x > 3$. $-2 = \\log_{1/2} 4$, знак меняется: $x - 3 \\le 4 \\Rightarrow x \\le 7$. Ответ $(3; 7]$, верхняя граница — $7$.' }, + { q: '$\\lg x > 1$ — введи нижнюю границу интервала ответа', ans: 10, hint: 'ОДЗ $x > 0$. $1 = \\lg 10$, знак сохраняется: $x > 10$. Ответ $(10; +\\infty)$, граница — $10$.' }, + { q: '$\\log_3 (x + 1) \\le 2$ — введи верхнюю границу интервала ответа', ans: 8, hint: 'ОДЗ $x > -1$. $2 = \\log_3 9$, знак сохраняется: $x + 1 \\le 9 \\Rightarrow x \\le 8$. Ответ $(-1; 8]$, верхняя граница — $8$.' }, + ]; + let i = 0, score = 0; + function show(){ + const qEl = document.getElementById('p10-iv4-q'); + const iEl = document.getElementById('p10-iv4-i'); + const sEl = document.getElementById('p10-iv4-s'); + const fb = document.getElementById('p10-iv4-fb'); + const ansI = document.getElementById('p10-iv4-ans'); + if(i >= Q.length){ + qEl.innerHTML = 'Готово! Результат: '+score+' / '+Q.length; + if(score === Q.length){ addXp(15, 'p10-iv4'); bumpProgress('p10', 25); } + else if(score >= 4){ addXp(8, 'p10-iv4'); bumpProgress('p10', 15); } + return; + } + iEl.textContent = (i + 1); + sEl.textContent = score; + qEl.innerHTML = Q[i].q; + ansI.value = ''; + renderMath(qEl); + fb.style.display = 'none'; + setTimeout(() => ansI.focus(), 30); + } + function go(){ + if(i >= Q.length) return; + const fb = document.getElementById('p10-iv4-fb'); + const raw = document.getElementById('p10-iv4-ans').value.replace(',', '.'); + const ans = parseFloat(raw); + if(isNaN(ans)){ feedback(fb, false, '✗ Введи число.'); return; } + if(Math.abs(ans - Q[i].ans) < 0.05){ + score++; + feedback(fb, true, '✓ Верно! '+Q[i].hint+' Дальше ▶'); + } else { + feedback(fb, false, '✗ Неверно. Ответ: $'+Q[i].ans+'$. '+Q[i].hint+' Дальше ▶'); + } + document.getElementById('p10-iv4-s').textContent = score; + i++; + setTimeout(show, 1700); + } + document.getElementById('p10-iv4-go').addEventListener('click', go); + document.getElementById('p10-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); }); + document.getElementById('p10-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); }); + show(); + })(); + wireReadBtn('p10'); } function buildFinal3(){ const box = document.getElementById('final3-body'); let html = ''; - html += makeCard('theory', 'В разработке', '★.0', ` -

Содержание финала главы Финал главы будет добавлено в Phase 1+.

-

Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.

-

Ключевая формула: Итоги · боссы главы 3

- `); - html += secNavFor('final3'); - html += readButton('final3'); + + /* Часть А — Шпаргалка главы 3 (4 mini-карточки) */ + html += `
+
+
${ICONS.theory}
+
Шпаргалка главы 3
+
Итог
+
+
+

Ключевые формулы и идеи всех четырёх параграфов в одном месте — просмотри перед битвой с боссами.

+
+
+
+ +
§ 7 · Свойства логарифмов
+
+
$\\log_a (bc) = \\log_a b + \\log_a c$, $\\;\\log_a \\dfrac{b}{c} = \\log_a b - \\log_a c$, $\\;\\log_a b^n = n \\log_a b$, $\\;\\log_a b = \\dfrac{\\log_c b}{\\log_c a}$.
+
+
+
+ +
§ 8 · Логарифмическая функция
+
+
$y = \\log_a x$. $D = (0; +\\infty)$, $E = \\mathbb{R}$. При $a > 1$ — возрастает, при $0 < a < 1$ — убывает. Точка $(1; 0)$. Асимптота $x = 0$. Обратная к $y = a^x$.
+
+
+
+ +
§ 9 · Логарифм. уравнения
+
+
$\\log_a f = \\log_a g \\Rightarrow f = g$ + ОДЗ ($f, g > 0$). Методы: потенциирование, замена, свойства, графический. Проверять корни!
+
+
+
+ +
§ 10 · Логарифм. неравенства
+
+
При $a > 1$ знак сохраняется, при $0 < a < 1$ — меняется. ВСЕГДА учитываем ОДЗ: всё под $\\log$ должно быть строго положительно.
+
+
+
+
`; + + /* Часть Б — 5 боссов (intro) */ + html += `
+
+
${ICONS.rule}
+
Боссы главы 3
+
5
+
+
+

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

+
+
`; + + html += '
'; + + html += `
+
Прогресс по боссам
+
0 / 5 боссов побеждено
+
+
+
+ +
`; + + html += secNav('p10', null); + box.innerHTML = html; renderMath(box); - wireReadBtn('final3'); + + /* Боссы */ + const BOSSES = [ + { + n:1, color:'#10b981', + title:'Циклоп Свойств', + tag:'§ 7', + q:'Вычислите: $\\log_2 24 - \\log_2 3 - \\log_2 \\sqrt{16}$. Введите числовой ответ.', + ans:1, + hint:'$\\log_2 24 - \\log_2 3 = \\log_2 \\dfrac{24}{3} = \\log_2 8 = 3$. $\\;\\log_2 \\sqrt{16} = \\log_2 4 = 2$. Итог: $3 - 2 = 1$.' + }, + { + n:2, color:'#0891b2', + title:'Минотавр Логарифмической', + tag:'§ 8', + q:'У функции $y = \\log_{1/3} x$ найдите $y(81)$.', + ans:-4, + hint:'$\\log_{1/3} 81 = \\log_{1/3} (1/3)^{-4} = -4$ (т.к. $(1/3)^{-4} = 3^4 = 81$).' + }, + { + n:3, color:'#7c3aed', + title:'Гарпия Уравнений', + tag:'§ 9', + q:'Решите $\\log_3 (x^2 - 2x) = \\log_3 3$. Найдите сумму корней.', + ans:2, + hint:'Потенциируем: $x^2 - 2x = 3 \\Rightarrow (x-3)(x+1) = 0 \\Rightarrow x = 3, x = -1$. ОДЗ $x^2 - 2x > 0$: $x < 0$ или $x > 2$. Оба корня подходят. Сумма $= 3 + (-1) = 2$.' + }, + { + n:4, color:'#dc2626', + title:'Дракон Неравенств', + tag:'§ 10', + q:'Решите $\\log_{1/2} (x - 3) \\ge -2$. Найдите наибольшее целое $x$ из решения.', + ans:7, + hint:'ОДЗ $x > 3$. $-2 = \\log_{1/2} 4$, $a < 1$ — знак меняется: $x - 3 \\le 4 \\Rightarrow x \\le 7$. Решение $(3; 7]$, наибольшее целое — $7$.' + }, + { + n:5, color:'#f59e0b', + title:'Мастер Логарифмов', + tag:'§ 7 + § 8 + § 9 + § 10', + q:'Решите $\\log_2^2 x - \\log_2 x = 2$. Найдите произведение корней.', + ans:2, + hint:'Замена $t = \\log_2 x$: $t^2 - t - 2 = 0 \\Rightarrow t = 2$ или $t = -1$. $x_1 = 2^2 = 4$, $x_2 = 2^{-1} = 1/2$. Произведение: $4 \\cdot 1/2 = 2$.' + }, + ]; + + const cont = document.getElementById('ch3-bosses-container'); + const STATE_KEY = 'algebra11_ch3_bosses'; + const BOSS_STATE = (function(){ + try{ const s = localStorage.getItem(STATE_KEY); if(s){ const p = JSON.parse(s); if(Array.isArray(p) && p.length === BOSSES.length) return p; } }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('ch3-boss-overall'); + const fill = document.getElementById('ch3-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('ch3-final-reward'); + if(reward && reward.style.display === 'none'){ + reward.style.display = 'block'; + if(!STATE.achievements.has('ch3_done')){ + achievement('ch3_done','Магистр логарифмической функции'); + addXp(50, 'ch3-bonus'); + bumpProgress('final3', 30); + if(window.confetti){ try{ confetti(); }catch(e){} } + } + } + } + } + + BOSSES.forEach((b, idx)=>{ + const card = document.getElementById('boss3-'+b.n+'-card'); + const goBtn = document.getElementById('boss3-'+b.n+'-go'); + const hintBtn = document.getElementById('boss3-'+b.n+'-hint'); + const ansInp = document.getElementById('boss3-'+b.n+'-ans'); + if(BOSS_STATE[idx].defeated){ + card.style.background = 'linear-gradient(135deg,var(--sec-acc-soft),var(--pri-soft))'; + card.classList.add('glow'); + 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('boss3-'+b.n+'-fb'); + const raw = ansInp.value.replace(',', '.'); + const val = parseFloat(raw); + if(isNaN(val)){ feedback(fb, false, '✗ Введи число.'); return; } + if(Math.abs(val - b.ans) < 0.05){ + BOSS_STATE[idx].defeated = true; saveBosses(); + feedback(fb, true, '✓ Босс '+b.n+' повержен! +10 XP. '+b.hint); + addXp(10, 'boss-ch3-'+b.n); + bumpProgress('final3', 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))'; + card.classList.add('glow','pulse'); + setTimeout(()=>card.classList.remove('pulse'), 900); + refreshOverall(); + } else { + feedback(fb, false, '✗ Промах. Попробуй ещё. Подсказка доступна.'); + } + }); + hintBtn.addEventListener('click', ()=>{ + const fb = document.getElementById('boss3-'+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 ===== */