feat(algebra-8 ch3): Wave 3 — §17 (метод интервалов) + §18 (дробно-рац.)
§ 17 «Квадратные неравенства. Метод интервалов»: - Теория: парабола, метод интервалов, правило знаков - INTERACT 1: SVG-парабола + слайдеры a, b, c с цветовой раскраской на оси: зелёные зоны = выражение > 0, красные = < 0. Корни как точки. Внизу — текстовый анализ (D, корни, решение для >0 и <0). - INTERACT 2: Пошаговый решатель — D, корни, знаки, ответ (4-5 шагов с обработкой D<0 и D=0) - INTERACT 3: Тренажёр 6 квадратных (multiple-choice) - INTERACT 4: Drag-сопоставление (a, D, направление неравенства) → тип ответа: вне корней / между / R / пусто - INTERACT 5: «Где плюс, где минус?» — кликаем по 3 интервалам параболы x²−4x+3, ставим знаки. Победа = +, -, +. § 18 «Дробно-рациональные»: - Теория: f/g ≷ 0, выколотые точки знаменателя, алгоритм - INTERACT 1: Пошаговый решатель (x-a)/(x-b) ≥ 0 с учётом a vs b (включая случай a == b) - INTERACT 2: Тренажёр 6 неравенств (multiple-choice) - INTERACT 3: Найди ОДЗ — 5 выражений, вводим запрещённые точки - INTERACT 4: Drag «закрашена/выколота» — 8 ситуаций
This commit is contained in:
@@ -1738,8 +1738,551 @@ function buildP16(){
|
||||
refresh();
|
||||
})();
|
||||
}
|
||||
function buildP17stub(){ document.getElementById('p17-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 17 — Квадратные неравенства. Метод интервалов</b><br><br>Будет в Wave 3.</p></div></div>${secNav('p16','p18')}`; }
|
||||
function buildP18stub(){ document.getElementById('p18-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 18 — Дробно-рациональные неравенства</b><br><br>Будет в Wave 3.</p></div></div>${secNav('p17','final3')}`; }
|
||||
function buildP17stub(){ buildP17(); }
|
||||
function buildP18stub(){ buildP18(); }
|
||||
|
||||
/* ============================================================
|
||||
§ 17 — КВАДРАТНЫЕ НЕРАВЕНСТВА. МЕТОД ИНТЕРВАЛОВ
|
||||
============================================================ */
|
||||
function buildP17(){
|
||||
const box = document.getElementById('p17-body');
|
||||
let html = '';
|
||||
|
||||
html += makeCard('repeat','Повторение',null,`
|
||||
<ul style="margin-left:18px;line-height:1.7">
|
||||
<li>Квадратное уравнение $ax^2 + bx + c = 0$ (Глава 2).</li>
|
||||
<li>Дискриминант $D = b^2 - 4ac$, корни $x_{1,2} = \\dfrac{-b \\pm \\sqrt{D}}{2a}$.</li>
|
||||
<li>Парабола: при $a > 0$ ветви вверх, при $a < 0$ — вниз.</li>
|
||||
</ul>`);
|
||||
|
||||
html += makeCard('theory','Что такое квадратное неравенство','17.1',`
|
||||
<p><b>Определение.</b> Неравенство вида $ax^2 + bx + c \\gtrless 0$, $a \\neq 0$.</p>
|
||||
<p style="margin-top:6px"><b>Геометрический смысл:</b> найти, где парабола $y = ax^2 + bx + c$ <i>выше</i> или <i>ниже</i> оси OX (в зависимости от знака неравенства).</p>`);
|
||||
|
||||
html += makeCard('algo','Метод интервалов','17.2',`
|
||||
<ol style="margin-left:18px;line-height:1.9">
|
||||
<li>Найти корни уравнения $ax^2 + bx + c = 0$.</li>
|
||||
<li>Если $D < 0$ — знак выражения постоянен (совпадает со знаком $a$).</li>
|
||||
<li>Если $D \\geq 0$ — отметить корни на числовой прямой.</li>
|
||||
<li>Определить знак выражения на каждом интервале (можно подставить пробную точку).</li>
|
||||
<li>Выбрать интервалы, удовлетворяющие неравенству.</li>
|
||||
</ol>
|
||||
<p style="margin-top:8px"><b>Правило знаков для квадратного:</b> при $a > 0$ — между корнями знак минус, вне — плюс. При $a < 0$ — наоборот.</p>`);
|
||||
|
||||
html += makeCard('example','Пример',null,`
|
||||
<p><b>Решить</b> $x^2 - 5x + 6 > 0$.</p>
|
||||
<p>Корни: $x_1 = 2$, $x_2 = 3$. $a = 1 > 0$ — парабола вверх.</p>
|
||||
<p>Знаки: $+$ при $x<2$, $-$ при $2<x<3$, $+$ при $x>3$.</p>
|
||||
<p><b>Ответ:</b> $x \\in (-\\infty;\\,2) \\cup (3;\\,+\\infty)$.</p>`);
|
||||
|
||||
/* INT 1 — Парабола + закраска */
|
||||
html += widget('Парабола и знак','INTERACT 1','Двигай $a, b, c$. Парабола показывает, где выражение положительно (зелёное) и отрицательно (красное).',`
|
||||
<div class="sliders">
|
||||
<label>$a$ = <b id="p17p-a-val">1</b><input type="range" min="-3" max="3" step="0.5" value="1" id="p17p-a"></label>
|
||||
<label>$b$ = <b id="p17p-b-val">-1</b><input type="range" min="-6" max="6" step="0.5" value="-1" id="p17p-b"></label>
|
||||
<label>$c$ = <b id="p17p-c-val">-6</b><input type="range" min="-8" max="8" step="0.5" value="-6" id="p17p-c"></label>
|
||||
</div>
|
||||
<svg id="p17p-svg" viewBox="-10 -10 240 180" style="width:100%;max-width:520px;display:block;margin:10px auto;background:#fafafa;border:1px solid var(--border);border-radius:10px"></svg>
|
||||
<div id="p17p-out" style="padding:12px;background:var(--sec-acc-soft);border-radius:10px;line-height:1.7"></div>`);
|
||||
|
||||
/* INT 2 — Шаговый решатель */
|
||||
html += widget('Метод интервалов: шаг за шагом','INTERACT 2','Введите $a, b, c$ для $ax^2 + bx + c \\geq 0$ и нажимайте «Дальше».',`
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;justify-content:center;margin-bottom:10px">
|
||||
<label>$a$ = <input type="number" id="p17s-a" value="1" class="tinp" style="width:60px"></label>
|
||||
<label>$b$ = <input type="number" id="p17s-b" value="-5" class="tinp" style="width:60px"></label>
|
||||
<label>$c$ = <input type="number" id="p17s-c" value="6" class="tinp" style="width:60px"></label>
|
||||
<button class="btn primary" id="p17s-go">Старт</button>
|
||||
<button class="btn" id="p17s-next" style="display:none">Дальше</button>
|
||||
<button class="btn" id="p17s-reset" style="display:none">Сначала</button>
|
||||
</div>
|
||||
<div id="p17s-stage" style="padding:14px;background:var(--card-soft);border-radius:10px;min-height:80px"></div>`);
|
||||
|
||||
/* INT 3 — Тренажёр */
|
||||
html += widget('Тренажёр квадратных неравенств','INTERACT 3','Решите неравенство и выберите правильный промежуток-ответ.',`
|
||||
<div class="score-display"><span>Задача <b id="p17t-i">1</b> / 6</span><span>Очки: <b id="p17t-score">0</b></span></div>
|
||||
<div id="p17t-task" style="font-size:1.2rem;text-align:center;padding:16px;background:var(--sec-acc-soft);border-radius:10px;margin-bottom:10px"></div>
|
||||
<div id="p17t-opts" style="display:flex;flex-direction:column;gap:6px"></div>
|
||||
<div class="feedback" id="p17t-fb" style="display:none;margin-top:10px"></div>
|
||||
<button class="btn primary" id="p17t-start" style="margin-top:10px">Начать</button>`);
|
||||
|
||||
/* INT 4 — Drag: парабола ↔ ответ */
|
||||
html += widget('Сопоставь параболу и неравенство','INTERACT 4','По описанию ситуации (направление ветвей + расположение корней) подбери решение неравенства $\\geq 0$.',`
|
||||
${DND_HINT_HTML}
|
||||
<div id="p17d-pool"></div>
|
||||
<div class="drop-row" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px">
|
||||
<div class="drop-box"><h5>$(-\\infty; x_1] \\cup [x_2; +\\infty)$</h5><div class="drop-items" data-cat="out"></div></div>
|
||||
<div class="drop-box"><h5>$[x_1; x_2]$</h5><div class="drop-items" data-cat="in"></div></div>
|
||||
<div class="drop-box"><h5>$\\mathbb{R}$ (все числа)</h5><div class="drop-items" data-cat="all"></div></div>
|
||||
<div class="drop-box"><h5>$\\emptyset$ (нет решений)</h5><div class="drop-items" data-cat="none"></div></div>
|
||||
</div>
|
||||
<div class="actions"><button class="btn primary" id="p17d-check">Проверить</button><button class="btn" id="p17d-reset">Сначала</button></div>
|
||||
<div class="feedback" id="p17d-fb" style="display:none"></div>`);
|
||||
|
||||
/* INT 5 — Знак между / вне корней */
|
||||
html += widget('Где плюс, где минус?','INTERACT 5','Дана парабола. Кликни на интервал — раскрась знак.',`
|
||||
<p style="margin-bottom:10px">Пусть $y = x^2 - 4x + 3$. Корни: $x_1 = 1$, $x_2 = 3$. Кликни по каждому интервалу и поставь знак.</p>
|
||||
<div id="p17z-line" style="background:var(--card);border:1px solid var(--border);border-radius:8px;padding:12px"></div>
|
||||
<div class="feedback" id="p17z-fb" style="display:none;margin-top:10px"></div>`);
|
||||
|
||||
html += makeCard('class','Класс — решите',null,`
|
||||
<ol style="margin-left:18px;line-height:1.8">
|
||||
<li>$x^2 - 6x + 5 \\leq 0$</li>
|
||||
<li>$-x^2 + 4x - 3 > 0$</li>
|
||||
<li>$x^2 + 2x + 5 > 0$ (без корней — особый случай)</li>
|
||||
<li>$4x^2 - 9 \\geq 0$</li>
|
||||
</ol>`);
|
||||
|
||||
html += makeCard('home','Домашка',null,`
|
||||
<ol style="margin-left:18px;line-height:1.8">
|
||||
<li>$x^2 - 7x + 10 < 0$</li>
|
||||
<li>$3x^2 + 2x - 1 \\geq 0$</li>
|
||||
<li>$x^2 + 1 \\leq 0$ (особый случай)</li>
|
||||
<li>При каких $m$ неравенство $x^2 + 6x + m > 0$ верно для всех $x$?</li>
|
||||
</ol>`);
|
||||
|
||||
html += secNav('p16', 'p18');
|
||||
box.innerHTML = html;
|
||||
if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
|
||||
|
||||
/* INIT 1 — Парабола */
|
||||
(function(){
|
||||
const aE = document.getElementById('p17p-a'), bE = document.getElementById('p17p-b'), cE = document.getElementById('p17p-c');
|
||||
const svg = document.getElementById('p17p-svg'), out = document.getElementById('p17p-out');
|
||||
let done = false;
|
||||
const W = 220, H = 160, x0 = W/2, y0 = H/2, sx = 14, sy = 14;
|
||||
function refresh(){
|
||||
const a = +aE.value, b = +bE.value, c = +cE.value;
|
||||
document.getElementById('p17p-a-val').textContent = a;
|
||||
document.getElementById('p17p-b-val').textContent = b;
|
||||
document.getElementById('p17p-c-val').textContent = c;
|
||||
let path = '';
|
||||
for(let i = 0; i <= 240; i++){
|
||||
const x = -W/(2*sx) + i * (W/sx) / 240;
|
||||
const y = a*x*x + b*x + c;
|
||||
const cx = x0 + x*sx, cy = y0 - y*sy;
|
||||
path += (i === 0 ? 'M' : 'L') + cx.toFixed(2) + ',' + cy.toFixed(2) + ' ';
|
||||
}
|
||||
const D = b*b - 4*a*c;
|
||||
const xs = D >= 0 ? [(-b - Math.sqrt(D))/(2*a), (-b + Math.sqrt(D))/(2*a)].sort((p,q)=>p-q) : [];
|
||||
// фон зон
|
||||
let s = '';
|
||||
if(a !== 0){
|
||||
if(D > 0){
|
||||
// полосы зелёный/красный на оси
|
||||
const x1 = x0 + xs[0]*sx, x2 = x0 + xs[1]*sx;
|
||||
if(a > 0){
|
||||
s += '<rect x="0" y="' + (y0-3) + '" width="' + x1 + '" height="6" fill="#10b981" opacity="0.35"/>';
|
||||
s += '<rect x="' + x1 + '" y="' + (y0-3) + '" width="' + (x2-x1) + '" height="6" fill="#ef4444" opacity="0.35"/>';
|
||||
s += '<rect x="' + x2 + '" y="' + (y0-3) + '" width="' + (W-x2) + '" height="6" fill="#10b981" opacity="0.35"/>';
|
||||
} else {
|
||||
s += '<rect x="0" y="' + (y0-3) + '" width="' + x1 + '" height="6" fill="#ef4444" opacity="0.35"/>';
|
||||
s += '<rect x="' + x1 + '" y="' + (y0-3) + '" width="' + (x2-x1) + '" height="6" fill="#10b981" opacity="0.35"/>';
|
||||
s += '<rect x="' + x2 + '" y="' + (y0-3) + '" width="' + (W-x2) + '" height="6" fill="#ef4444" opacity="0.35"/>';
|
||||
}
|
||||
} else {
|
||||
s += '<rect x="0" y="' + (y0-3) + '" width="' + W + '" height="6" fill="' + (a*c >= 0 ? '#10b981' : '#ef4444') + '" opacity="0.35"/>';
|
||||
}
|
||||
}
|
||||
s += '<line x1="0" y1="' + y0 + '" x2="' + W + '" y2="' + y0 + '" stroke="#94a3b8" stroke-width="0.8"/>';
|
||||
s += '<line x1="' + x0 + '" y1="0" x2="' + x0 + '" y2="' + H + '" stroke="#94a3b8" stroke-width="0.8"/>';
|
||||
s += '<path d="' + path + '" fill="none" stroke="#6366f1" stroke-width="2"/>';
|
||||
xs.forEach(r => { s += '<circle cx="' + (x0 + r*sx).toFixed(2) + '" cy="' + y0 + '" r="4" fill="#6366f1"/>'; });
|
||||
svg.innerHTML = s;
|
||||
let info = '<div><b>$D$ = ' + D.toFixed(2) + '</b></div>';
|
||||
if(D > 0){
|
||||
info += '<div>Корни: $x_1 = ' + fmt(xs[0]) + ',\\ x_2 = ' + fmt(xs[1]) + '$</div>';
|
||||
if(a > 0) info += '<div><b>$ax^2+bx+c > 0$:</b> $x < ' + fmt(xs[0]) + '$ или $x > ' + fmt(xs[1]) + '$</div><div><b>$ax^2+bx+c < 0$:</b> $' + fmt(xs[0]) + ' < x < ' + fmt(xs[1]) + '$</div>';
|
||||
else info += '<div><b>$ax^2+bx+c > 0$:</b> $' + fmt(xs[0]) + ' < x < ' + fmt(xs[1]) + '$</div><div><b>$ax^2+bx+c < 0$:</b> $x < ' + fmt(xs[0]) + '$ или $x > ' + fmt(xs[1]) + '$</div>';
|
||||
} else if(D === 0){
|
||||
const r = -b/(2*a);
|
||||
info += '<div>Один корень: $x = ' + fmt(r) + '$</div>';
|
||||
info += '<div>Парабола касается оси. Знак — везде ' + (a > 0 ? 'положителен (кроме точки $x = ' + fmt(r) + '$)' : 'отрицателен') + '.</div>';
|
||||
} else {
|
||||
info += '<div>Корней нет. Парабола ' + (a > 0 ? 'выше' : 'ниже') + ' оси.</div>';
|
||||
info += '<div>Знак выражения везде ' + (a > 0 ? 'положителен' : 'отрицателен') + '.</div>';
|
||||
}
|
||||
out.innerHTML = info; renderMath(out);
|
||||
if(!done){ done = true; setTimeout(()=>{ achievement('p17_parab'); bumpProgress('p17', 14); }, 300); }
|
||||
}
|
||||
[aE,bE,cE].forEach(e => e.addEventListener('input', refresh));
|
||||
refresh();
|
||||
})();
|
||||
|
||||
/* INIT 2 — Метод интервалов шаговый */
|
||||
(function(){
|
||||
const stage = document.getElementById('p17s-stage');
|
||||
const goBtn = document.getElementById('p17s-go'), nextBtn = document.getElementById('p17s-next'), resetBtn = document.getElementById('p17s-reset');
|
||||
let steps = [], idx = 0, awarded = false;
|
||||
function build(a, b, c){
|
||||
const arr = [];
|
||||
arr.push('<b>Дано:</b> $' + a + 'x^2 ' + (b >= 0 ? '+ ' + b : '- ' + Math.abs(b)) + 'x ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)) + ' \\geq 0$');
|
||||
const D = b*b - 4*a*c;
|
||||
arr.push('<b>Шаг 1.</b> $D = b^2 - 4ac = ' + (b*b) + ' - ' + (4*a*c) + ' = ' + D + '$');
|
||||
if(D < 0){
|
||||
arr.push('<b>Шаг 2.</b> $D < 0$ — корней нет. Знак совпадает со знаком $a = ' + a + '$.');
|
||||
if(a > 0) arr.push('<b>Шаг 3.</b> $a > 0$ — выражение всегда $> 0$, тем более $\\geq 0$. Ответ: $\\mathbb{R}$.');
|
||||
else arr.push('<b>Шаг 3.</b> $a < 0$ — выражение всегда $< 0$, ни одна точка не удовлетворяет $\\geq 0$. Ответ: $\\emptyset$.');
|
||||
} else if(D === 0){
|
||||
const r = -b/(2*a);
|
||||
arr.push('<b>Шаг 2.</b> $D = 0$ — один корень: $x = ' + fmt(r) + '$.');
|
||||
if(a > 0) arr.push('<b>Шаг 3.</b> $a > 0$ — выражение всюду $\\geq 0$, равно нулю только в $x = ' + fmt(r) + '$. Ответ: $\\mathbb{R}$.');
|
||||
else arr.push('<b>Шаг 3.</b> $a < 0$ — выражение всюду $\\leq 0$, равно нулю только в $x = ' + fmt(r) + '$. Ответ: $\\{' + fmt(r) + '\\}$.');
|
||||
} else {
|
||||
const x1 = (-b - Math.sqrt(D))/(2*a), x2 = (-b + Math.sqrt(D))/(2*a);
|
||||
const lo = Math.min(x1, x2), hi = Math.max(x1, x2);
|
||||
arr.push('<b>Шаг 2.</b> Корни: $x_1 = ' + fmt(lo) + ',\\ x_2 = ' + fmt(hi) + '$');
|
||||
if(a > 0){
|
||||
arr.push('<b>Шаг 3.</b> $a > 0$ — парабола вверх. Знак: $+$ при $x < x_1$, $-$ между корнями, $+$ при $x > x_2$.');
|
||||
arr.push('<b>Ответ:</b> $x \\in (-\\infty;\\,' + fmt(lo) + '] \\cup [' + fmt(hi) + ';\\,+\\infty)$');
|
||||
} else {
|
||||
arr.push('<b>Шаг 3.</b> $a < 0$ — парабола вниз. Знак: $-$ вне, $+$ между корнями.');
|
||||
arr.push('<b>Ответ:</b> $x \\in [' + fmt(lo) + ';\\,' + fmt(hi) + ']$');
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
function render(){
|
||||
stage.innerHTML = steps.slice(0, idx + 1).map(s => `<div style="margin:6px 0;padding:9px 12px;background:var(--card);border-left:3px solid var(--sec-acc);border-radius:7px;animation:fadeIn .3s ease">${s}</div>`).join('');
|
||||
renderMath(stage);
|
||||
if(idx >= steps.length - 1){
|
||||
nextBtn.disabled = true; nextBtn.textContent = 'Готово';
|
||||
if(!awarded){ awarded = true; achievement('p17_solver'); bumpProgress('p17', 16); confetti(); }
|
||||
} else { nextBtn.disabled = false; nextBtn.textContent = 'Дальше (' + (idx + 1) + '/' + steps.length + ')'; }
|
||||
}
|
||||
goBtn.addEventListener('click', ()=>{
|
||||
const a = +document.getElementById('p17s-a').value, b = +document.getElementById('p17s-b').value, c = +document.getElementById('p17s-c').value;
|
||||
if(!a){ stage.innerHTML = '<p>$a \\neq 0$</p>'; renderMath(stage); return; }
|
||||
steps = build(a, b, c); idx = 0; awarded = false;
|
||||
goBtn.style.display = 'none'; nextBtn.style.display = ''; resetBtn.style.display = '';
|
||||
render();
|
||||
});
|
||||
nextBtn.addEventListener('click', ()=>{ if(idx < steps.length - 1){ idx++; render(); } });
|
||||
resetBtn.addEventListener('click', ()=>{ idx = 0; stage.innerHTML = ''; goBtn.style.display = ''; nextBtn.style.display = 'none'; resetBtn.style.display = 'none'; });
|
||||
})();
|
||||
|
||||
/* INIT 3 — Тренажёр */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{ q:'$x^2 - 5x + 6 > 0$', opts:['$(-\\infty;\\,2) \\cup (3;\\,+\\infty)$','$[2;\\,3]$','$(2;\\,3)$','$\\mathbb{R}$'], ok:0 },
|
||||
{ q:'$x^2 - 4x + 3 \\leq 0$', opts:['$[1;\\,3]$','$(-\\infty;\\,1] \\cup [3;\\,+\\infty)$','$(1;\\,3)$','$\\emptyset$'], ok:0 },
|
||||
{ q:'$x^2 + 1 > 0$', opts:['$\\mathbb{R}$','$\\emptyset$','$x \\neq 0$','$x > 0$'], ok:0 },
|
||||
{ q:'$x^2 + 2x + 5 < 0$', opts:['$\\emptyset$','$\\mathbb{R}$','$(-1;\\,1)$','$x < -1$'], ok:0 },
|
||||
{ q:'$-x^2 + 4 \\geq 0$', opts:['$[-2;\\,2]$','$(-\\infty;\\,-2] \\cup [2;\\,+\\infty)$','$(-2;\\,2)$','$\\mathbb{R}$'], ok:0 },
|
||||
{ q:'$x^2 - 9 < 0$', opts:['$(-3;\\,3)$','$[-3;\\,3]$','$(-\\infty;\\,-3) \\cup (3;\\,+\\infty)$','$\\emptyset$'], ok:0 },
|
||||
];
|
||||
let cur = null, i = 1, score = 0, shuffled = [];
|
||||
function show(){
|
||||
cur = shuffled[i-1];
|
||||
document.getElementById('p17t-i').textContent = i;
|
||||
document.getElementById('p17t-task').innerHTML = '$' + cur.q + '$';
|
||||
renderMath(document.getElementById('p17t-task'));
|
||||
const opts = document.getElementById('p17t-opts'); opts.innerHTML = '';
|
||||
cur.opts.forEach((o, k)=>{
|
||||
const b = document.createElement('button');
|
||||
b.className = 'btn'; b.innerHTML = o; b.style.cssText = 'text-align:left';
|
||||
b.addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p17t-fb'); fb.style.display = 'block';
|
||||
if(k === cur.ok){ score++; b.classList.add('ok'); feedback(fb, true, '✓'); }
|
||||
else { b.classList.add('fail'); feedback(fb, false, 'Не то.'); }
|
||||
document.getElementById('p17t-score').textContent = score;
|
||||
if(i >= shuffled.length){ setTimeout(()=>{ feedback(fb, score >= 4, 'Итог: ' + score + '/' + shuffled.length); if(score >= 4){ achievement('p17_train'); bumpProgress('p17', 16); confetti(); } }, 700); }
|
||||
else { i++; setTimeout(show, 900); }
|
||||
});
|
||||
opts.appendChild(b);
|
||||
});
|
||||
renderMath(opts);
|
||||
document.getElementById('p17t-fb').style.display = 'none';
|
||||
}
|
||||
document.getElementById('p17t-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p17t-score').textContent = 0; shuffled = [...tasks].sort(()=>Math.random()-0.5); show(); });
|
||||
})();
|
||||
|
||||
/* INIT 4 — Drag парабола ↔ ответ */
|
||||
(function(){
|
||||
const items = [
|
||||
{ id:1, html:'$a > 0$, есть 2 корня, неравенство $\\geq 0$', cat:'out' },
|
||||
{ id:2, html:'$a > 0$, есть 2 корня, неравенство $\\leq 0$', cat:'in' },
|
||||
{ id:3, html:'$a < 0$, есть 2 корня, неравенство $\\geq 0$', cat:'in' },
|
||||
{ id:4, html:'$a > 0$, $D < 0$, неравенство $\\geq 0$', cat:'all' },
|
||||
{ id:5, html:'$a > 0$, $D < 0$, неравенство $\\leq 0$', cat:'none' },
|
||||
{ id:6, html:'$a < 0$, $D < 0$, неравенство $\\geq 0$', cat:'none' },
|
||||
{ id:7, html:'$a < 0$, $D < 0$, неравенство $\\leq 0$', cat:'all' },
|
||||
{ id:8, html:'$a < 0$, есть 2 корня, неравенство $\\leq 0$', cat:'out' },
|
||||
];
|
||||
const sorter = setupSorter({ poolId:'p17d-pool', cats:['out','in','all','none'], items, scopeSelector:'#p17-body', columnLayout:true });
|
||||
document.getElementById('p17d-check').addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p17d-fb'); fb.style.display = 'block';
|
||||
if(Object.keys(sorter.placed).length < items.length){ feedback(fb, false, '⚠ Разложите все.'); return; }
|
||||
let ok = 0; items.forEach(it=>{ if(sorter.placed[it.id] === it.cat) ok++; });
|
||||
if(ok === items.length){ feedback(fb, true, '✓ Все верно!'); achievement('p17_drag'); bumpProgress('p17', 14); confetti(); }
|
||||
else feedback(fb, false, 'Верно ' + ok + ' из ' + items.length);
|
||||
});
|
||||
document.getElementById('p17d-reset').addEventListener('click', ()=>{ sorter.reset(); document.getElementById('p17d-fb').style.display='none'; });
|
||||
})();
|
||||
|
||||
/* INIT 5 — Знаки на интервалах (клик) */
|
||||
(function(){
|
||||
// 3 интервала: (-inf, 1), (1, 3), (3, inf). Должны быть: +, -, +.
|
||||
const correct = ['+','-','+'];
|
||||
const labels = ['$x < 1$', '$1 < x < 3$', '$x > 3$'];
|
||||
const lineE = document.getElementById('p17z-line');
|
||||
function build(){
|
||||
let s = '<div style="display:flex;gap:8px;flex-wrap:wrap;justify-content:center;align-items:center;font-size:1.1rem">';
|
||||
s += '<span>$-\\infty$</span>';
|
||||
[0, 1, 2].forEach(i => {
|
||||
s += '<button class="btn p17z-int" data-i="' + i + '" data-sign="" style="min-width:90px">' + labels[i] + '<br><span class="sg">?</span></button>';
|
||||
if(i < 2) s += '<span style="font-family:JetBrains Mono,monospace;font-size:1.2rem;color:var(--sec-acc-d)">●' + (i === 0 ? ' 1 ●' : ' 3 ●').replace('●','') + '</span>';
|
||||
});
|
||||
s += '<span>$+\\infty$</span></div>';
|
||||
lineE.innerHTML = s;
|
||||
renderMath(lineE);
|
||||
document.querySelectorAll('.p17z-int').forEach(btn => {
|
||||
btn.addEventListener('click', ()=>{
|
||||
const cur = btn.dataset.sign;
|
||||
const next = cur === '' ? '+' : cur === '+' ? '-' : '';
|
||||
btn.dataset.sign = next;
|
||||
btn.querySelector('.sg').textContent = next || '?';
|
||||
btn.style.background = next === '+' ? 'rgba(16,185,129,.2)' : next === '-' ? 'rgba(239,68,68,.2)' : '';
|
||||
checkAll();
|
||||
});
|
||||
});
|
||||
}
|
||||
function checkAll(){
|
||||
const all = [...document.querySelectorAll('.p17z-int')];
|
||||
const got = all.map(b => b.dataset.sign);
|
||||
if(got.every((s, i) => s === correct[i])){
|
||||
const fb = document.getElementById('p17z-fb'); fb.style.display = 'block';
|
||||
feedback(fb, true, '✓ Точно! Между корнями знак минус (так как $a > 0$).');
|
||||
achievement('p17_intervals'); bumpProgress('p17', 14); confetti();
|
||||
}
|
||||
}
|
||||
build();
|
||||
})();
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
§ 18 — ДРОБНО-РАЦИОНАЛЬНЫЕ НЕРАВЕНСТВА
|
||||
============================================================ */
|
||||
function buildP18(){
|
||||
const box = document.getElementById('p18-body');
|
||||
let html = '';
|
||||
|
||||
html += makeCard('repeat','Повторение',null,`
|
||||
<ul style="margin-left:18px;line-height:1.7">
|
||||
<li>Метод интервалов из § 17 — корни, знаки на интервалах.</li>
|
||||
<li>ОДЗ (Глава 2 § 12): знаменатель $\\neq 0$.</li>
|
||||
<li>$\\dfrac{a}{b}$ имеет тот же знак, что и $a \\cdot b$.</li>
|
||||
</ul>`);
|
||||
|
||||
html += makeCard('theory','Что такое дробно-рациональное неравенство','18.1',`
|
||||
<p><b>Дробно-рациональное</b> — неравенство, в котором есть дроби с переменной в знаменателе:</p>
|
||||
<div style="background:var(--sec-acc-soft);border-radius:10px;padding:10px;margin:8px 0;text-align:center;font-size:1.1rem">$$\\dfrac{f(x)}{g(x)} \\gtrless 0$$</div>
|
||||
<p><b>Ключевая идея:</b> знак дроби определяется произведением знаков числителя и знаменателя. Метод интервалов работает, но точки, где знаменатель $= 0$, всегда <b>выколотые</b> (не входят в ОДЗ).</p>`);
|
||||
|
||||
html += makeCard('algo','Алгоритм','18.2',`
|
||||
<ol style="margin-left:18px;line-height:1.9">
|
||||
<li>Привести к виду $\\dfrac{f(x)}{g(x)} \\gtrless 0$ (всё в одну часть, общий знаменатель).</li>
|
||||
<li>Найти нули числителя $f(x) = 0$ и знаменателя $g(x) = 0$.</li>
|
||||
<li>Отметить точки на прямой: нули $f$ — закрашены (если знак $\\geq, \\leq$), нули $g$ — всегда выколотые.</li>
|
||||
<li>Определить знак выражения на каждом интервале.</li>
|
||||
<li>Выбрать интервалы, удовлетворяющие неравенству.</li>
|
||||
</ol>`);
|
||||
|
||||
html += makeCard('example','Пример',null,`
|
||||
<p><b>Решим:</b> $\\dfrac{x - 1}{x + 2} \\geq 0$.</p>
|
||||
<p>Нули: числитель $x = 1$ (входит), знаменатель $x = -2$ (выколот).</p>
|
||||
<p>Знаки на интервалах: $(-\\infty;\\,-2)$ — $+$ (минус на минус), $(-2;\\,1)$ — $-$ (плюс на минус), $(1;\\,+\\infty)$ — $+$.</p>
|
||||
<p><b>Ответ:</b> $x \\in (-\\infty;\\,-2) \\cup [1;\\,+\\infty)$.</p>`);
|
||||
|
||||
/* INT 1 — Пошаговый решатель */
|
||||
html += widget('Пошаговый решатель дроби','INTERACT 1','Решаем $\\dfrac{x-a}{x-b} \\geq 0$ пошагово.',`
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;justify-content:center;margin-bottom:10px;font-size:1.05rem">
|
||||
<span>$\\dfrac{x -$</span><input type="number" id="p18s-a" value="1" class="tinp" style="width:55px"><span>$}{x -$</span><input type="number" id="p18s-b" value="-2" class="tinp" style="width:55px"><span>$} \\geq 0$</span>
|
||||
<button class="btn primary" id="p18s-go">Старт</button>
|
||||
<button class="btn" id="p18s-next" style="display:none">Дальше</button>
|
||||
<button class="btn" id="p18s-reset" style="display:none">Сначала</button>
|
||||
</div>
|
||||
<div id="p18s-stage" style="padding:14px;background:var(--card-soft);border-radius:10px;min-height:80px"></div>`);
|
||||
|
||||
/* INT 2 — Тренажёр */
|
||||
html += widget('Тренажёр дробно-рациональных','INTERACT 2','Выбери правильный ответ.',`
|
||||
<div class="score-display"><span>Задача <b id="p18t-i">1</b> / 6</span><span>Очки: <b id="p18t-score">0</b></span></div>
|
||||
<div id="p18t-task" style="font-size:1.2rem;text-align:center;padding:16px;background:var(--sec-acc-soft);border-radius:10px;margin-bottom:10px"></div>
|
||||
<div id="p18t-opts" style="display:flex;flex-direction:column;gap:6px"></div>
|
||||
<div class="feedback" id="p18t-fb" style="display:none;margin-top:10px"></div>
|
||||
<button class="btn primary" id="p18t-start" style="margin-top:10px">Начать</button>`);
|
||||
|
||||
/* INT 3 — Найди ОДЗ */
|
||||
html += widget('Найди ОДЗ','INTERACT 3','По выражению определи запрещённые точки (где знаменатель = 0).',`
|
||||
<div class="score-display"><span>Раунд <b id="p18o-i">1</b> / 5</span><span>Очки: <b id="p18o-score">0</b></span></div>
|
||||
<div id="p18o-task" style="font-size:1.15rem;text-align:center;padding:16px;background:var(--sec-acc-soft);border-radius:10px;margin-bottom:10px"></div>
|
||||
<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap">
|
||||
<input type="text" id="p18o-inp" placeholder="x = ... ; x = ..." class="tinp" style="width:220px">
|
||||
<button class="btn primary" id="p18o-go">Ответ</button>
|
||||
</div>
|
||||
<div class="feedback" id="p18o-fb" style="display:none;margin-top:10px"></div>
|
||||
<button class="btn primary" id="p18o-start" style="margin-top:10px">Начать</button>`);
|
||||
|
||||
/* INT 4 — Drag: закрашена/выколота */
|
||||
html += widget('Закрашена или выколота?','INTERACT 4','Отнеси каждую точку к нужной категории.',`
|
||||
${DND_HINT_HTML}
|
||||
<div id="p18d-pool"></div>
|
||||
<div class="drop-row" style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
|
||||
<div class="drop-box"><h5>Закрашена (входит)</h5><div class="drop-items" data-cat="full"></div></div>
|
||||
<div class="drop-box"><h5>Выколота (не входит)</h5><div class="drop-items" data-cat="open"></div></div>
|
||||
</div>
|
||||
<div class="actions"><button class="btn primary" id="p18d-check">Проверить</button><button class="btn" id="p18d-reset">Сначала</button></div>
|
||||
<div class="feedback" id="p18d-fb" style="display:none"></div>`);
|
||||
|
||||
html += makeCard('class','Класс — решите',null,`
|
||||
<ol style="margin-left:18px;line-height:1.8">
|
||||
<li>$\\dfrac{x - 2}{x + 3} > 0$</li>
|
||||
<li>$\\dfrac{x + 1}{x - 4} \\leq 0$</li>
|
||||
<li>$\\dfrac{x^2 - 4}{x - 1} \\geq 0$</li>
|
||||
</ol>`);
|
||||
|
||||
html += makeCard('home','Домашка',null,`
|
||||
<ol style="margin-left:18px;line-height:1.8">
|
||||
<li>$\\dfrac{x - 3}{x + 1} \\geq 0$</li>
|
||||
<li>$\\dfrac{x + 5}{x^2 - 4} > 0$</li>
|
||||
<li>$\\dfrac{x^2 - 9}{x^2 + 2x - 8} \\leq 0$</li>
|
||||
</ol>`);
|
||||
|
||||
html += secNav('p17', 'final3');
|
||||
box.innerHTML = html;
|
||||
if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
|
||||
|
||||
/* INIT 1 — Пошаговый */
|
||||
(function(){
|
||||
const stage = document.getElementById('p18s-stage');
|
||||
const goBtn = document.getElementById('p18s-go'), nextBtn = document.getElementById('p18s-next'), resetBtn = document.getElementById('p18s-reset');
|
||||
let steps = [], idx = 0, awarded = false;
|
||||
function build(a, b){
|
||||
const arr = [];
|
||||
arr.push('<b>Дано:</b> $\\dfrac{x - (' + a + ')}{x - (' + b + ')} \\geq 0$');
|
||||
arr.push('<b>Шаг 1.</b> Нули числителя: $x = ' + a + '$ (входит, $\\geq$). Нули знаменателя: $x = ' + b + '$ (всегда выколот).');
|
||||
const lo = Math.min(a, b), hi = Math.max(a, b);
|
||||
arr.push('<b>Шаг 2.</b> Отметим на прямой: ' + (a < b ? ('$' + a + '$ (закрашена), $' + b + '$ (выколота)') : ('$' + b + '$ (выколота), $' + a + '$ (закрашена)')) + '.');
|
||||
arr.push('<b>Шаг 3.</b> Знаки: подставим $x = ' + (hi + 1) + '$ — числитель $' + (hi + 1 - a) + ' > 0$, знаменатель $' + (hi + 1 - b) + ' > 0$, дробь $> 0$. Чередуем знаки от правого края: $+,\\ -,\\ +$.');
|
||||
if(a < b){
|
||||
arr.push('<b>Шаг 4.</b> $\\geq 0$ — берём $+$. Это $(-\\infty;\\,' + a + ']$ и $(' + b + ';\\,+\\infty)$.');
|
||||
arr.push('<b>Ответ:</b> $x \\in (-\\infty;\\,' + a + '] \\cup (' + b + ';\\,+\\infty)$');
|
||||
} else if(a > b){
|
||||
arr.push('<b>Шаг 4.</b> $\\geq 0$ — берём $+$. Это $(-\\infty;\\,' + b + ')$ и $[' + a + ';\\,+\\infty)$.');
|
||||
arr.push('<b>Ответ:</b> $x \\in (-\\infty;\\,' + b + ') \\cup [' + a + ';\\,+\\infty)$');
|
||||
} else {
|
||||
arr.push('<b>Шаг 4.</b> $a = b$ — дробь равна 1 везде, кроме $x = ' + a + '$ (выколота). $1 \\geq 0$. Ответ: $x \\neq ' + a + '$.');
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
function render(){
|
||||
stage.innerHTML = steps.slice(0, idx + 1).map(s => `<div style="margin:6px 0;padding:9px 12px;background:var(--card);border-left:3px solid var(--sec-acc);border-radius:7px;animation:fadeIn .3s ease">${s}</div>`).join('');
|
||||
renderMath(stage);
|
||||
if(idx >= steps.length - 1){
|
||||
nextBtn.disabled = true; nextBtn.textContent = 'Готово';
|
||||
if(!awarded){ awarded = true; achievement('p18_solver'); bumpProgress('p18', 16); confetti(); }
|
||||
} else { nextBtn.disabled = false; nextBtn.textContent = 'Дальше (' + (idx + 1) + '/' + steps.length + ')'; }
|
||||
}
|
||||
goBtn.addEventListener('click', ()=>{
|
||||
const a = +document.getElementById('p18s-a').value, b = +document.getElementById('p18s-b').value;
|
||||
steps = build(a, b); idx = 0; awarded = false;
|
||||
goBtn.style.display = 'none'; nextBtn.style.display = ''; resetBtn.style.display = '';
|
||||
render();
|
||||
});
|
||||
nextBtn.addEventListener('click', ()=>{ if(idx < steps.length - 1){ idx++; render(); } });
|
||||
resetBtn.addEventListener('click', ()=>{ idx = 0; stage.innerHTML = ''; goBtn.style.display = ''; nextBtn.style.display = 'none'; resetBtn.style.display = 'none'; });
|
||||
})();
|
||||
|
||||
/* INIT 2 — Тренажёр */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{ q:'$\\dfrac{x - 3}{x + 1} > 0$', opts:['$(-\\infty;\\,-1) \\cup (3;\\,+\\infty)$','$(-1;\\,3)$','$[-1;\\,3]$','$\\emptyset$'], ok:0 },
|
||||
{ q:'$\\dfrac{x + 2}{x - 5} \\leq 0$', opts:['$[-2;\\,5)$','$(-2;\\,5)$','$[-2;\\,5]$','$(-\\infty;\\,-2] \\cup (5;\\,+\\infty)$'], ok:0 },
|
||||
{ q:'$\\dfrac{1}{x - 4} > 0$', opts:['$(4;\\,+\\infty)$','$(-\\infty;\\,4)$','$\\mathbb{R} \\setminus \\{4\\}$','$[4;\\,+\\infty)$'], ok:0 },
|
||||
{ q:'$\\dfrac{x - 1}{x + 3} \\geq 0$', opts:['$(-\\infty;\\,-3) \\cup [1;\\,+\\infty)$','$[-3;\\,1]$','$(-3;\\,1)$','$\\mathbb{R}$'], ok:0 },
|
||||
{ q:'$\\dfrac{x + 6}{x} < 0$', opts:['$(-6;\\,0)$','$[-6;\\,0)$','$(-\\infty;\\,-6)$','$(0;\\,+\\infty)$'], ok:0 },
|
||||
{ q:'$\\dfrac{x - 2}{x - 2} > 0$', opts:['$\\mathbb{R} \\setminus \\{2\\}$','$\\mathbb{R}$','$\\{2\\}$','$\\emptyset$'], ok:0 },
|
||||
];
|
||||
let cur = null, i = 1, score = 0, shuffled = [];
|
||||
function show(){
|
||||
cur = shuffled[i-1];
|
||||
document.getElementById('p18t-i').textContent = i;
|
||||
document.getElementById('p18t-task').innerHTML = '$' + cur.q.replace(/^\$|\$$/g,'') + '$';
|
||||
renderMath(document.getElementById('p18t-task'));
|
||||
const opts = document.getElementById('p18t-opts'); opts.innerHTML = '';
|
||||
cur.opts.forEach((o, k)=>{
|
||||
const b = document.createElement('button');
|
||||
b.className = 'btn'; b.innerHTML = o; b.style.cssText = 'text-align:left';
|
||||
b.addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p18t-fb'); fb.style.display = 'block';
|
||||
if(k === cur.ok){ score++; b.classList.add('ok'); feedback(fb, true, '✓'); }
|
||||
else { b.classList.add('fail'); feedback(fb, false, 'Не то.'); }
|
||||
document.getElementById('p18t-score').textContent = score;
|
||||
if(i >= shuffled.length){ setTimeout(()=>{ feedback(fb, score >= 4, 'Итог: ' + score + '/' + shuffled.length); if(score >= 4){ achievement('p18_intervals'); bumpProgress('p18', 16); confetti(); } }, 700); }
|
||||
else { i++; setTimeout(show, 900); }
|
||||
});
|
||||
opts.appendChild(b);
|
||||
});
|
||||
renderMath(opts);
|
||||
document.getElementById('p18t-fb').style.display = 'none';
|
||||
}
|
||||
document.getElementById('p18t-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p18t-score').textContent = 0; shuffled = [...tasks].sort(()=>Math.random()-0.5); show(); });
|
||||
})();
|
||||
|
||||
/* INIT 3 — ОДЗ */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{ q:'$\\dfrac{x + 1}{x - 3}$', ans:[3] },
|
||||
{ q:'$\\dfrac{x^2 + 1}{x(x - 5)}$', ans:[0, 5] },
|
||||
{ q:'$\\dfrac{1}{x^2 - 4}$', ans:[-2, 2] },
|
||||
{ q:'$\\dfrac{x + 3}{x^2 - 6x + 9}$', ans:[3] },
|
||||
{ q:'$\\dfrac{1}{x} + \\dfrac{1}{x + 1}$', ans:[-1, 0] },
|
||||
];
|
||||
let cur = null, i = 1, score = 0;
|
||||
function show(){
|
||||
cur = tasks[i-1];
|
||||
document.getElementById('p18o-i').textContent = i;
|
||||
document.getElementById('p18o-task').innerHTML = 'Запрещённые точки для ' + cur.q;
|
||||
renderMath(document.getElementById('p18o-task'));
|
||||
document.getElementById('p18o-inp').value = '';
|
||||
document.getElementById('p18o-fb').style.display = 'none';
|
||||
}
|
||||
document.getElementById('p18o-go').addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p18o-fb'); fb.style.display = 'block';
|
||||
const u = document.getElementById('p18o-inp').value.replace(/[xX\s=]/g, '').split(/[;,]+/).filter(Boolean).map(Number).sort((a,b)=>a-b);
|
||||
const a = [...cur.ans].sort((p,q)=>p-q);
|
||||
const ok = u.length === a.length && a.every((v, k) => v === u[k]);
|
||||
if(ok){ score++; feedback(fb, true, '✓'); }
|
||||
else feedback(fb, false, 'Правильно: ' + a.join(', '));
|
||||
document.getElementById('p18o-score').textContent = score;
|
||||
if(i >= tasks.length){ setTimeout(()=>{ feedback(fb, score >= 3, 'Итог: ' + score + '/' + tasks.length); if(score >= 3){ achievement('p18_odz'); bumpProgress('p18', 14); confetti(); } }, 700); }
|
||||
else { i++; setTimeout(show, 900); }
|
||||
});
|
||||
document.getElementById('p18o-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p18o-score').textContent = 0; show(); });
|
||||
})();
|
||||
|
||||
/* INIT 4 — Drag закрашена/выколота */
|
||||
(function(){
|
||||
const items = [
|
||||
{ id:1, html:'нуль числителя при $\\geq 0$', cat:'full' },
|
||||
{ id:2, html:'нуль знаменателя', cat:'open' },
|
||||
{ id:3, html:'нуль числителя при $> 0$ строго', cat:'open' },
|
||||
{ id:4, html:'нуль числителя при $\\leq 0$', cat:'full' },
|
||||
{ id:5, html:'точка вне ОДЗ', cat:'open' },
|
||||
{ id:6, html:'граница в системе с $\\leq$', cat:'full' },
|
||||
{ id:7, html:'граница в системе с $<$', cat:'open' },
|
||||
{ id:8, html:'нуль знаменателя — всегда', cat:'open' },
|
||||
];
|
||||
const sorter = setupSorter({ poolId:'p18d-pool', cats:['full','open'], items, scopeSelector:'#p18-body', columnLayout:true });
|
||||
document.getElementById('p18d-check').addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p18d-fb'); fb.style.display = 'block';
|
||||
if(Object.keys(sorter.placed).length < items.length){ feedback(fb, false, '⚠ Разложите все.'); return; }
|
||||
let ok = 0; items.forEach(it=>{ if(sorter.placed[it.id] === it.cat) ok++; });
|
||||
if(ok === items.length){ feedback(fb, true, '✓ Все верно!'); achievement('p18_odz'); bumpProgress('p18', 14); confetti(); }
|
||||
else feedback(fb, false, 'Верно ' + ok + ' из ' + items.length);
|
||||
});
|
||||
document.getElementById('p18d-reset').addEventListener('click', ()=>{ sorter.reset(); document.getElementById('p18d-fb').style.display='none'; });
|
||||
})();
|
||||
}
|
||||
function buildFinal3stub(){ document.getElementById('final3-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>Финал главы</b><br><br>Будет в Wave 4 — 7 боссов, увлекательная математика, практика.</p></div></div>${secNav('p18',null)}`; }
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user