feat(alg9 ch4 wave2): §16 «Сумма арифм.» + §17 «Геом. прогрессия»

This commit is contained in:
Maxim Dolgolyov
2026-05-29 08:56:30 +03:00
parent eb565081f6
commit 5ed21e4d2e
+587 -25
View File
@@ -1120,38 +1120,600 @@ function buildP15(){
}
function buildP16(){
const root = document.getElementById('p16-body');
root.innerHTML = `
<div class="card">
<div class="card-header">
<span class="card-icon theory">${ICONS.theory}</span>
<span class="card-title">В разработке</span>
<span class="card-num">§ 16</span>
const box = document.getElementById('p16-body');
let html = '';
html += makeCard('theory', 'Формула суммы (через крайние члены)', '16.1', `
<p>Сумма $n$ первых членов арифметической прогрессии равна <b>полусумме первого и последнего</b> члена, умноженной на число членов:</p>
<p>$$S_n = \\dfrac{a_1 + a_n}{2} \\cdot n.$$</p>
<p>Удобно применять, когда известны <b>$a_1$, $a_n$ и $n$</b> (или их легко найти).</p>`);
html += makeCard('rule', 'Формула суммы (через $a_1$ и $d$)', '16.2', `
<p>Подставив $a_n = a_1 + (n - 1) d$ в первую формулу, получим:</p>
<p>$$S_n = \\dfrac{2 a_1 + (n - 1) d}{2} \\cdot n.$$</p>
<p>Эта формула удобна, когда заданы <b>$a_1$, $d$ и $n$</b>. Обе формулы эквивалентны и дают один и тот же результат.</p>`);
html += makeCard('example', 'Идея вывода (Гаусс) и примеры', '16.3', `
<p><b>Идея вывода.</b> Пусть $S = 1 + 2 + 3 + \\ldots + 100$. Сложим пары крайних членов:
$(1 + 100) + (2 + 99) + \\ldots + (50 + 51)$. Каждая пара даёт $101$, пар $50$, поэтому
$S = 50 \\cdot 101 = \\mathbf{5050}$.</p>
<p>Аналогично для арифм. прогрессии: пар $n/2$, каждая равна $a_1 + a_n$, итого $S_n = \\dfrac{(a_1 + a_n) \\cdot n}{2}$.</p>
<p><b>а)</b> Сумма первых $20$ членов прогрессии $3, 7, 11, \\ldots$: $a_1 = 3$, $d = 4$, $a_{20} = 3 + 19 \\cdot 4 = 79$. Тогда $S_{20} = \\dfrac{3 + 79}{2} \\cdot 20 = \\mathbf{820}.$</p>
<p><b>б)</b> Сумма первых $100$ натуральных чисел: $S = \\dfrac{1 + 100}{2} \\cdot 100 = \\mathbf{5050}.$</p>`);
/* INTERACTIVE 1 — конструктор суммы (Гаусс-пары) */
html += `<div class="wg" id="p16-iv1">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Конструктор суммы (приём Гаусса)</div></div>
<div class="wg-help">Двигай ползунки $a_1$, $d$, $n$. Будут показаны все $n$ членов и подсвечены пары крайних — каждая пара даёт одно и то же число $a_1 + a_n$.</div>
<div class="sliders">
<label>$a_1$ =<b id="p16-iv1-av">0</b><input type="range" id="p16-iv1-a1" min="-10" max="10" step="1" value="3"></label>
<label>$d$ =<b id="p16-iv1-dv">0</b><input type="range" id="p16-iv1-d" min="-5" max="5" step="1" value="4"></label>
<label>$n$ =<b id="p16-iv1-nv">0</b><input type="range" id="p16-iv1-n" min="2" max="20" step="1" value="8"></label>
</div>
<div id="p16-iv1-terms" style="padding:12px;background:var(--card);border-radius:10px;margin-bottom:10px;font-family:'JetBrains Mono',monospace;font-size:.95rem;line-height:1.9;text-align:center;overflow-x:auto"></div>
<div id="p16-iv1-pairs" style="padding:10px 12px;background:var(--sec-acc-soft);border-radius:9px;margin-bottom:10px;font-size:.92rem;text-align:center"></div>
<div id="p16-iv1-formula" style="padding:12px;background:var(--card);border-radius:10px;font-size:1rem;text-align:center"></div>
</div>`;
/* INTERACTIVE 2 — калькулятор суммы */
html += `<div class="wg" id="p16-iv2">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор суммы $S_n$</div></div>
<div class="wg-help">Введи $a_1$, $d$, $n$ — получишь $a_n$ и $S_n$ с подстановкой.</div>
<div style="background:var(--card);border-radius:11px;padding:14px;max-width:480px;margin:0 auto">
<div style="display:grid;grid-template-columns:auto 1fr;gap:8px 10px;align-items:center;margin-bottom:10px">
<span>$a_1$ =</span><input type="number" id="p16-iv2-a1" class="tinp" value="3" step="1">
<span>$d$ =</span><input type="number" id="p16-iv2-d" class="tinp" value="4" step="1">
<span>$n$ =</span><input type="number" id="p16-iv2-n" class="tinp" value="20" step="1" min="1">
</div>
<div class="card-body">
<p>Содержание параграфа <b>«Сумма арифм. прогрессии»</b> будет добавлено в следующих обновлениях.</p>
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 1.</p>
</div>
</div>` + secNav('p15', 'p17') + readButton('p16');
renderMath(root);
<button class="btn primary" id="p16-iv2-go" style="width:100%">Вычислить $S_n$</button>
<div id="p16-iv2-out" style="margin-top:10px;padding:10px 12px;background:var(--sec-acc-soft);border-radius:8px;font-size:.95rem;min-height:36px;line-height:1.7"></div>
</div>
</div>`;
/* INTERACTIVE 3 — найди ошибку в формуле */
html += `<div class="wg" id="p16-iv3">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Найди ошибку в формуле</div></div>
<div class="wg-help">Перед тобой — утверждение. Если оно верное, жми «Верно»; если есть ошибка — «Ошибка».</div>
<div class="score-display">Задача: <b id="p16-iv3-idx">1</b> / 6 &middot; Очки: <b id="p16-iv3-sc">0</b></div>
<div id="p16-iv3-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:70px"></div>
<div class="actions" style="justify-content:center">
<button class="btn primary" id="p16-iv3-y">Верно</button>
<button class="btn" id="p16-iv3-n">Ошибка</button>
</div>
<div class="feedback" id="p16-iv3-fb"></div>
</div>`;
/* INTERACTIVE 4 — тренажёр сумм */
html += `<div class="wg" id="p16-iv4">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр сумм</div></div>
<div class="wg-help">Применяй $S_n = \\dfrac{a_1 + a_n}{2} \\cdot n$ или $S_n = \\dfrac{2 a_1 + (n - 1) d}{2} \\cdot n$. Ответ — целое число.</div>
<div class="score-display">Задача: <b id="p16-iv4-idx">1</b> / 6 &middot; Очки: <b id="p16-iv4-sc">0</b></div>
<div id="p16-iv4-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:60px"></div>
<div class="actions" style="justify-content:center;align-items:center">
<span style="font-family:'JetBrains Mono',monospace">Ответ:</span>
<input type="number" id="p16-iv4-ans" class="tinp" style="width:140px;text-align:center" step="1">
<button class="btn primary" id="p16-iv4-go">Проверить</button>
</div>
<div class="feedback" id="p16-iv4-fb"></div>
</div>`;
box.innerHTML = html + secNav('p15', 'p17') + readButton('p16');
renderMath(box);
/* ===== IV1 wiring ===== */
(function(){
const a1Sl = document.getElementById('p16-iv1-a1');
const dSl = document.getElementById('p16-iv1-d');
const nSl = document.getElementById('p16-iv1-n');
const av = document.getElementById('p16-iv1-av');
const dv = document.getElementById('p16-iv1-dv');
const nv = document.getElementById('p16-iv1-nv');
const termsEl = document.getElementById('p16-iv1-terms');
const pairsEl = document.getElementById('p16-iv1-pairs');
const formEl = document.getElementById('p16-iv1-formula');
const PAIR_COLORS = ['#ef4444','#0891b2','#16a34a','#a855f7','#f59e0b','#ec4899','#6366f1','#14b8a6','#f97316','#84cc16'];
let bumped = false;
function redraw(){
const a1 = +a1Sl.value, d = +dSl.value, n = +nSl.value;
av.textContent = a1; dv.textContent = d; nv.textContent = n;
// массив членов
const arr = [];
for (let i=0;i<n;i++) arr.push(a1 + i*d);
const an = arr[n-1];
// раскраска пар: i и n-1-i получают один цвет, средний (если n нечётно) — серый
const colors = new Array(n).fill('#94a3b8');
const halfPairs = Math.floor(n/2);
for (let p=0;p<halfPairs;p++){
const c = PAIR_COLORS[p % PAIR_COLORS.length];
colors[p] = c;
colors[n-1-p] = c;
}
// отрисовка членов с цветами
const parts = arr.map((v,i)=>'<span style="display:inline-block;padding:3px 9px;margin:2px;border-radius:7px;background:'+colors[i]+'15;color:'+colors[i]+';font-weight:700;border:1.5px solid '+colors[i]+'55">'+v+'</span>');
termsEl.innerHTML = parts.join(' ');
// описание пар
const pairSum = a1 + an;
let pairsTxt = '';
if (halfPairs > 0){
const pairsList = [];
for (let p=0;p<Math.min(halfPairs,3);p++){
pairsList.push('('+arr[p]+'\\, +\\, '+arr[n-1-p]+')');
}
if (halfPairs > 3) pairsList.push('\\ldots');
pairsTxt = '<b>Пары:</b> $' + pairsList.join('\\, +\\, ') + ' = ' + halfPairs + ' \\cdot ' + pairSum + ' = ' + (halfPairs*pairSum) + '$';
if (n % 2 === 1){
const mid = arr[(n-1)/2];
pairsTxt += ' &nbsp;+&nbsp; <span style="color:#64748b">средний $' + mid + '$</span>';
}
} else {
pairsTxt = '<b>n = 1</b>: $S_1 = a_1 = ' + a1 + '$';
}
pairsEl.innerHTML = pairsTxt;
// итог
const Sn = (a1 + an) * n / 2;
const dPart = (d>=0 ? '+ ' + d : '- ' + (-d));
formEl.innerHTML = '$a_{'+n+'} = '+a1+' '+dPart+' \\cdot ('+n+' - 1) = '+an+'$<br>'+
'$S_{'+n+'} = \\dfrac{'+a1+' + '+an+'}{2} \\cdot '+n+' = \\mathbf{'+Sn+'}$';
renderMath(pairsEl); renderMath(formEl);
if (!bumped){ bumped = true; bumpProgress('p16', 15); addXp(10,'p16-iv1'); }
}
a1Sl.addEventListener('input', redraw);
dSl.addEventListener('input', redraw);
nSl.addEventListener('input', redraw);
redraw();
})();
/* ===== IV2 wiring ===== */
(function(){
const out = document.getElementById('p16-iv2-out');
let bumped = false;
document.getElementById('p16-iv2-go').addEventListener('click', ()=>{
const a1 = +document.getElementById('p16-iv2-a1').value;
const d = +document.getElementById('p16-iv2-d').value;
const n = +document.getElementById('p16-iv2-n').value;
if (!Number.isInteger(n) || n < 1){ out.innerHTML = 'Номер $n$ должен быть натуральным.'; renderMath(out); return; }
const an = a1 + (n - 1) * d;
const Sn = (a1 + an) * n / 2;
const dPart = (d>=0 ? '+ ' + d : '- ' + (-d));
out.innerHTML =
'$a_{'+n+'} = '+a1+' '+dPart+' \\cdot ('+n+' - 1) = '+fmt(an)+'$<br>'+
'$S_{'+n+'} = \\dfrac{'+a1+' + '+fmt(an)+'}{2} \\cdot '+n+' = \\mathbf{'+fmt(Sn)+'}$';
renderMath(out);
if (!bumped){ bumped = true; bumpProgress('p16', 15); addXp(10,'p16-iv2'); }
});
})();
/* ===== IV3 wiring ===== */
(function(){
const items = [
{ q:'Для прогрессии $1, 3, 5, 7, 9$: $S_5 = \\dfrac{1 + 9}{2} \\cdot 5 = 25$.', ans:true, hint:'$\\dfrac{10}{2} \\cdot 5 = 25$.' },
{ q:'$S_n = a_1 + (n - 1) d$.', ans:false, hint:'Это формула $a_n$, а не суммы. У суммы есть множитель $n/2$.' },
{ q:'$S_n = \\dfrac{a_1 + a_n}{2} \\cdot n$.', ans:true, hint:'Классическая формула суммы через крайние члены.' },
{ q:'Для $1, 3, 5, \\ldots, 19$ (10 членов): $S_{10} = \\dfrac{1 + 19}{2} \\cdot 10 = 100$.', ans:true, hint:'$\\dfrac{20}{2} \\cdot 10 = 100$.' },
{ q:'$S_n = n \\cdot a_1 + d$.', ans:false, hint:'Слагаемых с $d$ должно быть много, а здесь только одно. Это не сумма.' },
{ q:'Сумма первых $50$ натуральных чисел: $\\dfrac{50 \\cdot 51}{2} = 1275$.', ans:true, hint:'$S = \\dfrac{1 + 50}{2} \\cdot 50 = 1275$.' }
];
let i = 0, sc = 0;
const idxEl = document.getElementById('p16-iv3-idx');
const scEl = document.getElementById('p16-iv3-sc');
const qEl = document.getElementById('p16-iv3-q');
const fb = document.getElementById('p16-iv3-fb');
const yBtn = document.getElementById('p16-iv3-y');
const nBtn = document.getElementById('p16-iv3-n');
let bumped = false;
function render(){
idxEl.textContent = Math.min(i+1, items.length);
scEl.textContent = sc;
if (i >= items.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
yBtn.disabled = true; nBtn.disabled = true;
yBtn.style.opacity = .5; nBtn.style.opacity = .5;
if (!bumped){ bumped = true; bumpProgress('p16', 25); addXp(15,'p16-iv3'); }
return;
}
qEl.innerHTML = items[i].q;
fb.style.display = 'none';
renderMath(qEl);
}
function answer(v){
if (i >= items.length) return;
const it = items[i];
const ok = (v === it.ans);
if (ok) sc++;
feedback(fb, ok, (ok?'&#10003; Верно. ':'&#10007; Неверно. ') + it.hint);
i++;
setTimeout(render, 1100);
}
yBtn.addEventListener('click', ()=>answer(true));
nBtn.addEventListener('click', ()=>answer(false));
render();
})();
/* ===== IV4 wiring ===== */
(function(){
const items = [
{ q:'Сумма первых 10 нечётных чисел: $1 + 3 + 5 + \\ldots + 19 = ?$', ans: 100 },
{ q:'$a_1 = 5,\\ d = 2,\\ n = 6$. Найти $S_6$.', ans: 60 },
{ q:'$a_1 = -3,\\ d = 4,\\ n = 10$. Найти $S_{10}$.', ans: 150 },
{ q:'Сумма первых $100$ натуральных чисел.', ans: 5050 },
{ q:'$a_1 = 2,\\ a_{20} = 40$. Найти $S_{20}$.', ans: 420 },
{ q:'Прогрессия $7, 11, 15, \\ldots, 47$. Найти сумму всех её членов.', ans: 297 }
];
let i = 0, sc = 0;
const idxEl = document.getElementById('p16-iv4-idx');
const scEl = document.getElementById('p16-iv4-sc');
const qEl = document.getElementById('p16-iv4-q');
const inp = document.getElementById('p16-iv4-ans');
const btn = document.getElementById('p16-iv4-go');
const fb = document.getElementById('p16-iv4-fb');
let bumped = false;
function render(){
idxEl.textContent = Math.min(i+1, items.length);
scEl.textContent = sc;
if (i >= items.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
inp.disabled = true; btn.disabled = true;
inp.style.opacity = .5; btn.style.opacity = .5;
if (!bumped){ bumped = true; bumpProgress('p16', 25); addXp(15,'p16-iv4'); }
return;
}
qEl.innerHTML = items[i].q;
inp.value = ''; fb.style.display = 'none';
renderMath(qEl);
}
btn.addEventListener('click', ()=>{
if (i >= items.length) return;
const v = +inp.value;
const it = items[i];
const ok = (v === it.ans);
if (ok) sc++;
feedback(fb, ok, ok ? '&#10003; Верно: $'+it.ans+'$' : '&#10007; Неверно. Правильный ответ: $'+it.ans+'$');
i++;
setTimeout(render, 1100);
});
inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ e.preventDefault(); btn.click(); } });
render();
})();
wireReadBtn('p16');
}
function buildP17(){
const root = document.getElementById('p17-body');
root.innerHTML = `
<div class="card">
<div class="card-header">
<span class="card-icon theory">${ICONS.theory}</span>
<span class="card-title">В разработке</span>
<span class="card-num">§ 17</span>
const box = document.getElementById('p17-body');
let html = '';
html += makeCard('theory', 'Определение и формула $n$-го члена', '17.1', `
<p><b>Геометрическая прогрессия</b> — числовая последовательность, в которой каждый следующий член равен предыдущему, умноженному на одно и то же число $q \\ne 0$ — <b>знаменатель прогрессии</b>.</p>
<p>$$b_{n+1} = b_n \\cdot q,\\quad b_1 \\ne 0.$$</p>
<p><b>Формула $n$-го члена:</b></p>
<p>$$b_n = b_1 \\cdot q^{n - 1}.$$</p>
<p><b>Пример.</b> $2, 6, 18, 54, \\ldots$ — геометрическая прогрессия с $b_1 = 2$, $q = 3$. Тогда $b_5 = 2 \\cdot 3^4 = 162$.</p>`);
html += makeCard('rule', 'Характеристическое свойство', '17.2', `
<p>В геометрической прогрессии с положительными членами (или с одним знаком) <b>средний</b> член — это <b>среднее геометрическое</b> своих соседей:</p>
<p>$$b_n^2 = b_{n-1} \\cdot b_{n+1}\\quad (n \\ge 2),$$</p>
<p>то есть $|b_n| = \\sqrt{b_{n-1} \\cdot b_{n+1}}$.</p>
<p><b>Пример.</b> Между $2$ и $8$ в геом. прогрессии стоит $\\sqrt{2 \\cdot 8} = \\sqrt{16} = 4$.</p>`);
html += makeCard('example', 'Применение формулы и поведение', '17.3', `
<p><b>а)</b> $b_1 = 3$, $q = 2$: $b_5 = 3 \\cdot 2^4 = 3 \\cdot 16 = \\mathbf{48}.$</p>
<p><b>б)</b> $b_1 = 64$, $q = \\dfrac{1}{2}$: $b_5 = 64 \\cdot \\left(\\dfrac{1}{2}\\right)^4 = 64 \\cdot \\dfrac{1}{16} = \\mathbf{4}.$ Прогрессия убывает по модулю.</p>
<p><b>Поведение в зависимости от $q$:</b></p>
<ul style="margin-left:18px">
<li>$|q| > 1$ — модули членов <b>растут</b>;</li>
<li>$|q| < 1$ — модули <b>убывают</b> к $0$;</li>
<li>$|q| = 1$ — все члены равны по модулю;</li>
<li>$q < 0$ — знаки членов <b>чередуются</b>.</li>
</ul>`);
/* INTERACTIVE 1 — конструктор геометрической */
html += `<div class="wg" id="p17-iv1">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Конструктор геом. прогрессии</div></div>
<div class="wg-help">Двигай ползунки $b_1$ и $q$. Точки $(n; b_n)$ показывают, как ведёт себя прогрессия: рост / убывание / чередование знаков.</div>
<div class="sliders">
<label>$b_1$ =<b id="p17-iv1-bv">0</b><input type="range" id="p17-iv1-b1" min="-5" max="10" step="1" value="2"></label>
<label>$q$ =<b id="p17-iv1-qv">0</b><input type="range" id="p17-iv1-q" min="-2" max="2" step="0.25" value="1.5"></label>
</div>
<div id="p17-iv1-formula" style="text-align:center;font-size:1.05rem;padding:10px;background:var(--card);border-radius:9px;margin-bottom:10px"></div>
<div style="background:var(--card);border-radius:10px;padding:10px;overflow-x:auto">
<svg id="p17-iv1-svg" viewBox="0 0 460 300" style="width:100%;max-width:560px;height:auto;display:block;margin:0 auto"></svg>
</div>
<div id="p17-iv1-out" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem;text-align:center"></div>
<div id="p17-iv1-desc" style="margin-top:8px;padding:8px 12px;background:var(--card);border-radius:8px;font-size:.9rem;text-align:center;color:var(--muted)"></div>
</div>`;
/* INTERACTIVE 2 — калькулятор b_n и q */
html += `<div class="wg" id="p17-iv2">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор $b_n$ и $q$</div></div>
<div class="wg-help">Две формы. <b>Слева</b> — найди $b_n$ по $b_1$, $q$, $n$. <b>Справа</b> — найди $q$ по $b_1$, $b_n$, $n$.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-bottom:8px">
<div style="background:var(--card);border-radius:11px;padding:14px">
<div style="font-weight:700;color:var(--sec-acc-d,var(--pri2));margin-bottom:10px">Найти $b_n$</div>
<div style="display:grid;grid-template-columns:auto 1fr;gap:8px 10px;align-items:center;margin-bottom:10px">
<span>$b_1$ =</span><input type="number" id="p17-iv2a-b1" class="tinp" value="2" step="1">
<span>$q$ =</span><input type="number" id="p17-iv2a-q" class="tinp" value="3" step="0.5">
<span>$n$ =</span><input type="number" id="p17-iv2a-n" class="tinp" value="5" step="1" min="1">
</div>
<button class="btn primary" id="p17-iv2a-go" style="width:100%">Найти $b_n$</button>
<div id="p17-iv2a-out" style="margin-top:10px;padding:8px 12px;background:var(--sec-acc-soft);border-radius:8px;font-size:.92rem;min-height:36px"></div>
</div>
<div class="card-body">
<p>Содержание параграфа <b>«Геометрическая прогрессия»</b> будет добавлено в следующих обновлениях.</p>
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 1.</p>
<div style="background:var(--card);border-radius:11px;padding:14px">
<div style="font-weight:700;color:var(--sec-acc-d,var(--pri2));margin-bottom:10px">Найти $q$</div>
<div style="display:grid;grid-template-columns:auto 1fr;gap:8px 10px;align-items:center;margin-bottom:10px">
<span>$b_1$ =</span><input type="number" id="p17-iv2b-b1" class="tinp" value="2" step="1">
<span>$b_n$ =</span><input type="number" id="p17-iv2b-bn" class="tinp" value="162" step="1">
<span>$n$ =</span><input type="number" id="p17-iv2b-n" class="tinp" value="5" step="1" min="2">
</div>
<button class="btn primary" id="p17-iv2b-go" style="width:100%">Найти $q$</button>
<div id="p17-iv2b-out" style="margin-top:10px;padding:8px 12px;background:var(--sec-acc-soft);border-radius:8px;font-size:.92rem;min-height:36px"></div>
</div>
</div>` + secNav('p16', 'p18') + readButton('p17');
renderMath(root);
</div>
</div>`;
/* INTERACTIVE 3 — геометрическая или нет */
html += `<div class="wg" id="p17-iv3">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Является ли геометрической?</div></div>
<div class="wg-help">Даны первые члены последовательности. Если отношение $b_{n+1}/b_n$ постоянно — это геометрическая прогрессия.</div>
<div class="score-display">Задача: <b id="p17-iv3-idx">1</b> / 6 &middot; Очки: <b id="p17-iv3-sc">0</b></div>
<div id="p17-iv3-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:60px"></div>
<div class="actions" style="justify-content:center">
<button class="btn primary" id="p17-iv3-y">Да, геом.</button>
<button class="btn" id="p17-iv3-n">Нет</button>
</div>
<div class="feedback" id="p17-iv3-fb"></div>
</div>`;
/* INTERACTIVE 4 — тренажёр */
html += `<div class="wg" id="p17-iv4">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр геом. прогрессии</div></div>
<div class="wg-help">Применяй $b_n = b_1 \\cdot q^{n - 1}$ и характеристическое свойство $b_n^2 = b_{n-1} \\cdot b_{n+1}$. Ответ — целое число.</div>
<div class="score-display">Задача: <b id="p17-iv4-idx">1</b> / 6 &middot; Очки: <b id="p17-iv4-sc">0</b></div>
<div id="p17-iv4-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:60px"></div>
<div class="actions" style="justify-content:center;align-items:center">
<span style="font-family:'JetBrains Mono',monospace">Ответ:</span>
<input type="number" id="p17-iv4-ans" class="tinp" style="width:120px;text-align:center" step="1">
<button class="btn primary" id="p17-iv4-go">Проверить</button>
</div>
<div class="feedback" id="p17-iv4-fb"></div>
</div>`;
box.innerHTML = html + secNav('p16', 'p18') + readButton('p17');
renderMath(box);
/* ===== IV1 wiring ===== */
(function(){
const svg = document.getElementById('p17-iv1-svg');
const b1Sl = document.getElementById('p17-iv1-b1');
const qSl = document.getElementById('p17-iv1-q');
const bv = document.getElementById('p17-iv1-bv');
const qv = document.getElementById('p17-iv1-qv');
const formula = document.getElementById('p17-iv1-formula');
const out = document.getElementById('p17-iv1-out');
const desc = document.getElementById('p17-iv1-desc');
let bumped = false;
function fmtQ(q){
// 1/2, 1/4 — для красоты
if (Math.abs(q - 0.5) < 1e-9) return '\\dfrac{1}{2}';
if (Math.abs(q + 0.5) < 1e-9) return '-\\dfrac{1}{2}';
if (Math.abs(q - 0.25) < 1e-9) return '\\dfrac{1}{4}';
if (Math.abs(q + 0.25) < 1e-9) return '-\\dfrac{1}{4}';
if (Math.abs(q - 0.75) < 1e-9) return '\\dfrac{3}{4}';
if (Math.abs(q + 0.75) < 1e-9) return '-\\dfrac{3}{4}';
if (Math.abs(q - 1.5) < 1e-9) return '\\dfrac{3}{2}';
if (Math.abs(q + 1.5) < 1e-9) return '-\\dfrac{3}{2}';
return fmt(q);
}
function redraw(){
const b1 = +b1Sl.value;
const q = +qSl.value;
bv.textContent = b1; qv.textContent = q;
const N = 10;
const pts = [];
for (let n=1;n<=N;n++) pts.push([n, b1 * Math.pow(q, n-1)]);
// обрезаем чрезмерные значения для оси Y
const ABS_LIMIT = 200;
const ys = pts.map(p=>p[1]).filter(v=>Math.abs(v)<=ABS_LIMIT*5);
let ymin = Math.min(...ys, 0), ymax = Math.max(...ys, 0);
if (!isFinite(ymin) || !isFinite(ymax) || ymax === ymin){ ymin = -1; ymax = 1; }
const pad = Math.max(2, (ymax - ymin) * 0.15);
ymin = Math.floor(ymin - pad);
ymax = Math.ceil(ymax + pad);
const ax = axes2D(460, 300, 34, 0, N+1, ymin, ymax);
let g = ax.content;
// соединяющая ломаная (без хвостов вне зоны)
let path = '';
let prevIn = false;
pts.forEach(p=>{
const inZone = (p[1] >= ymin && p[1] <= ymax);
if (inZone){
path += (prevIn ? ' L' : ' M') + ax.toX(p[0]).toFixed(1) + ',' + ax.toY(p[1]).toFixed(1);
}
prevIn = inZone;
});
g += '<path d="'+path+'" stroke="#0891b2" stroke-width="1.5" fill="none" opacity=".55" stroke-dasharray="4 3"/>';
// точки
pts.forEach(p=>{
if (p[1] < ymin || p[1] > ymax) return;
const x = ax.toX(p[0]); const y = ax.toY(p[1]);
const color = (p[1] >= 0) ? '#0891b2' : '#ef4444';
g += '<circle cx="'+x.toFixed(1)+'" cy="'+y.toFixed(1)+'" r="5" fill="'+color+'" stroke="#fff" stroke-width="2"/>';
});
svg.innerHTML = g;
// формула
formula.innerHTML = '$b_n = ' + b1 + ' \\cdot (' + fmtQ(q) + ')^{n - 1}$';
// первые 6 членов
const first6 = pts.slice(0,6).map(p=>fmt(+p[1].toFixed(4))).join(',\\ ');
out.innerHTML = '<b>Первые 6 членов:</b> $' + first6 + ',\\ \\ldots$';
// описание поведения
let txt = '';
const aq = Math.abs(q);
if (q === 0){ txt = 'При $q = 0$ прогрессия не определена (со 2-го члена все нули).'; }
else if (aq > 1) txt = 'Модули растут (|q| > 1). ';
else if (aq < 1) txt = 'Модули убывают к 0 (|q| < 1). ';
else txt = 'Все члены по модулю равны $|b_1|$ (|q| = 1). ';
if (q < 0) txt += 'Знаки чередуются (q < 0).';
else if (q > 0) txt += 'Все члены одного знака (q > 0).';
desc.textContent = txt;
renderMath(formula); renderMath(out);
if (!bumped){ bumped = true; bumpProgress('p17', 15); addXp(10,'p17-iv1'); }
}
b1Sl.addEventListener('input', redraw);
qSl.addEventListener('input', redraw);
redraw();
})();
/* ===== IV2 wiring ===== */
(function(){
// Найти b_n
const outA = document.getElementById('p17-iv2a-out');
let bumpedA = false;
document.getElementById('p17-iv2a-go').addEventListener('click', ()=>{
const b1 = +document.getElementById('p17-iv2a-b1').value;
const q = +document.getElementById('p17-iv2a-q').value;
const n = +document.getElementById('p17-iv2a-n').value;
if (!Number.isInteger(n) || n < 1){ outA.innerHTML = 'Номер $n$ должен быть натуральным.'; renderMath(outA); return; }
if (q === 0){ outA.innerHTML = 'Знаменатель $q$ должен быть $\\ne 0$.'; renderMath(outA); return; }
const bn = b1 * Math.pow(q, n - 1);
outA.innerHTML = '$b_{'+n+'} = '+b1+' \\cdot ('+fmt(q)+')^{'+n+' - 1} = '+b1+' \\cdot ('+fmt(q)+')^{'+(n-1)+'} = \\mathbf{'+fmt(+bn.toFixed(6))+'}$';
renderMath(outA);
if (!bumpedA){ bumpedA = true; bumpProgress('p17', 8); addXp(5,'p17-iv2a'); }
});
// Найти q
const outB = document.getElementById('p17-iv2b-out');
let bumpedB = false;
document.getElementById('p17-iv2b-go').addEventListener('click', ()=>{
const b1 = +document.getElementById('p17-iv2b-b1').value;
const bn = +document.getElementById('p17-iv2b-bn').value;
const n = +document.getElementById('p17-iv2b-n').value;
if (!Number.isInteger(n) || n < 2){ outB.innerHTML = '$n$ должно быть целым и $\\ge 2$.'; renderMath(outB); return; }
if (b1 === 0){ outB.innerHTML = 'Должно быть $b_1 \\ne 0$.'; renderMath(outB); return; }
const ratio = bn / b1;
const k = n - 1;
// действительный корень (положительный)
let qPos;
if (ratio >= 0) qPos = Math.pow(ratio, 1/k);
else if (k % 2 === 1) qPos = -Math.pow(-ratio, 1/k);
else qPos = NaN;
if (!isFinite(qPos) || isNaN(qPos)){
outB.innerHTML = '$\\dfrac{b_n}{b_1} = '+fmt(ratio)+' < 0$, а степень $n - 1 = '+k+'$ чётная — действительного $q$ нет.';
renderMath(outB); return;
}
outB.innerHTML = '$q^{'+k+'} = \\dfrac{b_n}{b_1} = \\dfrac{'+bn+'}{'+b1+'} = '+fmt(ratio)+'$ &nbsp; $\\Rightarrow$ &nbsp; $q = \\sqrt['+k+']{'+fmt(ratio)+'} = \\mathbf{'+fmt(+qPos.toFixed(6))+'}$';
renderMath(outB);
if (!bumpedB){ bumpedB = true; bumpProgress('p17', 7); addXp(5,'p17-iv2b'); }
});
})();
/* ===== IV3 wiring ===== */
(function(){
const items = [
{ q:'$1,\\ 2,\\ 4,\\ 8,\\ \\ldots$', ans:true, hint:'Отношение $q = 2$ постоянно.' },
{ q:'$3,\\ 6,\\ 9,\\ 12,\\ \\ldots$', ans:false, hint:'Отношения $2, 1.5, \\tfrac{4}{3}$ — разные. Это арифметическая ($d = 3$).' },
{ q:'$5,\\ 5,\\ 5,\\ 5,\\ \\ldots$', ans:true, hint:'Это геом. прогрессия с $q = 1$ (и одновременно арифм. с $d = 0$).' },
{ q:'$81,\\ -27,\\ 9,\\ -3,\\ \\ldots$', ans:true, hint:'$q = -\\dfrac{1}{3}$ постоянна — знаки чередуются.' },
{ q:'$2,\\ 4,\\ 6,\\ 8,\\ \\ldots$', ans:false, hint:'Отношения $2, 1.5, \\tfrac{4}{3}$ — не равны. Это арифм. с $d = 2$.' },
{ q:'$1,\\ \\dfrac{1}{2},\\ \\dfrac{1}{4},\\ \\dfrac{1}{8},\\ \\ldots$', ans:true, hint:'$q = \\dfrac{1}{2}$ постоянна.' }
];
let i = 0, sc = 0;
const idxEl = document.getElementById('p17-iv3-idx');
const scEl = document.getElementById('p17-iv3-sc');
const qEl = document.getElementById('p17-iv3-q');
const fb = document.getElementById('p17-iv3-fb');
const yBtn = document.getElementById('p17-iv3-y');
const nBtn = document.getElementById('p17-iv3-n');
let bumped = false;
function render(){
idxEl.textContent = Math.min(i+1, items.length);
scEl.textContent = sc;
if (i >= items.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
yBtn.disabled = true; nBtn.disabled = true;
yBtn.style.opacity = .5; nBtn.style.opacity = .5;
if (!bumped){ bumped = true; bumpProgress('p17', 25); addXp(15,'p17-iv3'); }
return;
}
qEl.innerHTML = items[i].q;
fb.style.display = 'none';
renderMath(qEl);
}
function answer(v){
if (i >= items.length) return;
const it = items[i];
const ok = (v === it.ans);
if (ok) sc++;
feedback(fb, ok, (ok?'&#10003; Верно. ':'&#10007; Неверно. ') + it.hint);
i++;
setTimeout(render, 1100);
}
yBtn.addEventListener('click', ()=>answer(true));
nBtn.addEventListener('click', ()=>answer(false));
render();
})();
/* ===== IV4 wiring — тренажёр ===== */
(function(){
const items = [
{ q:'$b_1 = 2,\\ q = 3$. Найти $b_4$.', ans: 54 },
{ q:'$b_1 = 64,\\ q = \\dfrac{1}{2}$. Найти $b_5$.', ans: 4 },
{ q:'$b_1 = 5,\\ b_3 = 45$. Найти $q$ (положительный).', ans: 3 },
{ q:'$b_2 = 6,\\ b_4 = 24$. Найти $q$ (положительный).', ans: 2 },
{ q:'Найти среднее геометрическое чисел $2$ и $8$ (положительное).', ans: 4 },
{ q:'$b_1 = 3,\\ q = -2$. Найти $b_4$.', ans: -24 }
];
let i = 0, sc = 0;
const idxEl = document.getElementById('p17-iv4-idx');
const scEl = document.getElementById('p17-iv4-sc');
const qEl = document.getElementById('p17-iv4-q');
const inp = document.getElementById('p17-iv4-ans');
const btn = document.getElementById('p17-iv4-go');
const fb = document.getElementById('p17-iv4-fb');
let bumped = false;
function render(){
idxEl.textContent = Math.min(i+1, items.length);
scEl.textContent = sc;
if (i >= items.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
inp.disabled = true; btn.disabled = true;
inp.style.opacity = .5; btn.style.opacity = .5;
if (!bumped){ bumped = true; bumpProgress('p17', 25); addXp(15,'p17-iv4'); }
return;
}
qEl.innerHTML = items[i].q;
inp.value = ''; fb.style.display = 'none';
renderMath(qEl);
}
btn.addEventListener('click', ()=>{
if (i >= items.length) return;
const v = +inp.value;
const it = items[i];
const ok = (v === it.ans);
if (ok) sc++;
feedback(fb, ok, ok ? '&#10003; Верно: $'+it.ans+'$' : '&#10007; Неверно. Правильный ответ: $'+it.ans+'$');
i++;
setTimeout(render, 1100);
});
inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ e.preventDefault(); btn.click(); } });
render();
})();
wireReadBtn('p17');
}