feat(algebra-8 ch2): Wave 3 — §11 (Текст. задачи) + §12 (Сводящиеся)

§ 11 «Текстовые задачи»:
- Теория «4 шага», типы (движение/работа/числа/геометрия)
- INTERACT 1: Шаблон 4 шага с пошаговым выбором (6 шагов)
- INTERACT 2: Тренажёр 5 задач с подсказками
- INTERACT 3: Движение по реке (vл, vр, S — live-расчёт)
- INTERACT 4: Задача про двузначное число (54)
- INTERACT 5: Drag-классификатор 8 задач по 4 типам

§ 12 «Сводящиеся к квадратным»:
- Биквадратные через замену t=x², дробные уравнения, ОДЗ
- INTERACT 1: Решатель биквадратного (вводишь a, b, c — полное решение)
- INTERACT 2: Тренажёр 6 биквадратных уравнений
- INTERACT 3: Пошаговое решение дробного уравнения (6 шагов)
- INTERACT 4: Выбор подходящей замены (4 уравнения)
- INTERACT 5: «Найди посторонний корень» (3 уравнения с ОДЗ)

ACH_LABELS для p11_*/p12_*, шпаргалки §11/§12 заполнены.
This commit is contained in:
Maxim Dolgolyov
2026-05-27 14:50:51 +03:00
parent 90d0c41fd0
commit cfca88c3e0
+544 -4
View File
@@ -391,6 +391,16 @@ const ACH_LABELS = {
p10_train: 'Тренажёр разложения',
p10_fraction: 'Сокращение дробей',
p10_sort: 'Разложимо или нет',
p11_steps: 'Решил по 4 шагам',
p11_train: 'Тренажёр текстовых задач',
p11_move: 'Движение по реке',
p11_digit: 'Двузначное число',
p11_class: 'Классификатор задач',
p12_bi: 'Биквадратное решено',
p12_train: 'Тренажёр биквадратных',
p12_frac: 'Дробное → квадратное',
p12_subst: 'Замена переменной',
p12_odz: 'Посторонний корень',
};
function loadProgress(){
@@ -528,8 +538,19 @@ const SIDEBARS = {
['Корни','через дискриминант или Виета'],
['Сокращение','через разложение числителя и знаменателя'],
]},
p11:{ title:'§ 11 — скоро', rows:[['Текстовые задачи','будет в Wave 3']]},
p12:{ title:'§ 12 — скоро', rows:[['Сводящиеся к квадратным','будет в Wave 3']]},
p11:{ title:'Шпаргалка § 11', rows:[
['4 шага','анализ → модель → решение → проверка'],
['Движение','$s = v t$; общее $\\dfrac{s_1}{v_1} + \\dfrac{s_2}{v_2}$'],
['Работа','$A = p \\cdot t$; вместе: $p_1 + p_2 = \\dfrac{1}{t}$'],
['Числа','$\\overline{ab} = 10a + b$'],
]},
p12:{ title:'Шпаргалка § 12', rows:[
['Биквадр','$ax^4+bx^2+c=0$ → $t=x^2$'],
['Условие','$t \\geq 0$'],
['$x = \\pm\\sqrt{t}$','для каждого $t \\geq 0$'],
['Дробное','умножить на ОЗ, проверить ОДЗ'],
['ОДЗ','знаменатель $\\neq 0$'],
]},
final2:{ title:'Финал', rows:[['Итоги главы','будет в Wave 4']]},
};
function buildSidebar(id){
@@ -1216,8 +1237,527 @@ function buildP10(){
render();
})();
}
function buildP11stub(){ document.getElementById('p11-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 11 — Текстовые задачи</b><br><br>Скоро в Wave 3.</p></div></div>${secNav('p10','p12')}`; }
function buildP12stub(){ document.getElementById('p12-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 12 — Сводящиеся к квадратным</b><br><br>Скоро в Wave 3.</p></div></div>${secNav('p11','final2')}`; }
function buildP11stub(){ buildP11(); }
function buildP11(){
const box = document.getElementById('p11-body');
let html = '';
html += makeCard('repeat','Повторение',null,`
<ul style="margin-left:18px;line-height:1.7">
<li>Дискриминант, формулы корней, теорема Виета — из § 8, § 9.</li>
<li><b>Движение:</b> $s = v \\cdot t$; средняя скорость на двух участках через общее $s$ и общее $t$.</li>
<li><b>Работа:</b> $A = p \\cdot t$, где $p$ — производительность.</li>
<li><b>Двузначное число</b> с цифрами $a$ (десятки) и $b$ (единицы): $\\overline{ab} = 10a + b$.</li>
</ul>`);
html += makeCard('theory','4 шага решения','11.1',`
<ol style="margin-left:18px;line-height:1.9">
<li><b>Анализ.</b> Прочесть условие, выделить величины, связи, искомое.</li>
<li><b>Модель.</b> Обозначить неизвестное буквой; выразить остальные величины через неё; составить уравнение.</li>
<li><b>Решение.</b> Решить уравнение — обычно квадратное.</li>
<li><b>Анализ ответа.</b> Проверить смысл (положительные ли значения, целые ли — если требуется), записать ответ.</li>
</ol>`);
html += makeCard('example','Образец',null,`
<p><b>Задача.</b> Произведение двух последовательных натуральных чисел равно 132. Найдите эти числа.</p>
<p><b>Решение.</b> Пусть меньшее $= x$. Тогда $x(x+1) = 132 \\Rightarrow x^2 + x - 132 = 0$. $D = 1 + 528 = 529$, $\\sqrt{D}=23$. $x = (-1+23)/2 = 11$ или $x = -12$. Натуральное только $11$.</p>
<p><b>Ответ:</b> $11$ и $12$.</p>`);
/* INT 1 — Шаблон «4 шага» */
html += widget('Шаблон «4 шага»','INTERACT 1','Решим задачу пошагово. На каждом шаге выберите правильный вариант.',`
<p style="margin-bottom:10px"><b>Задача.</b> Площадь прямоугольника равна 60 см², а одна сторона на 7 см больше другой. Найдите стороны.</p>
<div id="p11s-step" data-st="1" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.05rem"></div>
<div id="p11s-opts" style="display:flex;flex-direction:column;gap:6px;margin-top:10px"></div>
<div class="feedback" id="p11s-fb" style="display:none;margin-top:10px"></div>`);
/* INT 2 — Тренажёр задач */
html += widget('Тренажёр текстовых задач','INTERACT 2','Решите задачу и введите ответ. После 5 задач — итог.',`
<div class="score-display"><span>Задача <b id="p11t-i">1</b> / 5</span><span>Очки: <b id="p11t-score">0</b></span></div>
<div id="p11t-task" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:.98rem;line-height:1.6;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap">
<input type="text" id="p11t-inp" placeholder="ответ (число или два через ;)" style="width:240px;padding:8px;border:1.5px solid var(--border);border-radius:8px">
<button class="btn primary" id="p11t-go">Ответ</button>
<button class="btn" id="p11t-hint">Подсказка</button>
</div>
<div class="feedback" id="p11t-fb" style="display:none;margin-top:10px"></div>
<button class="btn primary" id="p11t-start" style="margin-top:10px">Начать</button>`);
/* INT 3 — Конструктор задачи на движение */
html += widget('Движение по реке','INTERACT 3','Лодка идёт по реке и обратно. Введите $v_л$ и $v_р$ — узнайте, как изменится время.',`
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;justify-content:center;margin-bottom:10px">
<label>Скорость лодки $v_л$ (км/ч) = <input type="number" id="p11m-vl" value="10" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
<label>Скорость реки $v_р$ (км/ч) = <input type="number" id="p11m-vr" value="2" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
<label>Расстояние $S$ (км) = <input type="number" id="p11m-s" value="24" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
</div>
<div id="p11m-out" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;line-height:1.7"></div>`);
/* INT 4 — Задача про двузначное число */
html += widget('Задача про двузначное число','INTERACT 4','Сумма квадратов цифр двузначного числа равна 41, а само число равно сумме его цифр, умноженной на 6. Найдите число.',`
<p style="margin-bottom:10px">Пусть $a$ — десятки, $b$ — единицы. Тогда число $= 10a + b$, $a^2 + b^2 = 41$ и $10a + b = 6(a+b)$.</p>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<label>Ваш ответ: <input type="number" id="p11d-inp" placeholder="двузначное число" style="width:130px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
<button class="btn primary" id="p11d-check">Проверить</button>
<button class="btn" id="p11d-show">Показать решение</button>
</div>
<div class="feedback" id="p11d-fb" style="display:none;margin-top:10px"></div>
<div id="p11d-sol" style="display:none;margin-top:10px;padding:12px;background:var(--card);border-radius:8px;border:1px solid var(--border)"></div>`);
/* INT 5 — Drag: типы задач */
html += widget('Классифицируем тип задачи','INTERACT 5','Прочитайте задачу — кликом отнесите её к одной из четырёх категорий.',`
<div id="p11c-pool" style="display:flex;flex-direction:column;gap:6px;margin-bottom:14px"></div>
<div class="drop-row" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px">
<div class="drop-box"><h5>Движение</h5><div class="drop-items" data-cat="dv"></div></div>
<div class="drop-box"><h5>Работа</h5><div class="drop-items" data-cat="wk"></div></div>
<div class="drop-box"><h5>Числа</h5><div class="drop-items" data-cat="nm"></div></div>
<div class="drop-box"><h5>Геометрия</h5><div class="drop-items" data-cat="gm"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p11c-check">Проверить</button><button class="btn" id="p11c-reset">Сначала</button></div>
<div class="feedback" id="p11c-fb" style="display:none"></div>`);
html += makeCard('class','Класс — решите',null,`
<ol style="margin-left:18px;line-height:1.8">
<li>Произведение двух последовательных нечётных чисел равно 195. Найдите их.</li>
<li>Длина сада на 5 м больше ширины, а площадь — 84 м². Найдите стороны.</li>
<li>Двое рабочих вместе закончили работу за 6 ч. Первый один сделал бы её на 5 ч быстрее, чем второй. За сколько часов сделал бы её каждый?</li>
</ol>`);
html += makeCard('home','Домашка',null,`
<ol style="margin-left:18px;line-height:1.8">
<li>Сумма квадратов двух последовательных натуральных чисел равна 113. Найдите их.</li>
<li>Лодка прошла 30 км по течению и 30 км против за 4 ч. Скорость течения 1 км/ч. Найдите скорость лодки.</li>
<li>Найдите два числа, сумма которых 14, а произведение 48.</li>
</ol>`);
html += secNav('p10','p12');
box.innerHTML = html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
/* INIT 1 — Шаблон 4 шага */
(function(){
const steps = [
{ q:'Шаг 1. Что обозначим за $x$?', opts:['меньшую сторону','произведение','периметр','диагональ'], ok:0 },
{ q:'Шаг 2. Тогда большая сторона равна:', opts:['$x - 7$','$x + 7$','$60/x$','$7x$'], ok:1 },
{ q:'Шаг 3. Уравнение из условия $S = a \\cdot b = 60$:', opts:['$x(x+7) = 60$','$x^2 - 7 = 60$','$2x + 7 = 60$','$x/7 = 60$'], ok:0 },
{ q:'Шаг 4. После раскрытия скобок и переноса:', opts:['$x^2 + 7x - 60 = 0$','$x^2 - 7x + 60 = 0$','$x^2 + 7 = 60$','$x^2 = 67$'], ok:0 },
{ q:'Шаг 5. $D = 49 + 240 = 289 \\Rightarrow \\sqrt{D} = 17$. Корни:', opts:['$x = 5$ и $x = -12$','$x = 6$ и $x = -10$','$x = 4$ и $x = -15$','$x = 8$ и $x = -7$'], ok:0 },
{ q:'Шаг 6. Ответ:', opts:['5 см и 12 см','12 см и 5 см','оба корня подходят','7 см и 15 см'], ok:0 },
];
let i = 0;
function show(){
const s = steps[i];
document.getElementById('p11s-step').innerHTML = '<b>' + (i+1) + ' / ' + steps.length + '.</b> ' + s.q;
renderMath(document.getElementById('p11s-step'));
const opts = document.getElementById('p11s-opts'); opts.innerHTML = '';
s.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('p11s-fb'); fb.style.display = 'block';
if(k === s.ok){
b.classList.add('ok');
feedback(fb, true, '&#10003;');
if(i >= steps.length - 1){ feedback(fb, true, '&#10003; Задача решена!'); achievement('p11_steps'); bumpProgress('p11', 18); confetti(); }
else setTimeout(()=>{ i++; show(); }, 700);
} else { b.classList.add('fail'); feedback(fb, false, 'Не то, подумайте ещё.'); }
});
opts.appendChild(b);
});
renderMath(opts);
document.getElementById('p11s-fb').style.display = 'none';
}
show();
})();
/* INIT 2 — Тренажёр */
(function(){
const tasks = [
{ q:'Произведение двух последовательных натуральных чисел равно 56. Найдите большее.', hint:'$x(x+1) = 56$', ans:[8] },
{ q:'Площадь прямоугольника 48 см², одна сторона на 2 см больше другой. Найдите меньшую.', hint:'$x(x+2)=48$', ans:[6] },
{ q:'Сумма числа и его квадрата равна 90. Найдите положительное число.', hint:'$x + x^2 = 90$', ans:[9] },
{ q:'Произведение двух чисел равно 35, а их сумма равна 12. Найдите большее.', hint:'Виета: $x_1+x_2=12,\\ x_1 x_2=35$', ans:[7] },
{ q:'Лодка прошла 12 км по течению (скорость = $v+1$) и обратно ($v-1$) за 5 ч. Найдите скорость в стоячей воде.', hint:'$\\dfrac{12}{v+1} + \\dfrac{12}{v-1} = 5$', ans:[5] },
];
let cur = null, i = 1, score = 0;
function show(){
cur = tasks[i-1];
document.getElementById('p11t-i').textContent = i;
document.getElementById('p11t-task').innerHTML = '<b>Задача ' + i + '.</b> ' + cur.q;
renderMath(document.getElementById('p11t-task'));
document.getElementById('p11t-inp').value = '';
document.getElementById('p11t-fb').style.display = 'none';
}
document.getElementById('p11t-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p11t-score').textContent = 0; show(); });
document.getElementById('p11t-go').addEventListener('click', ()=>{
const fb = document.getElementById('p11t-fb'); fb.style.display = 'block';
const u = +document.getElementById('p11t-inp').value;
const ok = cur.ans.some(a => Math.abs(u - a) < 1e-6);
if(ok){ score++; feedback(fb, true, '&#10003;'); }
else feedback(fb, false, 'Не то. Ответ: ' + cur.ans.join(' или '));
document.getElementById('p11t-score').textContent = score;
if(i >= tasks.length){ setTimeout(()=>{ feedback(fb, score >= 3, 'Итог: ' + score + '/' + tasks.length); if(score >= 3){ achievement('p11_train'); bumpProgress('p11', 16); confetti(); } }, 600); }
else { i++; setTimeout(show, 900); }
});
document.getElementById('p11t-hint').addEventListener('click', ()=>{
const fb = document.getElementById('p11t-fb'); fb.style.display = 'block';
feedback(fb, true, 'Подсказка: ' + cur.hint); renderMath(fb);
});
})();
/* INIT 3 — Движение */
(function(){
const vlE = document.getElementById('p11m-vl'), vrE = document.getElementById('p11m-vr'), sE = document.getElementById('p11m-s');
const out = document.getElementById('p11m-out');
let done = false;
function refresh(){
const vl = +vlE.value, vr = +vrE.value, s = +sE.value;
if(vl <= vr || vr < 0 || s <= 0){ out.innerHTML = '<span style="color:var(--bad)">Условие: $v_л > v_р \\geq 0,\\ S > 0$.</span>'; renderMath(out); return; }
const t1 = s/(vl+vr), t2 = s/(vl-vr), tT = t1 + t2;
let html = '<div><b>По течению:</b> $v = ' + (vl+vr) + '$ км/ч &rarr; $t = ' + s + '/' + (vl+vr) + ' = ' + fmt(t1) + '$ ч</div>';
html += '<div><b>Против течения:</b> $v = ' + (vl-vr) + '$ км/ч &rarr; $t = ' + fmt(t2) + '$ ч</div>';
html += '<div><b>Итого время:</b> $' + fmt(tT) + '$ ч</div>';
const vAvg = 2*s/tT;
html += '<div><b>Средняя скорость:</b> $\\dfrac{2S}{t_1+t_2} = ' + fmt(vAvg) + '$ км/ч</div>';
out.innerHTML = html; renderMath(out);
if(!done){ done = true; setTimeout(()=>{ achievement('p11_move'); bumpProgress('p11', 14); }, 300); }
}
[vlE,vrE,sE].forEach(e => e.addEventListener('input', refresh));
refresh();
})();
/* INIT 4 — Задача про число */
(function(){
document.getElementById('p11d-check').addEventListener('click', ()=>{
const v = +document.getElementById('p11d-inp').value;
const fb = document.getElementById('p11d-fb'); fb.style.display = 'block';
if(v === 54){ feedback(fb, true, '&#10003; Верно! Число = 54.'); achievement('p11_digit'); bumpProgress('p11', 14); confetti(); }
else feedback(fb, false, 'Не то. Подсказка: $a^2 + b^2 = 41,\\ 10a+b = 6(a+b) \\Rightarrow 4a = 5b$.');
renderMath(fb);
});
document.getElementById('p11d-show').addEventListener('click', ()=>{
const s = document.getElementById('p11d-sol');
s.style.display = 'block';
s.innerHTML = '<p><b>Шаг 1.</b> Из $10a+b = 6(a+b)$ получаем $4a = 5b$, то есть $b = \\dfrac{4a}{5}$. Чтобы $b$ было цифрой (0..9), $a$ должно делиться на 5.</p><p><b>Шаг 2.</b> $a = 5$ &rarr; $b = 4$. Проверяем: $a^2+b^2 = 25+16 = 41$. &#10003;</p><p><b>Ответ:</b> число $= 54$.</p>';
renderMath(s);
});
})();
/* INIT 5 — Drag типы */
(function(){
const items = [
{ id:1, txt:'Лодка прошла 24 км по течению и обратно.', cat:'dv' },
{ id:2, txt:'Двое рабочих вместе закончили работу за 6 ч.', cat:'wk' },
{ id:3, txt:'Произведение последовательных чисел равно 90.', cat:'nm' },
{ id:4, txt:'Сторона квадрата увеличена на 3 см, площадь увеличилась на 33 см².', cat:'gm' },
{ id:5, txt:'Автомобиль и автобус выехали навстречу из A и B.', cat:'dv' },
{ id:6, txt:'Сумма квадратов цифр двузначного числа = 25.', cat:'nm' },
{ id:7, txt:'Бассейн наполняется одной трубой на 2 ч быстрее, чем другой.', cat:'wk' },
{ id:8, txt:'Площадь прямоугольника 48 см², а периметр 28 см.', cat:'gm' },
];
const cats = ['dv','wk','nm','gm'];
const labels = { dv:'Движ.', wk:'Раб.', nm:'Числа', gm:'Геом.' };
let placed = {};
function makeChip(it, where){
const wrap = document.createElement('div');
wrap.style.cssText = 'display:inline-flex;align-items:center;gap:4px;background:var(--sec-acc-soft);border-radius:8px;padding:4px 6px;font-size:.86rem;flex-wrap:wrap;width:100%';
const sp = document.createElement('span'); sp.textContent = it.txt; sp.style.cssText = 'padding:2px 4px;flex:1;min-width:140px';
wrap.appendChild(sp);
if(where === 'pool'){
cats.forEach(cat=>{
const b = document.createElement('button'); b.className = 'btn small'; b.textContent = labels[cat];
b.style.cssText = 'padding:3px 7px;font-size:.7rem';
b.addEventListener('click', ()=>{ placed[it.id] = cat; render(); });
wrap.appendChild(b);
});
} else {
const b = document.createElement('button'); b.className = 'btn small'; b.textContent = '×';
b.style.cssText = 'padding:2px 7px'; b.addEventListener('click', ()=>{ delete placed[it.id]; render(); });
wrap.appendChild(b);
}
return wrap;
}
function render(){
const pool = document.getElementById('p11c-pool');
pool.innerHTML = '';
items.forEach(it=>{ if(!placed[it.id]) pool.appendChild(makeChip(it, 'pool')); });
cats.forEach(cat=>{
const box = document.querySelector('#p11-body .drop-items[data-cat="' + cat + '"]');
if(!box) return;
box.innerHTML = '';
items.forEach(it=>{ if(placed[it.id] === cat) box.appendChild(makeChip(it, 'placed')); });
});
}
document.getElementById('p11c-check').addEventListener('click', ()=>{
const fb = document.getElementById('p11c-fb'); fb.style.display = 'block';
if(Object.keys(placed).length < items.length){ feedback(fb, false, '&#9888; Разложите все ' + items.length + ' задач.'); return; }
let ok = 0; items.forEach(it=>{ if(placed[it.id] === it.cat) ok++; });
if(ok === items.length){ feedback(fb, true, '&#10003; Все верно!'); achievement('p11_class'); bumpProgress('p11', 14); confetti(); }
else feedback(fb, false, 'Верно ' + ok + ' из ' + items.length);
});
document.getElementById('p11c-reset').addEventListener('click', ()=>{ placed = {}; document.getElementById('p11c-fb').style.display='none'; render(); });
render();
})();
}
function buildP12stub(){ buildP12(); }
function buildP12(){
const box = document.getElementById('p12-body');
let html = '';
html += makeCard('repeat','Повторение',null,`
<ul style="margin-left:18px;line-height:1.7">
<li>Квадратное уравнение, дискриминант, Виета — §§ 79.</li>
<li>Разложение трёхчлена $ax^2+bx+c$ — § 10.</li>
<li><b>ОДЗ</b> дробного выражения: знаменатель $\\neq 0$.</li>
</ul>`);
html += makeCard('theory','Биквадратное уравнение','12.1',`
<p><b>Биквадратным</b> называют уравнение вида $ax^4 + bx^2 + c = 0$, $a \\neq 0$.</p>
<p style="margin-top:6px"><b>Метод.</b> Замена $t = x^2$, $t \\geq 0$. Получаем квадратное $at^2 + bt + c = 0$. Решаем его, потом для каждого $t \\geq 0$ находим $x = \\pm\\sqrt{t}$.</p>
<div style="background:var(--sec-acc-soft);border-radius:10px;padding:12px;margin:10px 0;text-align:center;font-size:1.05rem">$$t = x^2 \\geq 0,\\quad x = \\pm\\sqrt{t}$$</div>`);
html += makeCard('rule','Дробные → квадратные','12.2',`
<ol style="margin-left:18px;line-height:1.8">
<li>Найти ОДЗ (знаменатели $\\neq 0$).</li>
<li>Привести к общему знаменателю и умножить уравнение на него.</li>
<li>Решить полученное многочленное уравнение.</li>
<li>Отбросить посторонние корни (вне ОДЗ).</li>
</ol>`);
html += makeCard('example','Примеры',null,`
<p><b>1)</b> $x^4 - 5x^2 + 4 = 0$. Замена $t = x^2$: $t^2 - 5t + 4 = 0 \\Rightarrow t = 1$ или $t = 4$. Тогда $x = \\pm 1$ или $x = \\pm 2$. Ответ: $\\{-2;-1;1;2\\}$.</p>
<p style="margin-top:6px"><b>2)</b> $x^4 + 3x^2 - 4 = 0$. $t^2 + 3t - 4 = 0 \\Rightarrow t = 1$ или $t = -4$. Только $t = 1$ годится: $x = \\pm 1$.</p>
<p style="margin-top:6px"><b>3)</b> $\\dfrac{x}{x-2} - \\dfrac{2}{x+2} = 1$. ОДЗ: $x \\neq \\pm 2$. Умножим на $(x-2)(x+2)$: $x(x+2) - 2(x-2) = (x-2)(x+2) \\Rightarrow x^2 + 2x - 2x + 4 = x^2 - 4 \\Rightarrow 4 = -4$ — противоречие, корней нет.</p>`);
/* INT 1 — Биквадратное пошагово */
html += widget('Решатель биквадратного','INTERACT 1','Введите $a$, $b$, $c$ — система применит замену $t=x^2$ и доведёт до конца.',`
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label>$a$ = <input type="number" id="p12b-a" value="1" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
<label>$b$ = <input type="number" id="p12b-b" value="-5" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
<label>$c$ = <input type="number" id="p12b-c" value="4" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
<button class="btn primary" id="p12b-go">Решить</button>
</div>
<div id="p12b-out" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;line-height:1.7;min-height:60px"></div>`);
/* INT 2 — Тренажёр биквадратных */
html += widget('Тренажёр биквадратных','INTERACT 2','Решите устно. Вводите все корни через точку с запятой (или «нет»).',`
<div class="score-display"><span>Задача <b id="p12t-i">1</b> / 6</span><span>Очки: <b id="p12t-score">0</b></span></div>
<div id="p12t-task" style="font-size:1.3rem;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="p12t-inp" placeholder="например: -2; -1; 1; 2" style="width:240px;padding:8px;border:1.5px solid var(--border);border-radius:8px">
<button class="btn primary" id="p12t-go">Ответ</button>
</div>
<div class="feedback" id="p12t-fb" style="display:none;margin-top:10px"></div>
<button class="btn primary" id="p12t-start" style="margin-top:10px">Начать</button>`);
/* INT 3 — Дробное уравнение */
html += widget('Дробное → квадратное','INTERACT 3','По шагам решаем уравнение с дробями. Внимание к ОДЗ!',`
<p style="margin-bottom:10px">Решим: $\\dfrac{x+3}{x-1} - \\dfrac{2}{x+1} = 2$</p>
<div id="p12f-step" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;line-height:1.7"></div>
<div id="p12f-opts" style="display:flex;flex-direction:column;gap:6px;margin-top:10px"></div>
<div class="feedback" id="p12f-fb" style="display:none;margin-top:10px"></div>`);
/* INT 4 — Какая замена */
html += widget('Выберите подходящую замену','INTERACT 4','Для каждого уравнения подберите замену переменной.',`
<div id="p12s-pool"></div>
<div class="feedback" id="p12s-fb" style="display:none;margin-top:10px"></div>`);
/* INT 5 — ОДЗ проверка */
html += widget('Найди посторонний корень','INTERACT 5','Дано дробное уравнение с готовыми кандидатами на корни. Найдите корень, который НЕ удовлетворяет ОДЗ.',`
<div id="p12o-task" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;line-height:1.7;margin-bottom:10px"></div>
<div id="p12o-opts" style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap"></div>
<div class="feedback" id="p12o-fb" style="display:none;margin-top:10px"></div>
<button class="btn primary" id="p12o-start" style="margin-top:10px">Начать</button>`);
html += makeCard('class','Класс — решите',null,`
<ol style="margin-left:18px;line-height:1.8">
<li>$x^4 - 13x^2 + 36 = 0$</li>
<li>$x^4 - 5x^2 - 36 = 0$</li>
<li>$\\dfrac{2}{x-1} + \\dfrac{3}{x+1} = 1$</li>
</ol>`);
html += makeCard('home','Домашка',null,`
<ol style="margin-left:18px;line-height:1.8">
<li>$x^4 - 10x^2 + 9 = 0$</li>
<li>$x^4 + 7x^2 - 8 = 0$</li>
<li>$\\dfrac{x}{x+1} - \\dfrac{1}{x-1} = \\dfrac{2}{x^2-1}$</li>
<li>$(x^2 - 2)^2 - 3(x^2 - 2) - 4 = 0$ (замена!)</li>
</ol>`);
html += secNav('p11','final2');
box.innerHTML = html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
/* INIT 1 — Биквадратное */
(function(){
document.getElementById('p12b-go').addEventListener('click', ()=>{
const a = +document.getElementById('p12b-a').value;
const b = +document.getElementById('p12b-b').value;
const c = +document.getElementById('p12b-c').value;
const out = document.getElementById('p12b-out');
if(!a){ out.innerHTML = '$a \\neq 0$'; renderMath(out); return; }
let html = '<div><b>Дано:</b> $' + a + 'x^4 ' + (b >= 0 ? '+ ' + b : '- ' + Math.abs(b)) + 'x^2 ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)) + ' = 0$</div>';
html += '<div><b>Замена</b> $t = x^2,\\ t \\geq 0$: $' + a + 't^2 ' + (b >= 0 ? '+ ' + b : '- ' + Math.abs(b)) + 't ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)) + ' = 0$</div>';
const D = b*b - 4*a*c;
html += '<div><b>D</b> = ' + (b*b) + ' ' + (4*a*c) + ' = ' + D + '</div>';
if(D < 0){ html += '<div>$D < 0$ &rarr; нет $t$, значит нет $x$.</div>'; }
else {
const t1 = (-b - Math.sqrt(D))/(2*a), t2 = (-b + Math.sqrt(D))/(2*a);
html += '<div>$t_1 = ' + fmt(t1) + ',\\ t_2 = ' + fmt(t2) + '$</div>';
const roots = [];
[t1, t2].forEach((t, k)=>{
if(t > 0){ const r = Math.sqrt(t); roots.push(r, -r); html += '<div>$t_' + (k+1) + ' = ' + fmt(t) + ' > 0 \\Rightarrow x = \\pm' + fmt(r) + '$</div>'; }
else if(t === 0){ roots.push(0); html += '<div>$t_' + (k+1) + ' = 0 \\Rightarrow x = 0$</div>'; }
else html += '<div>$t_' + (k+1) + ' = ' + fmt(t) + ' < 0$ — не подходит</div>';
});
const u = [...new Set(roots)].sort((a,b)=>a-b);
html += '<div style="margin-top:8px;font-size:1.05rem"><b>Ответ:</b> ' + (u.length ? '$\\{' + u.map(fmt).join(';\\ ') + '\\}$' : 'корней нет') + '</div>';
}
out.innerHTML = html; renderMath(out);
achievement('p12_bi'); bumpProgress('p12', 14);
});
})();
/* INIT 2 — Тренажёр биквадр */
(function(){
const tasks = [
{ eq:'x^4 - 5x^2 + 4 = 0', ans:[-2,-1,1,2] },
{ eq:'x^4 - 10x^2 + 9 = 0', ans:[-3,-1,1,3] },
{ eq:'x^4 - 13x^2 + 36 = 0', ans:[-3,-2,2,3] },
{ eq:'x^4 + 3x^2 - 4 = 0', ans:[-1,1] },
{ eq:'x^4 + 2x^2 + 5 = 0', ans:null },
{ eq:'x^4 - 16 = 0', ans:[-2,2] },
];
let cur = null, i = 1, score = 0, shuffled = [];
function show(){
cur = shuffled[i-1];
document.getElementById('p12t-i').textContent = i;
document.getElementById('p12t-task').innerHTML = '$' + cur.eq + '$';
renderMath(document.getElementById('p12t-task'));
document.getElementById('p12t-inp').value = '';
document.getElementById('p12t-fb').style.display = 'none';
}
function parse(s){
s = s.trim().toLowerCase();
if(/нет|none/.test(s)) return null;
return s.replace(/,/g,';').split(/[;\s]+/).filter(Boolean).map(Number).sort((a,b)=>a-b);
}
function check(){
const fb = document.getElementById('p12t-fb'); fb.style.display = 'block';
const u = parse(document.getElementById('p12t-inp').value);
let ok = false;
if(cur.ans === null) ok = u === null;
else if(u !== null){ const a = [...cur.ans].sort((x,y)=>x-y); ok = a.length === u.length && a.every((v,k)=>v === u[k]); }
if(ok){ score++; feedback(fb, true, '&#10003;'); }
else feedback(fb, false, 'Правильно: ' + (cur.ans === null ? 'нет' : cur.ans.join('; ')));
document.getElementById('p12t-score').textContent = score;
if(i >= shuffled.length){ setTimeout(()=>{ feedback(fb, score >= 4, 'Итог: ' + score + '/' + shuffled.length); if(score >= 4){ achievement('p12_train'); bumpProgress('p12', 16); confetti(); } }, 600); }
else { i++; setTimeout(show, 900); }
}
document.getElementById('p12t-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p12t-score').textContent = 0; shuffled = [...tasks].sort(()=>Math.random()-0.5); show(); });
document.getElementById('p12t-go').addEventListener('click', check);
document.getElementById('p12t-inp').addEventListener('keyup', e=>{ if(e.key === 'Enter') check(); });
})();
/* INIT 3 — Дробное */
(function(){
const steps = [
{ q:'Шаг 1. ОДЗ:', opts:['$x \\neq 1$ и $x \\neq -1$','$x \\neq 0$','$x > 0$','любое $x$'], ok:0 },
{ q:'Шаг 2. Общий знаменатель:', opts:['$(x-1)(x+1)$','$x-1$','$x+1$','$x^2$'], ok:0 },
{ q:'Шаг 3. После умножения на ОЗ:', opts:['$(x+3)(x+1) - 2(x-1) = 2(x-1)(x+1)$','$x+3 - 2 = 2$','$(x+3) - 2 = 2(x-1)$','$x+3-2(x+1) = 2$'], ok:0 },
{ q:'Шаг 4. Раскрытие и приведение:', opts:['$x^2 + 4x + 5 = 2x^2 - 2 \\Rightarrow x^2 - 4x - 7 = 0$','$x^2 = 7$','$x^2 + 4x = 0$','$x = 5$'], ok:0 },
{ q:'Шаг 5. Корни:', opts:['$x = 2 \\pm \\sqrt{11}$','$x = 1, 7$','$x = -1, 7$','корней нет'], ok:0 },
{ q:'Шаг 6. Проверка ОДЗ ($x \\neq \\pm 1$):', opts:['оба корня подходят','$x = 2 - \\sqrt{11}$ лишний','$x = 2 + \\sqrt{11}$ лишний','оба лишние'], ok:0 },
];
let i = 0;
function show(){
const s = steps[i];
document.getElementById('p12f-step').innerHTML = '<b>' + (i+1) + ' / ' + steps.length + '.</b> ' + s.q;
renderMath(document.getElementById('p12f-step'));
const opts = document.getElementById('p12f-opts'); opts.innerHTML = '';
s.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('p12f-fb'); fb.style.display = 'block';
if(k === s.ok){
b.classList.add('ok');
feedback(fb, true, '&#10003;');
if(i >= steps.length - 1){ feedback(fb, true, '&#10003; Уравнение решено!'); achievement('p12_frac'); bumpProgress('p12', 16); confetti(); }
else setTimeout(()=>{ i++; show(); }, 700);
} else { b.classList.add('fail'); feedback(fb, false, 'Не то, подумайте.'); }
});
opts.appendChild(b);
});
renderMath(opts);
document.getElementById('p12f-fb').style.display = 'none';
}
show();
})();
/* INIT 4 — Замены */
(function(){
const items = [
{ eq:'x^4 + 3x^2 - 4 = 0', ans:'t=x^2' },
{ eq:'(x^2-3)^2 - 5(x^2-3) + 6 = 0', ans:'t=x^2-3' },
{ eq:'x^2 + \\dfrac{1}{x^2} - 4 = 0', ans:'t=x^2' },
{ eq:'(x+\\dfrac{1}{x})^2 - 3(x+\\dfrac{1}{x}) + 2 = 0', ans:'t=x+1/x' },
];
const opts = ['t=x^2', 't=x^2-3', 't=x+1/x', 't=x-1'];
const pool = document.getElementById('p12s-pool');
let answered = 0, score = 0;
items.forEach((it, idx)=>{
const row = document.createElement('div');
row.style.cssText = 'display:flex;gap:8px;align-items:center;padding:8px;border-bottom:1px solid var(--border);flex-wrap:wrap';
row.innerHTML = '<div style="flex:1;min-width:160px">$' + it.eq + '$</div>';
const sel = document.createElement('select');
sel.style.cssText = 'padding:6px;border:1.5px solid var(--border);border-radius:6px';
sel.innerHTML = '<option value="">— выбрать —</option>' + opts.map(o => '<option value="' + o + '">$' + o + '$</option>').join('').replace(/\$/g,'');
const mark = document.createElement('span'); mark.style.cssText = 'font-weight:700;font-size:1.2rem;width:24px;text-align:center';
const check = document.createElement('button'); check.className = 'btn small'; check.textContent = 'Проверить';
check.addEventListener('click', ()=>{
if(!sel.value){ mark.textContent = '?'; mark.style.color = 'var(--muted)'; return; }
if(sel.value === it.ans){ mark.textContent = '✓'; mark.style.color = 'var(--ok)'; if(!row.dataset.scored){ row.dataset.scored='1'; score++; answered++; } }
else { mark.textContent = '✗'; mark.style.color = 'var(--bad)'; if(!row.dataset.answered){ row.dataset.answered='1'; answered++; } }
if(answered >= items.length){
const fb = document.getElementById('p12s-fb'); fb.style.display = 'block';
feedback(fb, score >= 3, 'Итог: ' + score + '/' + items.length);
if(score >= 3){ achievement('p12_subst'); bumpProgress('p12', 14); confetti(); }
}
});
row.appendChild(sel); row.appendChild(check); row.appendChild(mark);
pool.appendChild(row);
});
if(window.renderMathInElement) renderMath(pool);
})();
/* INIT 5 — Посторонний корень */
(function(){
const tasks = [
{ eq:'\\dfrac{1}{x-2} = \\dfrac{x-2}{4}', roots:[0, 4, -2, 2], wrong:[2], odz:'x \\neq 2' },
{ eq:'\\dfrac{x}{x-3} = \\dfrac{9}{x-3}', roots:[3, 9, -9, 0], wrong:[3], odz:'x \\neq 3' },
{ eq:'\\dfrac{1}{x+1} + \\dfrac{1}{x-1} = 0', roots:[1, -1, 0, 2], wrong:[1,-1], odz:'x \\neq \\pm 1' },
];
let cur = null, i = 1;
function show(){
cur = tasks[i-1];
document.getElementById('p12o-task').innerHTML = '<b>Уравнение ' + i + ' / ' + tasks.length + ':</b> $' + cur.eq + '$<br><span style="color:var(--muted);font-size:.9rem">ОДЗ: $' + cur.odz + '$</span><br>Кандидаты на корни:';
renderMath(document.getElementById('p12o-task'));
const opts = document.getElementById('p12o-opts'); opts.innerHTML = '';
cur.roots.forEach(r=>{
const b = document.createElement('button'); b.className = 'btn'; b.textContent = 'x = ' + r;
b.addEventListener('click', ()=>{
const fb = document.getElementById('p12o-fb'); fb.style.display = 'block';
if(cur.wrong.includes(r)){ b.classList.add('ok'); feedback(fb, true, '&#10003; Это посторонний корень (не в ОДЗ).'); }
else { b.classList.add('fail'); feedback(fb, false, 'Не то — этот корень допустим в ОДЗ. Ищите тот, что нарушает.'); return; }
if(i >= tasks.length){ setTimeout(()=>{ feedback(fb, true, 'Все 3 пройдено!'); achievement('p12_odz'); bumpProgress('p12', 14); confetti(); }, 500); }
else { i++; setTimeout(show, 800); }
});
opts.appendChild(b);
});
document.getElementById('p12o-fb').style.display = 'none';
}
document.getElementById('p12o-start').addEventListener('click', ()=>{ i=1; show(); });
})();
}
function buildFinal2stub(){ document.getElementById('final2-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>Финал главы</b><br><br>Итоговая самооценка, практика, увлекательная математика и финальный босс — в Wave 4.</p></div></div>${secNav('p12',null)}`; }
</script>