feat(alg11 ch1 wave3 + final): §3 «Логарифм» + Финал Главы 1 (5 боссов)

This commit is contained in:
Maxim Dolgolyov
2026-05-29 11:50:26 +03:00
parent 2f4109cb7c
commit d0e249613c
+481 -14
View File
@@ -1375,31 +1375,498 @@ function buildP2(){
function buildP3(){
const box = document.getElementById('p3-body');
let html = '';
html += makeCard('theory', 'В разработке', '3.0', `
<p>Содержание параграфа <b>Определение логарифма</b> будет добавлено в Phase 1+.</p>
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.</p>
<p style="color:var(--muted);font-size:.9rem">Ключевая формула: $\log_a b = c$</p>
`);
html += secNavFor('p3');
html += makeCard('theory', 'Определение логарифма', '3.1', `
<p><b>Логарифмом</b> числа $b$ по основанию $a$ называется такой показатель степени $c$, в который нужно возвести $a$, чтобы получить $b$:</p>
\\[ \\log_a b = c \\;\\Leftrightarrow\\; a^c = b \\]
<p>при условиях $a > 0$, $a \\ne 1$, $b > 0$.</p>
<p><b>Примеры.</b></p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>$\\log_2 8 = 3$, потому что $2^3 = 8$.</li>
<li>$\\log_3 81 = 4$, потому что $3^4 = 81$.</li>
<li>$\\log_5 \\dfrac{1}{25} = -2$, потому что $5^{-2} = \\dfrac{1}{25}$.</li>
<li>$\\log_{10} 1000 = 3$ (десятичный логарифм).</li>
</ul>
<details class="spoiler"><summary>Почему такие ограничения на $a$ и $b$?</summary><div class="spoiler-body">
Если $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$ всегда.
</div></details>`);
html += makeCard('rule', 'Основное логарифмическое тождество и базовые свойства', '3.2', `
<p><b>Основное логарифмическое тождество:</b></p>
\\[ a^{\\log_a b} = b \\]
<p>Оно означает буквально то же, что и определение: если возвести основание $a$ в степень $\\log_a b$, получим само $b$.</p>
<p><b>Базовые свойства</b> (следуют прямо из определения):</p>
<ul style="margin:6px 0 8px 22px;line-height:1.75">
<li>$\\log_a 1 = 0$ — потому что $a^0 = 1$.</li>
<li>$\\log_a a = 1$ — потому что $a^1 = a$.</li>
<li>$\\log_a a^n = n$ — потому что $a^n = a^n$.</li>
<li>$\\log_a \\dfrac{1}{a^n} = -n$ — потому что $a^{-n} = \\dfrac{1}{a^n}$.</li>
</ul>
<p><b>Пример.</b> $7^{\\log_7 5} = 5$ — это сразу следует из тождества, не нужно ничего вычислять.</p>
<p><b>Пример.</b> $\\log_2 2^{10} = 10$, $\\log_3 \\dfrac{1}{81} = -4$.</p>`);
html += makeCard('example', 'Десятичный и натуральный логарифмы', '3.3', `
<p><b>Десятичный логарифм</b> — это логарифм по основанию $10$. Для него ввели специальное обозначение:</p>
\\[ \\lg b = \\log_{10} b \\]
<p>Примеры: $\\lg 1000 = 3$, $\\lg 0{,}01 = -2$, $\\lg 1 = 0$, $\\lg 10 = 1$.</p>
<p><b>Натуральный логарифм</b> — это логарифм по основанию $e \\approx 2{,}71828\\ldots$ ($e$ — иррациональное число, постоянная Эйлера):</p>
\\[ \\ln b = \\log_e b \\]
<p>Натуральный логарифм встречается в физике, биологии, экономике — везде, где речь идёт о законах роста и распада (радиоактивный распад, рост колоний бактерий, сложные проценты).</p>
<p><b>Примеры.</b> $\\ln e = 1$, $\\ln e^2 = 2$, $\\ln 1 = 0$, $e^{\\ln 5} = 5$ (по основному тождеству).</p>`);
/* INTERACTIVE 1 — визуализатор логарифма через показательную функцию */
html += `<div class="wg" id="p3-iv1">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Логарифм как показатель в $a^x = b$</div></div>
<div class="wg-help">Двигай ползунки. Кривая $y = a^x$ пересекает горизонталь $y = b$ в точке с абсциссой $x = \\log_a b$ — это и есть значение логарифма.</div>
<div class="sliders">
<label>Основание $a$ = <b id="p3-iv1-a">2</b><input type="range" id="p3-iv1-sa" min="1.5" max="10" step="0.5" value="2"></label>
<label>Аргумент $b$ = <b id="p3-iv1-b">8</b><input type="range" id="p3-iv1-sb" min="0.1" max="10" step="0.1" value="8"></label>
</div>
<div style="background:var(--card);border-radius:9px;padding:10px;text-align:center"><svg id="p3-iv1-svg" viewBox="0 0 480 360" width="100%" style="max-width:480px;height:auto"></svg></div>
<div id="p3-iv1-formula" style="margin-top:10px;padding:12px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:1rem;text-align:center;line-height:1.9"></div>
</div>`;
/* INTERACTIVE 2 — калькулятор логарифма */
html += `<div class="wg" id="p3-iv2">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор $\\log_a b$</div></div>
<div class="wg-help">Введи основание $a$ и аргумент $b$. Если $b$ — точная степень $a$, увидишь целый ответ. Иначе — приближённое значение.</div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:10px">
<span style="font-family:'JetBrains Mono',monospace">$a$ =</span>
<input type="number" id="p3-iv2-a" class="tinp" style="width:80px;text-align:center" value="2" step="0.1">
<span style="font-family:'JetBrains Mono',monospace;margin-left:8px">$b$ =</span>
<input type="number" id="p3-iv2-b" class="tinp" style="width:80px;text-align:center" value="8" step="0.1">
<button class="btn primary" id="p3-iv2-go">Вычислить $\\log_a b$</button>
</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;justify-content:center;margin-bottom:10px;font-size:.82rem">
<span style="color:var(--muted)">Быстрый ввод $a$:</span>
<button class="btn" data-aq="2" id="p3-iv2-a2" style="padding:3px 9px;font-size:.82rem">2</button>
<button class="btn" data-aq="3" id="p3-iv2-a3" style="padding:3px 9px;font-size:.82rem">3</button>
<button class="btn" data-aq="10" id="p3-iv2-a10" style="padding:3px 9px;font-size:.82rem">10</button>
<button class="btn" data-aq="2.71828" id="p3-iv2-ae" style="padding:3px 9px;font-size:.82rem">$e$</button>
</div>
<div id="p3-iv2-out" style="padding:12px 14px;background:var(--card);border-radius:9px;font-size:.96rem;min-height:80px;line-height:1.8"></div>
<div class="feedback" id="p3-iv2-fb"></div>
</div>`;
/* INTERACTIVE 3 — DnD: логарифм → значение */
html += `<div class="wg" id="p3-iv3">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Сопоставь логарифм со значением</div></div>
<div class="wg-help">Перетащи каждый логарифм в правильный ящик. Помни: $\\log_a b$ — это показатель, в который надо возвести $a$, чтобы получить $b$.</div>
<div class="dnd-hint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11V6a3 3 0 0 1 6 0v5"/><path d="M9 11h6v8a4 4 0 0 1-8 0z"/></svg> 8 логарифмов — 4 ящика</div>
<div id="p3-iv3-pool"></div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-top:8px">
<div class="drop-box"><h5 data-cat="m3">$=-3$</h5><div class="drop-items" data-cat="m3"></div></div>
<div class="drop-box"><h5 data-cat="m2">$=-2$</h5><div class="drop-items" data-cat="m2"></div></div>
<div class="drop-box"><h5 data-cat="p3">$=3$</h5><div class="drop-items" data-cat="p3"></div></div>
<div class="drop-box"><h5 data-cat="p4">$=4$</h5><div class="drop-items" data-cat="p4"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p3-iv3-check">Проверить</button><button class="btn" id="p3-iv3-reset">Сначала</button></div>
<div class="feedback" id="p3-iv3-fb"></div>
</div>`;
/* INTERACTIVE 4 — тренажёр логарифмов */
html += `<div class="wg" id="p3-iv4">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр: вычисли логарифм</div></div>
<div class="wg-help">6 задач. Введи число — целое или десятичное (допуск $\\pm 0{,}05$).</div>
<div class="score-display"><span>Задача <b id="p3-iv4-i">1</b> / 6</span><span>Очки: <b id="p3-iv4-s">0</b> / 6</span></div>
<div id="p3-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.15rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">
<span style="font-family:'JetBrains Mono',monospace">ответ =</span>
<input type="number" id="p3-iv4-ans" class="tinp" style="width:110px;text-align:center" step="0.01">
<button class="btn primary" id="p3-iv4-go">Проверить</button>
<button class="btn" id="p3-iv4-start">Заново</button>
</div>
<div class="feedback" id="p3-iv4-fb"></div>
</div>`;
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 += '<text x="'+(W-pad-110)+'" y="'+(pad+14)+'" font-size="12" font-weight="700" fill="#3b82f6">y = a^x</text>';
g += '<text x="'+(W-pad-110)+'" y="'+(pad+30)+'" font-size="12" font-weight="700" fill="#ef4444">y = b</text>';
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, '&#10007; Основание $a$ должно быть положительным.'); out.innerHTML=''; return; }
if(Math.abs(a - 1) < 1e-9){ feedback(fb, false, '&#10007; Основание $a$ не может быть равно 1.'); out.innerHTML=''; return; }
if(!isFinite(b) || b <= 0){ feedback(fb, false, '&#10007; Аргумент $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 += '<div style="font-weight:700;color:var(--ok)">$\\log_{'+aShow+'} '+bShow+' = '+intCand+'$</div>';
html += '<div style="font-size:.88rem;color:var(--muted);margin-top:6px">Точное значение, так как $'+bShow+' = '+aShow+'^{'+intCand+'}$.</div>';
} else {
html += '<div style="font-weight:700;color:var(--sec-acc-d)">$\\log_{'+aShow+'} '+bShow+' \\approx '+(+val.toFixed(4))+'$</div>';
html += '<div style="font-size:.88rem;color:var(--muted);margin-top:6px">Приближённое значение (через формулу $\\dfrac{\\ln b}{\\ln a}$).</div>';
}
html += '<div style="margin-top:8px;font-size:.92rem">Проверка: $'+aShow+'^{'+(+val.toFixed(4))+'} \\approx '+(+check.toFixed(4))+'$.</div>';
out.innerHTML = html;
renderMath(out);
feedback(fb, true, '&#10003; Вычислено.');
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, '&#10007; Размести все 8 логарифмов.'); return; }
if(correct === items.length){ feedback(fb, true, '&#10003; Все 8 на месте! +15 XP'); addXp(15,'p3-iv3'); bumpProgress('p3', 25); }
else feedback(fb, false, '&#10007; Правильно ' + 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 = '<b>Готово!</b> Результат: ' + 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, '&#10007; Введи число.'); return; }
if(Math.abs(ans - Q[i].ans) < 0.05){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].hint+'. Дальше ▶'); }
else feedback(fb, false, '&#10007; Неверно. Ответ: $'+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', `
<p>Содержание финала главы <b>Финал главы</b> будет добавлено в Phase 1+.</p>
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.</p>
<p style="color:var(--muted);font-size:.9rem">Ключевая формула: Итоги · боссы главы 1</p>
`);
html += secNavFor('final1');
html += readButton('final1');
/* Часть А — Шпаргалка главы (3 mini-карточки) */
html += `<div class="card">
<div class="card-header">
<span class="card-icon theory">${ICONS.theory}</span>
<span class="card-title">Шпаргалка главы 1</span>
<span class="card-num">Итог</span>
</div>
<div class="card-body">
<p>Ключевые формулы и идеи всех трёх параграфов в одном месте — просмотри перед битвой с боссами.</p>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-top:10px">
<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<svg viewBox="0 0 24 24" fill="none" stroke="#d97706" stroke-width="2" style="width:18px;height:18px"><path d="M3 18l3-6 3 6"/><path d="M4 16h4"/><path d="M14 8l4 8"/><path d="M14 16l4-8"/></svg>
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 1 · Рац. степень</div>
</div>
<div style="font-size:.95rem">$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}$.</div>
</div>
<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<svg viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" style="width:18px;height:18px"><path d="M3 12c4-9 14-9 18 0"/><path d="M3 12c4 9 14 9 18 0"/></svg>
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 2 · Степ. функция</div>
</div>
<div style="font-size:.95rem">$y = x^\\alpha$ — 6 типов по $\\alpha$. Все графики проходят через $(1; 1)$. При нечётном $\\alpha$ — нечётная, при чётном — чётная. При $\\alpha < 0$ — гипербола.</div>
</div>
<div style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<svg viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="2" style="width:18px;height:18px"><path d="M4 4h16"/><path d="M4 12h16"/><path d="M4 20h10"/></svg>
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 3 · Логарифм</div>
</div>
<div style="font-size:.95rem">$\\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$.</div>
</div>
</div>
</div>
</div>`;
/* Часть Б — 5 боссов (intro) */
html += `<div class="card">
<div class="card-header">
<span class="card-icon rule">${ICONS.rule}</span>
<span class="card-title">Боссы главы 1</span>
<span class="card-num">5</span>
</div>
<div class="card-body">
<p>5 интегрированных задач — каждая комбинирует ≥ 2 темы. За каждого побеждённого босса: <b>+10 XP, +18% к прогрессу</b>. Победишь всех — ачивка <b>«Магистр степеней и логарифмов»</b> и <b>+50 XP бонус</b>.</p>
</div>
</div>`;
html += '<div id="ch1-bosses-container"></div>';
html += `<div style="margin-top:18px;padding:18px 20px;background:linear-gradient(135deg,var(--pri-soft),var(--sec-acc-soft));border-radius:14px;border:1.5px solid var(--pri);text-align:center" id="ch1-final-summary">
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:var(--pri2);font-size:1.1rem;margin-bottom:6px">Прогресс по боссам</div>
<div id="ch1-boss-overall" style="font-size:.95rem;color:var(--text);margin-bottom:10px">0 / 5 боссов побеждено</div>
<div style="height:12px;background:var(--card);border-radius:8px;overflow:hidden;border:1px solid var(--border)">
<div id="ch1-boss-overall-fill" style="height:100%;width:0%;background:linear-gradient(90deg,#d97706,#fbbf24);transition:width .35s"></div>
</div>
<div id="ch1-final-reward" style="margin-top:14px;display:none;padding:14px;background:var(--card);border-radius:11px;border:2px solid #f59e0b">
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:#92400e;font-size:1.05rem;margin-bottom:6px">Магистр степеней и логарифмов</div>
<div style="font-size:.92rem;margin-bottom:10px">Глава 1 пройдена! Все 5 боссов повержены. +50 XP бонус.</div>
<a class="btn primary" href="/textbook/algebra-11-ch2" style="text-decoration:none">Дальше: Глава 2 <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></a>
</div>
</div>`;
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 '<div class="boss-card" id="boss1-'+b.n+'-card" style="padding:16px;background:var(--card);border-radius:12px;border:2px solid '+b.color+';margin-bottom:14px">'
+'<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap">'
+'<svg viewBox="0 0 24 24" fill="none" stroke="'+b.color+'" stroke-width="2.2" style="width:28px;height:28px;flex-shrink:0"><polygon points="12,2 22,20 2,20"/></svg>'
+'<div style="font-family:\'Unbounded\',sans-serif;font-weight:800;color:'+b.color+';font-size:1.05rem">Босс '+b.n+': '+b.title+'</div>'
+'<div style="margin-left:auto;font-size:.78rem;color:var(--muted);padding:3px 8px;background:var(--sec-acc-soft);border-radius:6px">'+b.tag+'</div>'
+'</div>'
+'<div class="boss-q" id="boss1-'+b.n+'-q" style="padding:12px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:1rem;line-height:1.5;margin-bottom:10px">'+b.q+'</div>'
+'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">'
+'<span style="font-family:\'JetBrains Mono\',monospace;font-size:.92rem">ответ =</span>'
+'<input type="number" id="boss1-'+b.n+'-ans" class="tinp" style="width:120px;text-align:center" step="0.01" placeholder="число">'
+'<button class="btn primary" id="boss1-'+b.n+'-go" style="background:'+b.color+';border-color:'+b.color+'">Атаковать</button>'
+'<button class="btn" id="boss1-'+b.n+'-hint">Подсказка</button>'
+'</div>'
+'<div class="feedback" id="boss1-'+b.n+'-fb"></div>'
+'</div>';
}).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, '&#10007; Введи число.'); return; }
if(Math.abs(val - b.ans) < 0.05){
BOSS_STATE[idx].defeated = true; saveBosses();
feedback(fb, true, '&#10003; Босс '+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, '&#10007; Промах. Попробуй ещё. Подсказка доступна.');
}
});
hintBtn.addEventListener('click', ()=>{
const fb = document.getElementById('boss1-'+b.n+'-fb');
fb.className = 'feedback ok';
fb.innerHTML = '<b>Подсказка:</b> '+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 ===== */