diff --git a/frontend/textbooks/algebra_11_ch1.html b/frontend/textbooks/algebra_11_ch1.html index 328721d..0de30ad 100644 --- a/frontend/textbooks/algebra_11_ch1.html +++ b/frontend/textbooks/algebra_11_ch1.html @@ -1375,31 +1375,498 @@ function buildP2(){ function buildP3(){ const box = document.getElementById('p3-body'); let html = ''; - html += makeCard('theory', 'В разработке', '3.0', ` -

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

-

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

-

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

- `); - html += secNavFor('p3'); + + html += makeCard('theory', 'Определение логарифма', '3.1', ` +

Логарифмом числа $b$ по основанию $a$ называется такой показатель степени $c$, в который нужно возвести $a$, чтобы получить $b$:

+ \\[ \\log_a b = c \\;\\Leftrightarrow\\; a^c = b \\] +

при условиях $a > 0$, $a \\ne 1$, $b > 0$.

+

Примеры.

+ +
Почему такие ограничения на $a$ и $b$?
+ Если $a = 1$, то $1^c = 1$ для любого $c$ — равенство $1^c = b$ имело бы решение только при $b = 1$, и оно было бы не единственным. Если $a \\le 0$, то $a^c$ не определена для всех действительных $c$. Если $b \\le 0$, то уравнение $a^c = b$ при $a > 0$ не имеет решений, ведь $a^c > 0$ всегда. +
`); + + html += makeCard('rule', 'Основное логарифмическое тождество и базовые свойства', '3.2', ` +

Основное логарифмическое тождество:

+ \\[ a^{\\log_a b} = b \\] +

Оно означает буквально то же, что и определение: если возвести основание $a$ в степень $\\log_a b$, получим само $b$.

+

Базовые свойства (следуют прямо из определения):

+ +

Пример. $7^{\\log_7 5} = 5$ — это сразу следует из тождества, не нужно ничего вычислять.

+

Пример. $\\log_2 2^{10} = 10$, $\\log_3 \\dfrac{1}{81} = -4$.

`); + + html += makeCard('example', 'Десятичный и натуральный логарифмы', '3.3', ` +

Десятичный логарифм — это логарифм по основанию $10$. Для него ввели специальное обозначение:

+ \\[ \\lg b = \\log_{10} b \\] +

Примеры: $\\lg 1000 = 3$, $\\lg 0{,}01 = -2$, $\\lg 1 = 0$, $\\lg 10 = 1$.

+

Натуральный логарифм — это логарифм по основанию $e \\approx 2{,}71828\\ldots$ ($e$ — иррациональное число, постоянная Эйлера):

+ \\[ \\ln b = \\log_e b \\] +

Натуральный логарифм встречается в физике, биологии, экономике — везде, где речь идёт о законах роста и распада (радиоактивный распад, рост колоний бактерий, сложные проценты).

+

Примеры. $\\ln e = 1$, $\\ln e^2 = 2$, $\\ln 1 = 0$, $e^{\\ln 5} = 5$ (по основному тождеству).

`); + + /* INTERACTIVE 1 — визуализатор логарифма через показательную функцию */ + html += `
+
ИНТЕРАКТИВ 1
Логарифм как показатель в $a^x = b$
+
Двигай ползунки. Кривая $y = a^x$ пересекает горизонталь $y = b$ в точке с абсциссой $x = \\log_a b$ — это и есть значение логарифма.
+
+ + +
+
+
+
`; + + /* INTERACTIVE 2 — калькулятор логарифма */ + html += `
+
ИНТЕРАКТИВ 2
Калькулятор $\\log_a b$
+
Введи основание $a$ и аргумент $b$. Если $b$ — точная степень $a$, увидишь целый ответ. Иначе — приближённое значение.
+
+ $a$ = + + $b$ = + + +
+
+ Быстрый ввод $a$: + + + + +
+
+
+
`; + + /* INTERACTIVE 3 — DnD: логарифм → значение */ + html += `
+
ИНТЕРАКТИВ 3
Сопоставь логарифм со значением
+
Перетащи каждый логарифм в правильный ящик. Помни: $\\log_a b$ — это показатель, в который надо возвести $a$, чтобы получить $b$.
+
8 логарифмов — 4 ящика
+
+
+
$=-3$
+
$=-2$
+
$=3$
+
$=4$
+
+
+
+
`; + + /* INTERACTIVE 4 — тренажёр логарифмов */ + html += `
+
ИНТЕРАКТИВ 4
Тренажёр: вычисли логарифм
+
6 задач. Введи число — целое или десятичное (допуск $\\pm 0{,}05$).
+
Задача 1 / 6Очки: 0 / 6
+
+
+ ответ = + + + +
+
+
`; + + html += secNav('p2', 'final1'); html += readButton('p3'); + box.innerHTML = html; renderMath(box); + + /* IV1 — визуализатор */ + (function(){ + const sa = document.getElementById('p3-iv1-sa'); + const sb = document.getElementById('p3-iv1-sb'); + const aL = document.getElementById('p3-iv1-a'); + const bL = document.getElementById('p3-iv1-b'); + const svg = document.getElementById('p3-iv1-svg'); + const fEl = document.getElementById('p3-iv1-formula'); + const seen = new Set(); + let _done = false; + + function draw(){ + const a = +sa.value; + const b = +sb.value; + aL.textContent = (Number.isInteger(a) ? a : a.toFixed(1)); + bL.textContent = (Math.abs(b - Math.round(b)) < 0.01) ? Math.round(b) : b.toFixed(1); + const W = 480, H = 360, pad = 36; + const xmin = -3, xmax = 5, ymin = -1, ymax = 12; + const ax = axes2D(W, H, pad, xmin, xmax, ymin, ymax); + let g = ax.content; + // y = a^x + g += plotFunc(x => Math.pow(a, x), xmin, xmax, ax.toX, ax.toY, '#3b82f6', 240); + // y = b (асимптота-горизонталь) + g += asymptote('h', b, ax.toX, ax.toY, xmin, xmax, ymin, ymax, '#ef4444'); + // точка пересечения + const xVal = Math.log(b) / Math.log(a); + if(isFinite(xVal) && xVal >= xmin && xVal <= xmax){ + g += pointWithDrop(xVal, b, ax.toX, ax.toY, '#10b981', 'log_'+ (Number.isInteger(a)?a:a.toFixed(1)) +' '+ (Math.abs(b - Math.round(b))<0.01?Math.round(b):b.toFixed(1)) +' ≈ ' + (+xVal.toFixed(3))); + } + // легенда + g += 'y = a^x'; + g += 'y = b'; + svg.innerHTML = g; + + const aTxt = Number.isInteger(a) ? a : (+a.toFixed(1)); + const bTxt = Math.abs(b - Math.round(b)) < 0.01 ? Math.round(b) : (+b.toFixed(1)); + const xTxt = (+xVal.toFixed(4)); + fEl.innerHTML = '$\\log_{'+aTxt+'} '+bTxt+' \\approx '+xTxt+'$ — это показатель, в который надо возвести $'+aTxt+'$, чтобы получить $'+bTxt+'$.'; + renderMath(fEl); + + const sig = (Math.round(a*2)/2) + ':' + (Math.round(b*10)/10); + seen.add(sig); + if(!_done && seen.size >= 6){ _done = true; addXp(10, 'p3-iv1'); bumpProgress('p3', 15); } + } + sa.addEventListener('input', draw); + sb.addEventListener('input', draw); + draw(); + })(); + + /* IV2 — калькулятор */ + (function(){ + const aI = document.getElementById('p3-iv2-a'); + const bI = document.getElementById('p3-iv2-b'); + const goBtn = document.getElementById('p3-iv2-go'); + const out = document.getElementById('p3-iv2-out'); + const fb = document.getElementById('p3-iv2-fb'); + let usedOk = 0; + let _done = false; + + document.querySelectorAll('#p3-iv2 [data-aq]').forEach(btn=>{ + btn.addEventListener('click', ()=>{ aI.value = btn.dataset.aq; }); + }); + + function compute(){ + const a = parseFloat(aI.value); + const b = parseFloat(bI.value); + if(!isFinite(a) || a <= 0){ feedback(fb, false, '✗ Основание $a$ должно быть положительным.'); out.innerHTML=''; return; } + if(Math.abs(a - 1) < 1e-9){ feedback(fb, false, '✗ Основание $a$ не может быть равно 1.'); out.innerHTML=''; return; } + if(!isFinite(b) || b <= 0){ feedback(fb, false, '✗ Аргумент $b$ должен быть положительным.'); out.innerHTML=''; return; } + + const val = Math.log(b) / Math.log(a); + // проверим целое значение + const intCand = Math.round(val); + const isExact = Math.abs(val - intCand) < 1e-6 && Math.abs(Math.pow(a, intCand) - b) < 1e-6; + let aShow = (Math.abs(a - 2.71828) < 0.001) ? 'e' : (Number.isInteger(a) ? String(a) : (+a.toFixed(3)).toString()); + let bShow = Number.isInteger(b) ? String(b) : (+b.toFixed(3)).toString(); + const check = Math.pow(a, val); + + let html = ''; + if(isExact){ + html += '
$\\log_{'+aShow+'} '+bShow+' = '+intCand+'$
'; + html += '
Точное значение, так как $'+bShow+' = '+aShow+'^{'+intCand+'}$.
'; + } else { + html += '
$\\log_{'+aShow+'} '+bShow+' \\approx '+(+val.toFixed(4))+'$
'; + html += '
Приближённое значение (через формулу $\\dfrac{\\ln b}{\\ln a}$).
'; + } + html += '
Проверка: $'+aShow+'^{'+(+val.toFixed(4))+'} \\approx '+(+check.toFixed(4))+'$.
'; + out.innerHTML = html; + renderMath(out); + feedback(fb, true, '✓ Вычислено.'); + usedOk++; + if(!_done && usedOk >= 4){ _done = true; addXp(10, 'p3-iv2'); bumpProgress('p3', 15); } + } + goBtn.addEventListener('click', compute); + aI.addEventListener('keydown', e=>{ if(e.key === 'Enter') compute(); }); + bI.addEventListener('keydown', e=>{ if(e.key === 'Enter') compute(); }); + })(); + + /* IV3 — DnD: логарифм → значение */ + (function(){ + const items = [ + { id:'l1', cat:'p3', html:'$\\log_2 8$' }, + { id:'l2', cat:'p4', html:'$\\log_3 81$' }, + { id:'l3', cat:'m2', html:'$\\log_2 \\tfrac{1}{4}$' }, + { id:'l4', cat:'p3', html:'$\\log_4 64$' }, + { id:'l5', cat:'m3', html:'$\\log_{10} 0{,}001$' }, + { id:'l6', cat:'p3', html:'$\\log_5 125$' }, + { id:'l7', cat:'p4', html:'$\\log_2 16$' }, + { id:'l8', cat:'m2', html:'$\\log_3 \\tfrac{1}{9}$' }, + ]; + const sorter = setupSorter({ + poolId:'p3-iv3-pool', + scopeSelector:'#p3-iv3', + items: items, + cats:['m3','m2','p3','p4'], + columnLayout:false, + }); + document.getElementById('p3-iv3-check').addEventListener('click', ()=>{ + const fb = document.getElementById('p3-iv3-fb'); + const placedCount = items.filter(it => sorter.placed[it.id]).length; + const correct = items.filter(it => sorter.placed[it.id] === it.cat).length; + if(placedCount < items.length){ feedback(fb, false, '✗ Размести все 8 логарифмов.'); return; } + if(correct === items.length){ feedback(fb, true, '✓ Все 8 на месте! +15 XP'); addXp(15,'p3-iv3'); bumpProgress('p3', 25); } + else feedback(fb, false, '✗ Правильно ' + correct + ' из 8. Попробуй ещё.'); + }); + document.getElementById('p3-iv3-reset').addEventListener('click', ()=>{ sorter.reset(); document.getElementById('p3-iv3-fb').style.display = 'none'; }); + })(); + + /* IV4 — тренажёр */ + (function(){ + const Q = [ + { q:'$\\log_2 32 = \\;?$', ans:5, hint:'$2^5 = 32$' }, + { q:'$\\log_{10} 1000 = \\;?$', ans:3, hint:'$10^3 = 1000$, то есть $\\lg 1000 = 3$' }, + { q:'$\\log_3 \\dfrac{1}{27} = \\;?$', ans:-3, hint:'$3^{-3} = \\dfrac{1}{27}$' }, + { q:'$2^{\\log_2 7} = \\;?$', ans:7, hint:'Основное логарифмическое тождество $a^{\\log_a b} = b$' }, + { q:'$\\log_5 5^4 = \\;?$', ans:4, hint:'$\\log_a a^n = n$' }, + { q:'$\\log_{1/2} 8 = \\;?$', ans:-3, hint:'$\\left(\\tfrac{1}{2}\\right)^{-3} = 2^3 = 8$' }, + ]; + let i = 0, score = 0; + function show(){ + if(i >= Q.length){ + document.getElementById('p3-iv4-q').innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length; + if(score === Q.length){ addXp(15,'p3-iv4'); bumpProgress('p3', 25); } + else if(score >= 4){ addXp(8,'p3-iv4'); bumpProgress('p3', 15); } + return; + } + document.getElementById('p3-iv4-i').textContent = (i+1); + document.getElementById('p3-iv4-s').textContent = score; + document.getElementById('p3-iv4-q').innerHTML = Q[i].q; + document.getElementById('p3-iv4-ans').value = ''; + renderMath(document.getElementById('p3-iv4-q')); + document.getElementById('p3-iv4-fb').style.display = 'none'; + } + function go(){ + if(i >= Q.length) return; + const fb = document.getElementById('p3-iv4-fb'); + const raw = document.getElementById('p3-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('p3-iv4-s').textContent = score; + i++; + setTimeout(show, 1300); + } + document.getElementById('p3-iv4-go').addEventListener('click', go); + document.getElementById('p3-iv4-ans').addEventListener('keydown', e=>{ if(e.key === 'Enter') go(); }); + document.getElementById('p3-iv4-start').addEventListener('click', ()=>{ i=0; score=0; show(); }); + show(); + })(); + wireReadBtn('p3'); } function buildFinal1(){ const box = document.getElementById('final1-body'); let html = ''; - html += makeCard('theory', 'В разработке', '★.0', ` -

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

-

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

-

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

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

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

+
+
+
+ +
§ 1 · Рац. степень
+
+
$a^{m/n} = \\sqrt[n]{a^m}$ при $a > 0$. Все свойства из 7 класса сохраняются: $a^p a^q = a^{p+q}$, $(a^p)^q = a^{pq}$. Показатель — любое $x \\in \\mathbb{R}$.
+
+
+
+ +
§ 2 · Степ. функция
+
+
$y = x^\\alpha$ — 6 типов по $\\alpha$. Все графики проходят через $(1; 1)$. При нечётном $\\alpha$ — нечётная, при чётном — чётная. При $\\alpha < 0$ — гипербола.
+
+
+
+ +
§ 3 · Логарифм
+
+
$\\log_a b = c \\Leftrightarrow a^c = b$ ($a > 0$, $a \\ne 1$, $b > 0$). Тождество: $a^{\\log_a b} = b$. $\\lg = \\log_{10}$, $\\ln = \\log_e$.
+
+
+
+
`; + + /* Часть Б — 5 боссов (intro) */ + html += `
+
+ ${ICONS.rule} + Боссы главы 1 + 5 +
+
+

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

+
+
`; + + html += '
'; + + html += `
+
Прогресс по боссам
+
0 / 5 боссов побеждено
+
+
+
+ +
`; + + html += secNav('p3', null); + box.innerHTML = html; renderMath(box); - wireReadBtn('final1'); + + /* Боссы */ + const BOSSES = [ + { + n:1, color:'#10b981', + title:'Циклоп Степеней', + tag:'§ 1 + § 2', + q:'Вычислите: $\\left(\\dfrac{27}{8}\\right)^{2/3} \\cdot \\left(\\dfrac{9}{4}\\right)^{-1}$. Введите ответ числом.', + ans:1, + hint:'$\\left(\\dfrac{27}{8}\\right)^{2/3} = \\left(\\dfrac{3}{2}\\right)^2 = \\dfrac{9}{4}$. Тогда $\\dfrac{9}{4} \\cdot \\dfrac{4}{9} = 1$.' + }, + { + n:2, color:'#0891b2', + title:'Минотавр Степенной', + tag:'§ 2', + q:'У функции $y = x^{-2}$ найдите $y(-0{,}5)$. Введите ответ числом.', + ans:4, + hint:'$(-0{,}5)^{-2} = \\dfrac{1}{(-0{,}5)^2} = \\dfrac{1}{0{,}25} = 4$.' + }, + { + n:3, color:'#7c3aed', + title:'Гарпия Тождества', + tag:'§ 3', + q:'Вычислите: $9^{\\log_3 5}$. Введите ответ числом.', + ans:25, + hint:'$9 = 3^2$, поэтому $9^{\\log_3 5} = 3^{2\\log_3 5} = 3^{\\log_3 25} = 25$.' + }, + { + n:4, color:'#dc2626', + title:'Дракон Логарифмический', + tag:'§ 3 + § 1', + q:'Найдите $\\log_2 \\sqrt[3]{16}$. Введите десятичное число (допуск $\\pm 0{,}05$).', + ans:4/3, + hint:'$\\sqrt[3]{16} = 16^{1/3} = (2^4)^{1/3} = 2^{4/3}$. Тогда $\\log_2 2^{4/3} = \\dfrac{4}{3} \\approx 1{,}33$.' + }, + { + n:5, color:'#f59e0b', + title:'Мастер Степеней', + tag:'§ 1 + § 2 + § 3', + q:'Решите уравнение $x^{\\log_2 x} = 16$. Введите больший корень числом.', + ans:4, + hint:'Логарифмируем по основанию 2: $(\\log_2 x)^2 = \\log_2 16 = 4$, значит $\\log_2 x = \\pm 2$. Корни $x = 4$ и $x = \\tfrac{1}{4}$. Больший — $4$.' + }, + ]; + + const cont = document.getElementById('ch1-bosses-container'); + const STATE_KEY = 'algebra11_ch1_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('ch1-boss-overall'); + const fill = document.getElementById('ch1-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('ch1-final-reward'); + if(reward && reward.style.display === 'none'){ + reward.style.display = 'block'; + if(!STATE.achievements.has('ch1_done')){ + achievement('ch1_done','Магистр степеней и логарифмов'); + addXp(50, 'ch1-bonus'); + bumpProgress('final1', 30); + if(window.confetti){ try{ confetti(); }catch(e){} } + } + } + } + } + + BOSSES.forEach((b, idx)=>{ + const card = document.getElementById('boss1-'+b.n+'-card'); + const goBtn = document.getElementById('boss1-'+b.n+'-go'); + const hintBtn = document.getElementById('boss1-'+b.n+'-hint'); + const ansInp = document.getElementById('boss1-'+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('boss1-'+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-ch1-'+b.n); + bumpProgress('final1', 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('boss1-'+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 ===== */