feat(alg11 ch2 wave3 + final): §6 «Показательные неравенства» + Финал Главы 2
§6 — 3 makeCard (теория правила знаков, алгоритм, замена переменной) + 4 интерактива: пошаговый решатель с числовой прямой SVG, калькулятор a^(kx+b) sg c с учётом монотонности и знака k, квикфайр «сохраняется/меняется» (8), тренажёр границ интервала (6). Финал 2 — 3 mini-карточки шпаргалки (§4/§5/§6) + 5 боссов (Циклоп Показательной, Минотавр Уравнений, Гарпия Неравенств, Дракон Замены, Мастер Показательной) с прогресс-баром, ачивкой ch2_done «Магистр показательной функции» + 50 XP бонус. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1459,31 +1459,707 @@ function buildP5(){
|
||||
function buildP6(){
|
||||
const box = document.getElementById('p6-body');
|
||||
let html = '';
|
||||
html += makeCard('theory', 'В разработке', '6.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">Ключевая формула: $a^x > b$</p>
|
||||
`);
|
||||
|
||||
/* === ТЕОРИЯ === */
|
||||
|
||||
html += makeCard('theory', 'Основное правило', '6.1', `
|
||||
<p><b>Показательным неравенством</b> называется неравенство вида $a^{f(x)} > a^{g(x)}$ (или $<$, $\\ge$, $\\le$), где $a > 0$, $a \\ne 1$.</p>
|
||||
<p>Поскольку функция $y = a^x$ <b>монотонна</b> (см. §4), при переходе от степеней к показателям всё зависит от того, возрастает она или убывает:</p>
|
||||
<p style="text-align:center;padding:12px;background:var(--sec-acc-soft);border-radius:9px;margin:12px 0">
|
||||
$a^{f(x)} > a^{g(x)} \\;\\Leftrightarrow\\; \\begin{cases} f(x) > g(x), & \\text{если } a > 1, \\\\ f(x) < g(x), & \\text{если } 0 < a < 1. \\end{cases}$
|
||||
</p>
|
||||
<p><b>Запомни</b>:</p>
|
||||
<ul style="margin:6px 0 6px 22px;line-height:1.7">
|
||||
<li>при $a > 1$ знак неравенства <b>сохраняется</b> (функция возрастает — порядок сохраняется);</li>
|
||||
<li>при $0 < a < 1$ знак неравенства <b>меняется на противоположный</b> (функция убывает — порядок переворачивается).</li>
|
||||
</ul>
|
||||
<p>Это правило — прямое следствие монотонности показательной функции (см. §4).</p>`);
|
||||
|
||||
html += makeCard('rule', 'Алгоритм решения', '6.2', `
|
||||
<p><b>Алгоритм</b> похож на алгоритм для уравнений из §5, но требует постоянного контроля знака неравенства:</p>
|
||||
<ol style="margin:8px 0 8px 22px;line-height:1.75">
|
||||
<li>Привести обе части к степени с <b>одинаковым основанием</b> $a$.</li>
|
||||
<li>Сравнить значение $a$ с единицей и записать неравенство показателей с правильным знаком.</li>
|
||||
<li>Решить полученное неравенство для $x$ и записать ответ интервалом.</li>
|
||||
</ol>
|
||||
<p><b>Пример 1.</b> $2^{x-1} > 8$.</p>
|
||||
<p>$8 = 2^3$, поэтому $2^{x-1} > 2^3$. Основание $a = 2 > 1$ — знак <b>сохраняется</b>: $x - 1 > 3 \\Rightarrow x > 4$.</p>
|
||||
<p><b>Ответ:</b> $x \\in (4;\\;+\\infty)$.</p>
|
||||
<p><b>Пример 2.</b> $\\left(\\dfrac{1}{3}\\right)^x \\ge 9$.</p>
|
||||
<p>$9 = 3^2 = \\left(\\dfrac{1}{3}\\right)^{-2}$. Тогда $\\left(\\dfrac{1}{3}\\right)^x \\ge \\left(\\dfrac{1}{3}\\right)^{-2}$. Основание $a = \\dfrac{1}{3} < 1$ — знак <b>меняется</b>: $x \\le -2$.</p>
|
||||
<p><b>Ответ:</b> $x \\in (-\\infty;\\;-2]$.</p>`);
|
||||
|
||||
html += makeCard('example', 'Метод замены переменной', '6.3', `
|
||||
<p>Если неравенство содержит $a^{2x}$ и $a^x$, делаем замену $t = a^x$, причём <b>обязательно $t > 0$</b>. Получаем алгебраическое неравенство (чаще квадратное), которое решаем методом интервалов.</p>
|
||||
<p style="text-align:center;padding:10px;background:var(--sec-acc-soft);border-radius:9px;margin:10px 0">
|
||||
$A \\cdot a^{2x} + B \\cdot a^x + C \\;\\gtrless\\; 0 \\;\\xrightarrow{\\;t = a^x > 0\\;}\\; A t^2 + B t + C \\;\\gtrless\\; 0$
|
||||
</p>
|
||||
<p><b>Алгоритм</b>:</p>
|
||||
<ol style="margin:8px 0 8px 22px;line-height:1.75">
|
||||
<li>Сделать замену $t = a^x$, $t > 0$.</li>
|
||||
<li>Решить полученное неравенство для $t$ методом интервалов.</li>
|
||||
<li>Пересечь полученное множество с условием $t > 0$.</li>
|
||||
<li>Вернуться к $x$ из $a^x \\in [\\,t_1;\\,t_2\\,]$ с учётом монотонности.</li>
|
||||
</ol>
|
||||
<p><b>Пример.</b> $4^x - 5 \\cdot 2^x + 4 \\le 0$.</p>
|
||||
<p>Замечаем $4^x = (2^x)^2$. Замена $t = 2^x > 0$: $t^2 - 5t + 4 \\le 0$. Корни $t = 1$, $t = 4$, значит $t \\in [1;\\;4]$ (оба положительны — условие выполнено).</p>
|
||||
<p>Возвращаемся: $1 \\le 2^x \\le 4 \\Leftrightarrow 2^0 \\le 2^x \\le 2^2$. Основание $2 > 1$ — знак сохраняется: $0 \\le x \\le 2$.</p>
|
||||
<p><b>Ответ:</b> $x \\in [0;\\;2]$.</p>`);
|
||||
|
||||
/* === ИНТЕРАКТИВЫ === */
|
||||
|
||||
/* IV1 — решатель показательных неравенств с шагами и числовой прямой */
|
||||
html += `<div class="wg" id="p6-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Решатель показательных неравенств</div></div>
|
||||
<div class="wg-help">Выбери задачу ползунком и нажимай «Следующий шаг ▶». В конце появится ответ на числовой прямой. Просмотри все 5 задач — получишь XP.</div>
|
||||
<div class="sliders">
|
||||
<label>Задача № <b id="p6-iv1-n">1</b> / 5<input type="range" id="p6-iv1-sn" min="1" max="5" step="1" value="1"></label>
|
||||
</div>
|
||||
<div id="p6-iv1-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.08rem;text-align:center;margin-bottom:10px"></div>
|
||||
<div id="p6-iv1-steps" style="display:flex;flex-direction:column;gap:8px;margin-bottom:10px"></div>
|
||||
<div id="p6-iv1-line" style="display:none;margin:10px 0;padding:10px;background:var(--card);border-radius:9px;border:1px solid var(--border);text-align:center"></div>
|
||||
<div class="actions" style="justify-content:center">
|
||||
<button class="btn primary" id="p6-iv1-next">Следующий шаг ▶</button>
|
||||
<button class="btn" id="p6-iv1-all">Показать все шаги</button>
|
||||
<button class="btn" id="p6-iv1-reset">Скрыть шаги</button>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
/* IV2 — калькулятор a^(kx+b) > c */
|
||||
html += `<div class="wg" id="p6-iv2">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор $a^{kx+b} \\gtrless c$</div></div>
|
||||
<div class="wg-help">Введи $a$, $k$, $b$, $c$ и выбери знак неравенства. Калькулятор подскажет, сохраняется или меняется знак, и выдаст ответ интервалом.</div>
|
||||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:8px">
|
||||
<span style="font-family:'JetBrains Mono',monospace">$a$ =</span>
|
||||
<input type="number" id="p6-iv2-a" class="tinp" style="width:70px;text-align:center" value="2" step="1">
|
||||
<span style="font-family:'JetBrains Mono',monospace">$k$ =</span>
|
||||
<input type="number" id="p6-iv2-k" class="tinp" style="width:70px;text-align:center" value="1" step="1">
|
||||
<span style="font-family:'JetBrains Mono',monospace">$b$ =</span>
|
||||
<input type="number" id="p6-iv2-b" class="tinp" style="width:70px;text-align:center" value="-1" step="1">
|
||||
<span style="font-family:'JetBrains Mono',monospace">знак</span>
|
||||
<select id="p6-iv2-sg" class="tinp" style="width:64px;text-align:center">
|
||||
<option value="gt">></option>
|
||||
<option value="ge">≥</option>
|
||||
<option value="lt"><</option>
|
||||
<option value="le">≤</option>
|
||||
</select>
|
||||
<span style="font-family:'JetBrains Mono',monospace">$c$ =</span>
|
||||
<input type="number" id="p6-iv2-c" class="tinp" style="width:70px;text-align:center" value="8" step="1">
|
||||
<button class="btn primary" id="p6-iv2-go">Решить</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)">Примеры:</span>
|
||||
<button class="btn" data-set="2,1,-1,gt,8" style="padding:4px 10px;font-size:.82rem">$2^{x-1}>8$</button>
|
||||
<button class="btn" data-set="3,1,1,lt,27" style="padding:4px 10px;font-size:.82rem">$3^{x+1}<27$</button>
|
||||
<button class="btn" data-set="2,1,0,gt,-5" style="padding:4px 10px;font-size:.82rem">$2^x>-5$</button>
|
||||
<button class="btn" data-set="2,1,0,lt,-1" style="padding:4px 10px;font-size:.82rem">$2^x<-1$</button>
|
||||
</div>
|
||||
<div id="p6-iv2-out" style="padding:12px 14px;background:var(--card);border-radius:9px;font-size:.96rem;min-height:60px;line-height:1.8"></div>
|
||||
<div class="feedback" id="p6-iv2-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* IV3 — знак сохраняется или меняется? */
|
||||
html += `<div class="wg" id="p6-iv3">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Сохраняется или меняется?</div></div>
|
||||
<div class="wg-help">Глядя на основание степени, определи, что произойдёт со знаком неравенства при переходе к показателям. 8 заданий.</div>
|
||||
<div class="score-display"><span>Задача <b id="p6-iv3-i">1</b> / 8</span><span>Очки: <b id="p6-iv3-s">0</b> / 8</span></div>
|
||||
<div id="p6-iv3-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.12rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
|
||||
<div id="p6-iv3-opts" style="display:grid;grid-template-columns:1fr 1fr;gap:10px;max-width:520px;margin:0 auto"></div>
|
||||
<div class="feedback" id="p6-iv3-fb"></div>
|
||||
<div class="actions" style="justify-content:center"><button class="btn" id="p6-iv3-restart">Начать заново</button></div>
|
||||
</div>`;
|
||||
|
||||
/* IV4 — тренажёр неравенств */
|
||||
html += `<div class="wg" id="p6-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр неравенств</div></div>
|
||||
<div class="wg-help">Реши неравенство и введи <b>границу</b> интервала ответа (например, для $x > 3$ ввести $3$; для $x \\in [0;\\,2]$ ввести любую границу — указано в задании). Допуск $\\pm 0{,}05$. 6 задач.</div>
|
||||
<div class="score-display"><span>Задача <b id="p6-iv4-i">1</b> / 6</span><span>Очки: <b id="p6-iv4-s">0</b> / 6</span></div>
|
||||
<div id="p6-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.12rem;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="p6-iv4-ans" class="tinp" style="width:120px;text-align:center" step="0.01">
|
||||
<button class="btn primary" id="p6-iv4-go">Проверить</button>
|
||||
<button class="btn" id="p6-iv4-start">Заново</button>
|
||||
</div>
|
||||
<div class="feedback" id="p6-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
html += secNavFor('p6');
|
||||
html += readButton('p6');
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
|
||||
/* === IV1 — решатель с шагами и числовой прямой === */
|
||||
(function(){
|
||||
/* line: {min, max, lo, hi, openLo, openHi, dirLeft, dirRight}
|
||||
dirLeft/dirRight — стрелка уходит влево/вправо за границу видимой части */
|
||||
const TASKS = [
|
||||
{
|
||||
q: '$2^x > 8$',
|
||||
steps: [
|
||||
'Приводим к одному основанию: $8 = 2^3$, поэтому $2^x > 2^3$.',
|
||||
'Основание $a = 2 > 1$ — знак <b>сохраняется</b>: $x > 3$.',
|
||||
'<b>Ответ:</b> $x \\in (3;\\;+\\infty)$.'
|
||||
],
|
||||
line: { min:-2, max:8, lo:3, hi:null, openLo:true, dirRight:true }
|
||||
},
|
||||
{
|
||||
q: '$\\left(\\dfrac{1}{2}\\right)^x \\ge 4$',
|
||||
steps: [
|
||||
'Приводим к одному основанию: $4 = 2^2 = \\left(\\dfrac{1}{2}\\right)^{-2}$.',
|
||||
'Получаем $\\left(\\dfrac{1}{2}\\right)^x \\ge \\left(\\dfrac{1}{2}\\right)^{-2}$.',
|
||||
'Основание $a = \\dfrac{1}{2} < 1$ — знак <b>меняется</b>: $x \\le -2$.',
|
||||
'<b>Ответ:</b> $x \\in (-\\infty;\\;-2]$.'
|
||||
],
|
||||
line: { min:-7, max:3, lo:null, hi:-2, openHi:false, dirLeft:true }
|
||||
},
|
||||
{
|
||||
q: '$3^{x+1} < 27$',
|
||||
steps: [
|
||||
'Приводим к одному основанию: $27 = 3^3$, поэтому $3^{x+1} < 3^3$.',
|
||||
'Основание $a = 3 > 1$ — знак <b>сохраняется</b>: $x + 1 < 3$.',
|
||||
'Откуда $x < 2$.',
|
||||
'<b>Ответ:</b> $x \\in (-\\infty;\\;2)$.'
|
||||
],
|
||||
line: { min:-3, max:7, lo:null, hi:2, openHi:true, dirLeft:true }
|
||||
},
|
||||
{
|
||||
q: '$4^x - 5 \\cdot 2^x + 4 \\le 0$',
|
||||
steps: [
|
||||
'Замечаем $4^x = (2^x)^2$. Замена $t = 2^x$, $t > 0$.',
|
||||
'Получаем квадратное: $t^2 - 5t + 4 \\le 0$. Корни $t = 1$, $t = 4$.',
|
||||
'Решение по $t$: $t \\in [1;\\;4]$ (оба положительны).',
|
||||
'Возвращаемся: $1 \\le 2^x \\le 4$, то есть $2^0 \\le 2^x \\le 2^2$. Знак сохраняется: $0 \\le x \\le 2$.',
|
||||
'<b>Ответ:</b> $x \\in [0;\\;2]$.'
|
||||
],
|
||||
line: { min:-2, max:5, lo:0, hi:2, openLo:false, openHi:false }
|
||||
},
|
||||
{
|
||||
q: '$\\left(\\dfrac{1}{3}\\right)^{x-1} > 9$',
|
||||
steps: [
|
||||
'Приводим к одному основанию: $9 = 3^2 = \\left(\\dfrac{1}{3}\\right)^{-2}$.',
|
||||
'Получаем $\\left(\\dfrac{1}{3}\\right)^{x-1} > \\left(\\dfrac{1}{3}\\right)^{-2}$.',
|
||||
'Основание $a = \\dfrac{1}{3} < 1$ — знак <b>меняется</b>: $x - 1 < -2$.',
|
||||
'Откуда $x < -1$.',
|
||||
'<b>Ответ:</b> $x \\in (-\\infty;\\;-1)$.'
|
||||
],
|
||||
line: { min:-6, max:4, lo:null, hi:-1, openHi:true, dirLeft:true }
|
||||
}
|
||||
];
|
||||
|
||||
function drawLine(L){
|
||||
const W = 420, H = 84, padL = 24, padR = 24;
|
||||
const y = 44;
|
||||
const lo = (L.lo!=null) ? L.lo : L.min;
|
||||
const hi = (L.hi!=null) ? L.hi : L.max;
|
||||
const span = L.max - L.min;
|
||||
const toX = v => padL + (v - L.min) * (W - padL - padR) / span;
|
||||
let s = '<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:'+W+'px;height:auto">';
|
||||
// главная ось
|
||||
s += '<line x1="'+padL+'" y1="'+y+'" x2="'+(W-padR)+'" y2="'+y+'" stroke="#0f172a" stroke-width="1.6"/>';
|
||||
s += '<polygon points="'+(W-padR)+','+y+' '+(W-padR-8)+','+(y-4)+' '+(W-padR-8)+','+(y+4)+'" fill="#0f172a"/>';
|
||||
// тики и подписи
|
||||
for(let v = Math.ceil(L.min); v <= Math.floor(L.max); v++){
|
||||
const x = toX(v);
|
||||
s += '<line x1="'+x+'" y1="'+(y-4)+'" x2="'+x+'" y2="'+(y+4)+'" stroke="#64748b" stroke-width="1"/>';
|
||||
s += '<text x="'+x+'" y="'+(y+18)+'" font-size="11" fill="#64748b" text-anchor="middle">'+v+'</text>';
|
||||
}
|
||||
// закрашенная область
|
||||
const xLo = toX(lo), xHi = toX(hi);
|
||||
let x1 = xLo, x2 = xHi;
|
||||
if(L.dirLeft){ x1 = padL + 2; }
|
||||
if(L.dirRight){ x2 = W - padR - 2; }
|
||||
s += '<line x1="'+x1+'" y1="'+y+'" x2="'+x2+'" y2="'+y+'" stroke="#7c3aed" stroke-width="5" stroke-linecap="round"/>';
|
||||
if(L.dirLeft){
|
||||
s += '<polygon points="'+(padL+2)+','+y+' '+(padL+10)+','+(y-5)+' '+(padL+10)+','+(y+5)+'" fill="#7c3aed"/>';
|
||||
}
|
||||
if(L.dirRight){
|
||||
s += '<polygon points="'+(W-padR-2)+','+y+' '+(W-padR-10)+','+(y-5)+' '+(W-padR-10)+','+(y+5)+'" fill="#7c3aed"/>';
|
||||
}
|
||||
// граничные точки
|
||||
if(L.lo != null){
|
||||
const fill = L.openLo ? '#fff' : '#7c3aed';
|
||||
s += '<circle cx="'+xLo+'" cy="'+y+'" r="5.5" fill="'+fill+'" stroke="#7c3aed" stroke-width="2"/>';
|
||||
s += '<text x="'+xLo+'" y="'+(y-12)+'" font-size="11" fill="#6d28d9" text-anchor="middle" font-weight="700">'+L.lo+'</text>';
|
||||
}
|
||||
if(L.hi != null){
|
||||
const fill = L.openHi ? '#fff' : '#7c3aed';
|
||||
s += '<circle cx="'+xHi+'" cy="'+y+'" r="5.5" fill="'+fill+'" stroke="#7c3aed" stroke-width="2"/>';
|
||||
s += '<text x="'+xHi+'" y="'+(y-12)+'" font-size="11" fill="#6d28d9" text-anchor="middle" font-weight="700">'+L.hi+'</text>';
|
||||
}
|
||||
s += '</svg>';
|
||||
return s;
|
||||
}
|
||||
|
||||
const sn = document.getElementById('p6-iv1-sn');
|
||||
const nL = document.getElementById('p6-iv1-n');
|
||||
const qEl = document.getElementById('p6-iv1-q');
|
||||
const stepsEl = document.getElementById('p6-iv1-steps');
|
||||
const lineEl = document.getElementById('p6-iv1-line');
|
||||
const nextBtn = document.getElementById('p6-iv1-next');
|
||||
const allBtn = document.getElementById('p6-iv1-all');
|
||||
const resetBtn = document.getElementById('p6-iv1-reset');
|
||||
const seen = new Set();
|
||||
let _done = false;
|
||||
let cur = 0, shown = 1;
|
||||
|
||||
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 '<div data-i="'+i+'" style="padding:10px 12px;background:'+bg+';border:'+brd+';border-radius:8px;font-size:.95rem;display:'+(visible?'block':'none')+'"><span style="color:var(--muted);font-weight:700;margin-right:6px">Шаг '+(i+1)+':</span>'+s+'</div>';
|
||||
}).join('');
|
||||
renderMath(qEl);
|
||||
renderMath(stepsEl);
|
||||
if(shown >= t.steps.length){
|
||||
lineEl.innerHTML = '<div style="font-size:.85rem;color:var(--muted);margin-bottom:4px">Ответ на числовой прямой:</div>' + drawLine(t.line);
|
||||
lineEl.style.display = 'block';
|
||||
seen.add(cur);
|
||||
if(!_done && seen.size >= 5){ _done = true; addXp(10, 'p6-iv1'); bumpProgress('p6', 15); }
|
||||
} else {
|
||||
lineEl.style.display = 'none';
|
||||
}
|
||||
}
|
||||
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 — калькулятор a^(kx+b) > c === */
|
||||
(function(){
|
||||
const aI = document.getElementById('p6-iv2-a');
|
||||
const kI = document.getElementById('p6-iv2-k');
|
||||
const bI = document.getElementById('p6-iv2-b');
|
||||
const sgI = document.getElementById('p6-iv2-sg');
|
||||
const cI = document.getElementById('p6-iv2-c');
|
||||
const go = document.getElementById('p6-iv2-go');
|
||||
const out = document.getElementById('p6-iv2-out');
|
||||
const fb = document.getElementById('p6-iv2-fb');
|
||||
const used = new Set();
|
||||
let _done = false;
|
||||
|
||||
document.querySelectorAll('#p6-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]; sgI.value = v[3]; cI.value = v[4];
|
||||
calc();
|
||||
});
|
||||
});
|
||||
|
||||
const SIGN_TEX = { gt:'>', ge:'\\ge', lt:'<', le:'\\le' };
|
||||
const SIGN_INT = { gt:'(', ge:'[', lt:')', le:']' };
|
||||
// переворот знака неравенства при умножении/делении на отрицательное
|
||||
function flipSign(s){ return ({gt:'lt',ge:'le',lt:'gt',le:'ge'})[s]; }
|
||||
|
||||
function calc(){
|
||||
const a = parseFloat(aI.value);
|
||||
const k = parseFloat(kI.value);
|
||||
const b = parseFloat(bI.value);
|
||||
const c = parseFloat(cI.value);
|
||||
const sg = sgI.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 expTex = (k===1?'':k) + 'x' + (b>0?'+'+b:(b<0?b:''));
|
||||
const ineq = '$' + a + '^{' + expTex + '} ' + SIGN_TEX[sg] + ' ' + c + '$';
|
||||
let html = '<div style="font-size:1.04rem;margin-bottom:8px;text-align:center">Неравенство: '+ineq+'</div>';
|
||||
|
||||
// Случай c <= 0 — левая часть всегда > 0
|
||||
if(c <= 0){
|
||||
if(sg === 'gt' || sg === 'ge'){
|
||||
html += '<div style="color:#15803d;font-weight:700">Левая часть $a^{kx+b} > 0$ при любых $x$, а правая $\\le 0$. Значит неравенство верно <b>при всех</b> $x \\in \\mathbb{R}$.</div>';
|
||||
} else {
|
||||
html += '<div style="color:#b91c1c;font-weight:700">Левая часть $a^{kx+b} > 0$, а требуется $\\le c \\le 0$. Решений <b>нет</b>.</div>';
|
||||
}
|
||||
out.innerHTML = html;
|
||||
renderMath(out);
|
||||
feedback(fb, true, '✓ Решено: см. ответ выше.');
|
||||
used.add(aI.value+','+kI.value+','+bI.value+','+sgI.value+','+cI.value);
|
||||
if(!_done && used.size >= 4){ _done = true; addXp(10, 'p6-iv2'); bumpProgress('p6', 15); }
|
||||
return;
|
||||
}
|
||||
|
||||
// Анализ монотонности
|
||||
let sgEff = sg;
|
||||
if(a < 1){
|
||||
html += '<div style="margin-bottom:6px"><b>Основание $a = '+a+' < 1$</b> — функция убывает, знак неравенства <b style="color:#b91c1c">МЕНЯЕТСЯ</b>.</div>';
|
||||
sgEff = flipSign(sgEff);
|
||||
} else {
|
||||
html += '<div style="margin-bottom:6px"><b>Основание $a = '+a+' > 1$</b> — функция возрастает, знак неравенства <b style="color:#15803d">сохраняется</b>.</div>';
|
||||
}
|
||||
|
||||
// Степень
|
||||
let intLog = null;
|
||||
for(let p = -10; p <= 12; p++){
|
||||
if(Math.abs(Math.pow(a, p) - c) < 1e-9){ intLog = p; break; }
|
||||
}
|
||||
let rhsTex;
|
||||
if(intLog !== null){
|
||||
html += '<div style="margin-bottom:6px">$'+c+' = '+a+'^{'+intLog+'}$, поэтому неравенство показателей: $'+expTex+' '+SIGN_TEX[sgEff]+' '+intLog+'$.</div>';
|
||||
rhsTex = String(intLog);
|
||||
} else {
|
||||
rhsTex = '\\log_{'+a+'} '+c;
|
||||
html += '<div style="margin-bottom:6px">Неравенство показателей: $'+expTex+' '+SIGN_TEX[sgEff]+' \\log_{'+a+'} '+c+'$.</div>';
|
||||
}
|
||||
|
||||
// Решаем kx + b [sgEff] R, где R = intLog (или log_a c)
|
||||
// x [?] (R - b) / k. Если k<0, знак ещё раз меняется.
|
||||
let sgFinal = sgEff;
|
||||
if(k < 0){
|
||||
html += '<div style="margin-bottom:6px">Делим на $k = '+k+' < 0$ — знак <b style="color:#b91c1c">снова меняется</b>.</div>';
|
||||
sgFinal = flipSign(sgFinal);
|
||||
}
|
||||
|
||||
const xNum = (intLog !== null) ? (intLog - b) : (Math.log(c)/Math.log(a) - b);
|
||||
const xVal = xNum / k;
|
||||
const xStr = (Math.abs(xVal - Math.round(xVal)) < 1e-9) ? String(Math.round(xVal)) : (+xVal.toFixed(4)).toString();
|
||||
|
||||
// Формируем интервал
|
||||
let interval;
|
||||
if(sgFinal === 'gt') interval = '('+xStr+';\\,+\\infty)';
|
||||
else if(sgFinal === 'ge') interval = '['+xStr+';\\,+\\infty)';
|
||||
else if(sgFinal === 'lt') interval = '(-\\infty;\\,'+xStr+')';
|
||||
else interval = '(-\\infty;\\,'+xStr+']';
|
||||
|
||||
html += '<div style="font-weight:700;color:#15803d">$\\Rightarrow\\; x '+SIGN_TEX[sgFinal]+' '+xStr+',\\quad x \\in '+interval+'$</div>';
|
||||
|
||||
out.innerHTML = html;
|
||||
renderMath(out);
|
||||
feedback(fb, true, '✓ Решено.');
|
||||
used.add(aI.value+','+kI.value+','+bI.value+','+sgI.value+','+cI.value);
|
||||
if(!_done && used.size >= 4){ _done = true; addXp(10, 'p6-iv2'); bumpProgress('p6', 15); }
|
||||
}
|
||||
go.addEventListener('click', calc);
|
||||
[aI, kI, bI, cI].forEach(i => i.addEventListener('keydown', e => { if(e.key === 'Enter') calc(); }));
|
||||
calc();
|
||||
})();
|
||||
|
||||
/* === IV3 — сохраняется или меняется? === */
|
||||
(function(){
|
||||
const OPTS = ['Сохраняется', 'Меняется'];
|
||||
const Q = [
|
||||
{ q: '$2^{f(x)} > 2^{g(x)}$', ans: 0, hint: 'Основание $2 > 1$ — функция возрастает, знак сохраняется.' },
|
||||
{ q: '$\\left(\\dfrac{1}{3}\\right)^{f(x)} > \\left(\\dfrac{1}{3}\\right)^{g(x)}$', ans: 1, hint: 'Основание $\\dfrac{1}{3} < 1$ — функция убывает, знак меняется.' },
|
||||
{ q: '$5^x < 25$', ans: 0, hint: 'Приводим: $5^x < 5^2$. Основание $5 > 1$ — знак сохраняется.' },
|
||||
{ q: '$\\left(\\dfrac{1}{2}\\right)^x > 8$', ans: 1, hint: 'Приводим: $\\left(1/2\\right)^x > \\left(1/2\\right)^{-3}$. Основание $< 1$ — знак меняется.' },
|
||||
{ q: '$0{,}1^x \\le 0{,}01$', ans: 1, hint: 'Приводим: $0{,}1^x \\le 0{,}1^2$. Основание $0{,}1 < 1$ — знак меняется.' },
|
||||
{ q: '$3^x \\ge 27$', ans: 0, hint: 'Приводим: $3^x \\ge 3^3$. Основание $3 > 1$ — знак сохраняется.' },
|
||||
{ q: '$10^x > 100$', ans: 0, hint: 'Приводим: $10^x > 10^2$. Основание $10 > 1$ — знак сохраняется.' },
|
||||
{ q: '$\\left(\\dfrac{2}{5}\\right)^x < 1$', ans: 1, hint: 'Приводим: $\\left(2/5\\right)^x < \\left(2/5\\right)^0$. Основание $< 1$ — знак меняется.' },
|
||||
];
|
||||
let i = 0, score = 0;
|
||||
const qEl = document.getElementById('p6-iv3-q');
|
||||
const oEl = document.getElementById('p6-iv3-opts');
|
||||
const fb = document.getElementById('p6-iv3-fb');
|
||||
const iEl = document.getElementById('p6-iv3-i');
|
||||
const sEl = document.getElementById('p6-iv3-s');
|
||||
|
||||
function show(){
|
||||
if(i >= Q.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: '+score+' / '+Q.length;
|
||||
oEl.innerHTML = '';
|
||||
if(score === Q.length){ addXp(15, 'p6-iv3'); bumpProgress('p6', 25); }
|
||||
else if(score >= 6){ addXp(8, 'p6-iv3'); bumpProgress('p6', 15); }
|
||||
return;
|
||||
}
|
||||
iEl.textContent = (i + 1);
|
||||
sEl.textContent = score;
|
||||
const item = Q[i];
|
||||
qEl.innerHTML = 'Знак неравенства при переходе к показателям: ' + item.q;
|
||||
oEl.innerHTML = OPTS.map((m, k) => '<button class="btn primary" data-k="'+k+'">'+m+'</button>').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, '✗ Неверно. Правильно: <b>'+OPTS[item.ans]+'</b>. '+item.hint+' Дальше ▶');
|
||||
sEl.textContent = score;
|
||||
oEl.querySelectorAll('button').forEach(x => x.disabled = true);
|
||||
i++;
|
||||
setTimeout(show, 1500);
|
||||
});
|
||||
});
|
||||
}
|
||||
document.getElementById('p6-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); });
|
||||
show();
|
||||
})();
|
||||
|
||||
/* === IV4 — тренажёр неравенств === */
|
||||
(function(){
|
||||
const Q = [
|
||||
{ q: '$2^x > 16$ — введи границу', ans: 4, hint: '$2^x > 2^4 \\Rightarrow x > 4$. Граница — $4$.' },
|
||||
{ q: '$\\left(\\dfrac{1}{3}\\right)^x \\ge 9$ — введи границу', ans: -2, hint: '$\\left(1/3\\right)^x \\ge \\left(1/3\\right)^{-2}$. Знак меняется: $x \\le -2$. Граница — $-2$.' },
|
||||
{ q: '$5^x < 1$ — введи границу', ans: 0, hint: '$5^x < 5^0$. Знак сохраняется: $x < 0$. Граница — $0$.' },
|
||||
{ q: '$3^{x-1} \\le 81$ — введи границу', ans: 5, hint: '$3^{x-1} \\le 3^4 \\Rightarrow x - 1 \\le 4 \\Rightarrow x \\le 5$. Граница — $5$.' },
|
||||
{ q: '$\\left(\\dfrac{1}{2}\\right)^x > 0{,}25$ — введи границу', ans: 2, hint: '$\\left(1/2\\right)^x > \\left(1/2\\right)^2$. Знак меняется: $x < 2$. Граница — $2$.' },
|
||||
{ q: '$4^x \\ge 8$ — введи границу', ans: 1.5, hint: '$2^{2x} \\ge 2^3 \\Rightarrow 2x \\ge 3 \\Rightarrow x \\ge 1{,}5$. Граница — $1{,}5$.' },
|
||||
];
|
||||
let i = 0, score = 0;
|
||||
function show(){
|
||||
const qEl = document.getElementById('p6-iv4-q');
|
||||
const iEl = document.getElementById('p6-iv4-i');
|
||||
const sEl = document.getElementById('p6-iv4-s');
|
||||
const fb = document.getElementById('p6-iv4-fb');
|
||||
const ansI = document.getElementById('p6-iv4-ans');
|
||||
if(i >= Q.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: '+score+' / '+Q.length;
|
||||
if(score === Q.length){ addXp(15, 'p6-iv4'); bumpProgress('p6', 25); }
|
||||
else if(score >= 4){ addXp(8, 'p6-iv4'); bumpProgress('p6', 15); }
|
||||
return;
|
||||
}
|
||||
iEl.textContent = (i + 1);
|
||||
sEl.textContent = score;
|
||||
qEl.innerHTML = Q[i].q;
|
||||
ansI.value = '';
|
||||
renderMath(qEl);
|
||||
fb.style.display = 'none';
|
||||
}
|
||||
function go(){
|
||||
if(i >= Q.length) return;
|
||||
const fb = document.getElementById('p6-iv4-fb');
|
||||
const raw = document.getElementById('p6-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('p6-iv4-s').textContent = score;
|
||||
i++;
|
||||
setTimeout(show, 1500);
|
||||
}
|
||||
document.getElementById('p6-iv4-go').addEventListener('click', go);
|
||||
document.getElementById('p6-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); });
|
||||
document.getElementById('p6-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); });
|
||||
show();
|
||||
})();
|
||||
|
||||
wireReadBtn('p6');
|
||||
}
|
||||
|
||||
function buildFinal2(){
|
||||
const box = document.getElementById('final2-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">Ключевая формула: Итоги · боссы главы 2</p>
|
||||
`);
|
||||
html += secNavFor('final2');
|
||||
html += readButton('final2');
|
||||
|
||||
/* Часть А — Шпаргалка главы (3 mini-карточки) */
|
||||
html += `<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-icon theory">${ICONS.theory}</div>
|
||||
<div class="card-title">Шпаргалка главы 2</div>
|
||||
<div class="card-num">Итог</div>
|
||||
</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="#7c3aed" stroke-width="2" style="width:18px;height:18px"><path d="M3 21c4-12 8-18 18-18"/><line x1="3" y1="21" x2="21" y2="21"/></svg>
|
||||
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 4 · Показ. функция</div>
|
||||
</div>
|
||||
<div style="font-size:.95rem">$y = a^x$ ($a > 0$, $a \\ne 1$). $D = \\mathbb{R}$, $E = (0;\\,+\\infty)$. При $a > 1$ — возрастает, при $0 < a < 1$ — убывает. Через $(0;\\,1)$. Асимптота $y = 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="#6d28d9" stroke-width="2" style="width:18px;height:18px"><path d="M5 12h14"/><polyline points="12 5 19 12 12 19"/></svg>
|
||||
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 5 · Показ. уравнения</div>
|
||||
</div>
|
||||
<div style="font-size:.95rem">$a^{f(x)} = a^{g(x)} \\Leftrightarrow f(x) = g(x)$. Четыре метода: одинаковое основание, замена переменной ($t = a^x > 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="#f59e0b" stroke-width="2" style="width:18px;height:18px"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="18" x2="21" y2="18"/><polyline points="7 10 3 14 7 18"/></svg>
|
||||
<div style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 6 · Показ. неравенства</div>
|
||||
</div>
|
||||
<div style="font-size:.95rem">При $a > 1$ знак <b>сохраняется</b>, при $0 < a < 1$ — <b>меняется</b>. Замена $t = a^x > 0$ — обязательно учитывать положительность.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
/* Часть Б — 5 боссов (intro) */
|
||||
html += `<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-icon rule">${ICONS.rule}</div>
|
||||
<div class="card-title">Боссы главы 2</div>
|
||||
<div class="card-num">5</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>5 интегрированных задач по всей главе. За каждого побеждённого босса: <b>+10 XP, +18% к прогрессу</b>. Победишь всех — ачивка <b>«Магистр показательной функции»</b> и <b>+50 XP бонус</b>.</p>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
html += '<div id="ch2-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="ch2-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="ch2-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="ch2-boss-overall-fill" style="height:100%;width:0%;background:linear-gradient(90deg,#7c3aed,#a78bfa);transition:width .35s"></div>
|
||||
</div>
|
||||
<div id="ch2-final-reward" style="margin-top:14px;display:none;padding:14px;background:var(--card);border-radius:11px;border:2px solid #7c3aed">
|
||||
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:#6d28d9;font-size:1.05rem;margin-bottom:6px">Магистр показательной функции</div>
|
||||
<div style="font-size:.92rem;margin-bottom:10px">Глава 2 пройдена! Все 5 боссов повержены. +50 XP бонус.</div>
|
||||
<a class="btn primary" href="/textbook/algebra-11-ch3" style="text-decoration:none">Дальше: Глава 3 <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
html += secNav('p6', null);
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
wireReadBtn('final2');
|
||||
|
||||
/* Боссы */
|
||||
const BOSSES = [
|
||||
{
|
||||
n:1, color:'#10b981',
|
||||
title:'Циклоп Показательной',
|
||||
tag:'§ 4',
|
||||
q:'Найдите значение функции $y = 3^x$ при $x = -2$. Введите ответ числом (допуск $\\pm 0{,}05$).',
|
||||
ans:1/9,
|
||||
hint:'$3^{-2} = \\dfrac{1}{3^2} = \\dfrac{1}{9} \\approx 0{,}11$.'
|
||||
},
|
||||
{
|
||||
n:2, color:'#0891b2',
|
||||
title:'Минотавр Уравнений',
|
||||
tag:'§ 5',
|
||||
q:'Решите уравнение $5^{2x-1} = 125$. Введите $x$.',
|
||||
ans:2,
|
||||
hint:'$125 = 5^3$, поэтому $2x - 1 = 3 \\Rightarrow x = 2$.'
|
||||
},
|
||||
{
|
||||
n:3, color:'#7c3aed',
|
||||
title:'Гарпия Неравенств',
|
||||
tag:'§ 6',
|
||||
q:'Решите $\\left(\\dfrac{1}{2}\\right)^x > 32$. Введите <b>наибольшее целое</b> $x$.',
|
||||
ans:-6,
|
||||
hint:'$\\left(1/2\\right)^x > \\left(1/2\\right)^{-5}$. Знак меняется: $x < -5$. Наибольшее целое — $-6$.'
|
||||
},
|
||||
{
|
||||
n:4, color:'#dc2626',
|
||||
title:'Дракон Замены',
|
||||
tag:'§ 5 + § 6',
|
||||
q:'Найдите <b>сумму корней</b> уравнения $9^x - 10 \\cdot 3^x + 9 = 0$.',
|
||||
ans:2,
|
||||
hint:'Замена $t = 3^x$: $t^2 - 10t + 9 = 0 \\Rightarrow t = 1$ или $t = 9$. $x = 0$ и $x = 2$. Сумма — $2$.'
|
||||
},
|
||||
{
|
||||
n:5, color:'#f59e0b',
|
||||
title:'Мастер Показательной',
|
||||
tag:'§ 4 + § 5 + § 6',
|
||||
q:'При каком $a$ функция $y = (3a - 5)^x$ убывает на $\\mathbb{R}$? Найдите <b>сумму целых значений</b> $a$ из найденного интервала.',
|
||||
ans:0,
|
||||
hint:'Убывает при $0 < 3a - 5 < 1$, то есть $\\dfrac{5}{3} < a < 2$. Целых $a$ в этом интервале нет — сумма равна $0$.'
|
||||
},
|
||||
];
|
||||
|
||||
const cont = document.getElementById('ch2-bosses-container');
|
||||
const STATE_KEY = 'algebra11_ch2_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="boss2-'+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="boss2-'+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="boss2-'+b.n+'-ans" class="tinp" style="width:120px;text-align:center" step="0.01" placeholder="число">'
|
||||
+'<button class="btn primary" id="boss2-'+b.n+'-go" style="background:'+b.color+';border-color:'+b.color+'">Атаковать</button>'
|
||||
+'<button class="btn" id="boss2-'+b.n+'-hint">Подсказка</button>'
|
||||
+'</div>'
|
||||
+'<div class="feedback" id="boss2-'+b.n+'-fb"></div>'
|
||||
+'</div>';
|
||||
}).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))';
|
||||
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('boss2-'+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-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))';
|
||||
card.classList.add('glow','pulse');
|
||||
setTimeout(()=>card.classList.remove('pulse'), 900);
|
||||
refreshOverall();
|
||||
} else {
|
||||
feedback(fb, false, '✗ Промах. Попробуй ещё. Подсказка доступна.');
|
||||
}
|
||||
});
|
||||
hintBtn.addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('boss2-'+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 ===== */
|
||||
|
||||
Reference in New Issue
Block a user