feat(alg11 ch1 wave2): §2 «Степенная функция y = x^α» + главный визуализатор
This commit is contained in:
@@ -923,15 +923,452 @@ function buildP1(){
|
||||
function buildP2(){
|
||||
const box = document.getElementById('p2-body');
|
||||
let html = '';
|
||||
html += makeCard('theory', 'В разработке', '2.0', `
|
||||
<p>Содержание параграфа <b>Степенная функция</b> будет добавлено в Phase 1+.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Ключевая формула: $y = x^\alpha$</p>
|
||||
`);
|
||||
html += secNavFor('p2');
|
||||
|
||||
html += makeCard('theory', 'Определение и классификация', '2.1', `
|
||||
<p>Функция вида $y = x^\\alpha$, где $\\alpha$ — действительное число, называется <b>степенной функцией</b>.</p>
|
||||
<p>Свойства функции $y = x^\\alpha$ (область определения, чётность, монотонность, вид графика) полностью зависят от того, какое число $\\alpha$:</p>
|
||||
<ul style="margin:8px 0 8px 22px;line-height:1.75">
|
||||
<li><b>Натуральное чётное</b> ($\\alpha = 2, 4, 6, \\ldots$) — парабола, чётная функция, $D = \\mathbb{R}$.</li>
|
||||
<li><b>Натуральное нечётное</b> ($\\alpha = 1, 3, 5, \\ldots$) — нечётная функция, $D = \\mathbb{R}$.</li>
|
||||
<li><b>Целое отрицательное</b> ($\\alpha = -1, -2, \\ldots$) — гипербола, есть асимптоты $x = 0$ и $y = 0$.</li>
|
||||
<li><b>Дробное вида $1/n$</b> — корень $\\sqrt[n]{x}$.</li>
|
||||
<li><b>Иррациональное</b> ($\\alpha = \\sqrt{2},\\ \\pi,\\ e,\\ \\ldots$) — определена только при $x > 0$.</li>
|
||||
</ul>
|
||||
<p>Несмотря на это разнообразие, все графики $y = x^\\alpha$ при $x = 1$ проходят через одну и ту же точку $(1; 1)$.</p>`);
|
||||
|
||||
html += makeCard('rule', 'Шесть ключевых случаев — свойства', '2.2', `
|
||||
<p>Перед нами таблица свойств $y = x^\\alpha$ для самых важных значений $\\alpha$.</p>
|
||||
<div style="overflow-x:auto;margin:10px 0">
|
||||
<table style="width:100%;border-collapse:collapse;font-size:.86rem">
|
||||
<thead>
|
||||
<tr style="background:var(--sec-acc-soft)">
|
||||
<th style="padding:8px;border:1px solid var(--border);text-align:left">Случай</th>
|
||||
<th style="padding:8px;border:1px solid var(--border);text-align:left">$D$</th>
|
||||
<th style="padding:8px;border:1px solid var(--border);text-align:left">$E$</th>
|
||||
<th style="padding:8px;border:1px solid var(--border);text-align:left">Чётность</th>
|
||||
<th style="padding:8px;border:1px solid var(--border);text-align:left">Монотонность</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td style="padding:7px;border:1px solid var(--border)"><b>$\\alpha = 2k$</b> (нат. чёт.)</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R}$</td><td style="padding:7px;border:1px solid var(--border)">$[0; +\\infty)$</td><td style="padding:7px;border:1px solid var(--border)">чётная</td><td style="padding:7px;border:1px solid var(--border)">$\\searrow$ на $(-\\infty; 0]$, $\\nearrow$ на $[0; +\\infty)$</td></tr>
|
||||
<tr><td style="padding:7px;border:1px solid var(--border)"><b>$\\alpha = 2k+1$</b> (нат. неч.)</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R}$</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R}$</td><td style="padding:7px;border:1px solid var(--border)">нечётная</td><td style="padding:7px;border:1px solid var(--border)">$\\nearrow$ на $\\mathbb{R}$</td></tr>
|
||||
<tr><td style="padding:7px;border:1px solid var(--border)"><b>$\\alpha = -2k$</b> (целое отр. чёт.)</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R} \\setminus \\{0\\}$</td><td style="padding:7px;border:1px solid var(--border)">$(0; +\\infty)$</td><td style="padding:7px;border:1px solid var(--border)">чётная</td><td style="padding:7px;border:1px solid var(--border)">$\\nearrow$ на $(-\\infty; 0)$, $\\searrow$ на $(0; +\\infty)$</td></tr>
|
||||
<tr><td style="padding:7px;border:1px solid var(--border)"><b>$\\alpha = -(2k+1)$</b> (целое отр. неч.)</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R} \\setminus \\{0\\}$</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R} \\setminus \\{0\\}$</td><td style="padding:7px;border:1px solid var(--border)">нечётная</td><td style="padding:7px;border:1px solid var(--border)">$\\searrow$ на каждом промежутке</td></tr>
|
||||
<tr><td style="padding:7px;border:1px solid var(--border)"><b>$\\alpha = 1/n$</b> ($n$ чёт.)</td><td style="padding:7px;border:1px solid var(--border)">$[0; +\\infty)$</td><td style="padding:7px;border:1px solid var(--border)">$[0; +\\infty)$</td><td style="padding:7px;border:1px solid var(--border)">—</td><td style="padding:7px;border:1px solid var(--border)">$\\nearrow$</td></tr>
|
||||
<tr><td style="padding:7px;border:1px solid var(--border)"><b>$\\alpha = 1/n$</b> ($n$ неч.)</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R}$</td><td style="padding:7px;border:1px solid var(--border)">$\\mathbb{R}$</td><td style="padding:7px;border:1px solid var(--border)">нечётная</td><td style="padding:7px;border:1px solid var(--border)">$\\nearrow$</td></tr>
|
||||
<tr><td style="padding:7px;border:1px solid var(--border)"><b>$\\alpha$ иррац.</b></td><td style="padding:7px;border:1px solid var(--border)">$(0; +\\infty)$</td><td style="padding:7px;border:1px solid var(--border)">$(0; +\\infty)$</td><td style="padding:7px;border:1px solid var(--border)">—</td><td style="padding:7px;border:1px solid var(--border)">$\\nearrow$ при $\\alpha > 0$; $\\searrow$ при $\\alpha < 0$</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p><b>Все графики проходят через $(1; 1)$:</b> ведь $1^\\alpha = 1$ при любом $\\alpha$.</p>`);
|
||||
|
||||
html += makeCard('example', 'Степенные функции в природе и физике', '2.3', `
|
||||
<p>Степенная функция $y = x^\\alpha$ — не абстракция: она описывает множество законов природы и формул из геометрии.</p>
|
||||
<ul style="margin:8px 0 8px 22px;line-height:1.85">
|
||||
<li><b>Закон Гука:</b> $F = kx$ — степенная с $\\alpha = 1$ (прямая пропорциональность).</li>
|
||||
<li><b>Площадь круга:</b> $S = \\pi r^2$ — степенная с $\\alpha = 2$.</li>
|
||||
<li><b>Объём шара:</b> $V = \\dfrac{4}{3} \\pi r^3$ — степенная с $\\alpha = 3$.</li>
|
||||
<li><b>Закон обратных квадратов</b> (гравитация, освещённость): $F = \\dfrac{k}{r^2}$ — степенная с $\\alpha = -2$.</li>
|
||||
<li><b>Период математического маятника:</b> $T = 2\\pi \\sqrt{\\dfrac{l}{g}}$ — степенная по $l$ с $\\alpha = \\dfrac{1}{2}$.</li>
|
||||
<li><b>Третий закон Кеплера:</b> $T^2 \\sim a^3$ или $T \\sim a^{3/2}$ — степенная с иррациональным показателем близкой формы.</li>
|
||||
</ul>
|
||||
<p>Знание свойств степенной функции — это <b>универсальный инструмент</b> для понимания физики, химии, биологии и техники.</p>`);
|
||||
|
||||
/* INTERACTIVE 1 — главный визуализатор y = x^alpha */
|
||||
html += `<div class="wg" id="p2-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Главный визуализатор $y = x^\\alpha$</div></div>
|
||||
<div class="wg-help">Меняй $\\alpha$ ползунком — наблюдай, как меняется график. Snap-точки: $-2,\\ -1,\\ -\\tfrac{1}{2},\\ 0,\\ \\tfrac{1}{2},\\ 1,\\ 2,\\ 3$. Точка $(1; 1)$ всегда на графике.</div>
|
||||
<div class="sliders">
|
||||
<label>Показатель $\\alpha$ = <b id="p2-iv1-a">2</b><input type="range" id="p2-iv1-sa" min="-3" max="3" step="0.1" value="2"></label>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;font-size:.82rem">
|
||||
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer"><input type="checkbox" id="p2-iv1-cb-1"> $y = x$ <span style="color:#94a3b8">(серый)</span></label>
|
||||
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer"><input type="checkbox" id="p2-iv1-cb-2"> $y = x^{2}$ <span style="color:#a78bfa">(фиолет.)</span></label>
|
||||
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer"><input type="checkbox" id="p2-iv1-cb-3"> $y = x^{3}$ <span style="color:#3b82f6">(син.)</span></label>
|
||||
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer"><input type="checkbox" id="p2-iv1-cb-h"> $y = 1/x$ <span style="color:#ef4444">(красн.)</span></label>
|
||||
</div>
|
||||
<div style="background:var(--card);border-radius:9px;padding:10px;text-align:center"><svg id="p2-iv1-svg" viewBox="0 0 480 360" width="100%" style="max-width:480px;height:auto"></svg></div>
|
||||
<div id="p2-iv1-desc" style="margin-top:10px;padding:12px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.94rem;line-height:1.65;min-height:90px"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 2 — калькулятор D и E */
|
||||
html += `<div class="wg" id="p2-iv2">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор $D$ и $E$</div></div>
|
||||
<div class="wg-help">Введи показатель $\\alpha$ (целое, дробное вида $p/q$ или иррациональное вроде $\\sqrt{2} \\approx 1{,}41$, $\\pi \\approx 3{,}14$). Получи области определения и значений.</div>
|
||||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:10px">
|
||||
<span style="font-family:'JetBrains Mono',monospace">$\\alpha$ =</span>
|
||||
<input type="number" id="p2-iv2-a" class="tinp" style="width:110px;text-align:center" value="2" step="0.01">
|
||||
<button class="btn primary" id="p2-iv2-go">Определить $D$ и $E$</button>
|
||||
</div>
|
||||
<div id="p2-iv2-out" style="padding:12px 14px;background:var(--card);border-radius:9px;font-size:.94rem;min-height:80px;line-height:1.75"></div>
|
||||
<div class="feedback" id="p2-iv2-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 3 — квикфайр «Какая функция?» */
|
||||
html += `<div class="wg" id="p2-iv3">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Какая функция? Угадай $\\alpha$</div></div>
|
||||
<div class="wg-help">По описанию графика выбери правильное значение $\\alpha$ из 4 вариантов. 8 заданий.</div>
|
||||
<div class="score-display"><span>Задача <b id="p2-iv3-i">1</b> / 8</span><span>Очки: <b id="p2-iv3-s">0</b> / 8</span></div>
|
||||
<div id="p2-iv3-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.05rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
|
||||
<div id="p2-iv3-opts" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px"></div>
|
||||
<div class="feedback" id="p2-iv3-fb"></div>
|
||||
<div class="actions"><button class="btn" id="p2-iv3-restart">Начать заново</button></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 4 — тренажёр свойств */
|
||||
html += `<div class="wg" id="p2-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр: свойства степенной функции</div></div>
|
||||
<div class="wg-help">6 задач: подсчёт корней, вычисление значения, поиск $\\alpha$. Допуск $\\pm 0{,}05$.</div>
|
||||
<div class="score-display"><span>Задача <b id="p2-iv4-i">1</b> / 6</span><span>Очки: <b id="p2-iv4-s">0</b> / 6</span></div>
|
||||
<div id="p2-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.1rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
|
||||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">
|
||||
<span style="font-family:'JetBrains Mono',monospace">ответ =</span>
|
||||
<input type="number" id="p2-iv4-ans" class="tinp" style="width:110px;text-align:center" step="0.01">
|
||||
<button class="btn primary" id="p2-iv4-go">Проверить</button>
|
||||
<button class="btn" id="p2-iv4-start">Заново</button>
|
||||
</div>
|
||||
<div class="feedback" id="p2-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
html += secNav('p1', 'p3');
|
||||
html += readButton('p2');
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
|
||||
/* IV1 — главный визуализатор y = x^alpha */
|
||||
(function(){
|
||||
const sa = document.getElementById('p2-iv1-sa');
|
||||
const aL = document.getElementById('p2-iv1-a');
|
||||
const svg = document.getElementById('p2-iv1-svg');
|
||||
const desc = document.getElementById('p2-iv1-desc');
|
||||
const cb1 = document.getElementById('p2-iv1-cb-1');
|
||||
const cb2 = document.getElementById('p2-iv1-cb-2');
|
||||
const cb3 = document.getElementById('p2-iv1-cb-3');
|
||||
const cbh = document.getElementById('p2-iv1-cb-h');
|
||||
const SNAP = [-2, -1, -0.5, 0, 0.5, 1, 2, 3];
|
||||
const seen = new Set();
|
||||
let _done = false;
|
||||
|
||||
function alphaColor(a){
|
||||
if(a < 0) return '#ef4444';
|
||||
if(!Number.isInteger(a)) return '#f59e0b';
|
||||
if(a % 2 === 0) return '#a78bfa';
|
||||
return '#3b82f6';
|
||||
}
|
||||
function alphaLabel(a){
|
||||
if(Math.abs(a) < 0.001) return '0';
|
||||
if(Math.abs(a - Math.round(a)) < 0.001) return String(Math.round(a));
|
||||
if(Math.abs(a - 0.5) < 0.001) return '\\tfrac{1}{2}';
|
||||
if(Math.abs(a + 0.5) < 0.001) return '-\\tfrac{1}{2}';
|
||||
if(Math.abs(a - 1/3) < 0.01) return '\\tfrac{1}{3}';
|
||||
return (+a.toFixed(2)).toString();
|
||||
}
|
||||
function powSafe(x, a){
|
||||
if(x === 0){
|
||||
if(a > 0) return 0;
|
||||
return NaN;
|
||||
}
|
||||
if(x > 0) return Math.pow(x, a);
|
||||
// x < 0
|
||||
if(Number.isInteger(a)) return Math.pow(x, a);
|
||||
// дробное alpha с нечётным знаменателем → пробуем как корень
|
||||
// ищем простую рациональную аппроксимацию для snap-значений
|
||||
const snapMatch = SNAP.find(s => Math.abs(s - a) < 0.001);
|
||||
if(snapMatch !== undefined){
|
||||
// 1/3 - кубический корень определён для x<0
|
||||
if(Math.abs(snapMatch - 1/3) < 0.001) return -Math.pow(-x, 1/3);
|
||||
}
|
||||
return NaN;
|
||||
}
|
||||
function describe(a){
|
||||
const eps = 0.05;
|
||||
if(Math.abs(a) < eps) return '<b>$\\alpha = 0$:</b> $y = x^0 = 1$ при $x \\ne 0$. Горизонтальная прямая (с выколотой точкой в $x = 0$).';
|
||||
if(Math.abs(a - Math.round(a)) < eps){
|
||||
const n = Math.round(a);
|
||||
if(n > 0){
|
||||
if(n % 2 === 0){
|
||||
return '<b>Натуральное чётное</b> ($\\alpha = '+n+'$): парабола $'+n+'$-й степени.<br>$D = \\mathbb{R}$, $E = [0; +\\infty)$. <b>Чётная</b> функция (симметрия отн. $Oy$).<br>Убывает на $(-\\infty; 0]$, возрастает на $[0; +\\infty)$.';
|
||||
} else {
|
||||
return '<b>Натуральное нечётное</b> ($\\alpha = '+n+'$): $y = x^{'+n+'}$.<br>$D = \\mathbb{R}$, $E = \\mathbb{R}$. <b>Нечётная</b> функция (симметрия отн. начала координат).<br>Возрастает на всей $\\mathbb{R}$.';
|
||||
}
|
||||
} else {
|
||||
if(n % 2 === 0){
|
||||
return '<b>Целое отрицательное чётное</b> ($\\alpha = '+n+'$): $y = \\dfrac{1}{x^{'+(-n)+'}}$.<br>$D = \\mathbb{R} \\setminus \\{0\\}$, $E = (0; +\\infty)$. <b>Чётная</b>. Асимптоты: $x = 0$, $y = 0$.';
|
||||
} else {
|
||||
return '<b>Целое отрицательное нечётное</b> ($\\alpha = '+n+'$): гипербола $y = \\dfrac{1}{x^{'+(-n)+'}}$.<br>$D = \\mathbb{R} \\setminus \\{0\\}$, $E = \\mathbb{R} \\setminus \\{0\\}$. <b>Нечётная</b>. Асимптоты: $x = 0$, $y = 0$.';
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Math.abs(a - 0.5) < eps){
|
||||
return '<b>$\\alpha = \\tfrac{1}{2}$:</b> квадратный корень $y = \\sqrt{x}$.<br>$D = [0; +\\infty)$, $E = [0; +\\infty)$. Возрастает на области определения.';
|
||||
}
|
||||
if(Math.abs(a + 0.5) < eps){
|
||||
return '<b>$\\alpha = -\\tfrac{1}{2}$:</b> $y = \\dfrac{1}{\\sqrt{x}}$.<br>$D = (0; +\\infty)$, $E = (0; +\\infty)$. Убывает. Асимптоты $x = 0$, $y = 0$.';
|
||||
}
|
||||
if(a > 0){
|
||||
return '<b>Дробный положительный</b> ($\\alpha \\approx '+(+a.toFixed(2))+'$): $D = [0; +\\infty)$, возрастает.';
|
||||
}
|
||||
return '<b>Отрицательный</b> ($\\alpha \\approx '+(+a.toFixed(2))+'$): $D = (0; +\\infty)$, убывает. Асимптоты $x = 0$, $y = 0$.';
|
||||
}
|
||||
function draw(){
|
||||
let a = +sa.value;
|
||||
a = snapToValue(a, SNAP, 0.08);
|
||||
aL.textContent = alphaLabel(a);
|
||||
const xmin = -3.5, xmax = 3.5, ymin = -3.5, ymax = 3.5;
|
||||
const W = 480, H = 360, pad = 24;
|
||||
const ax = axes2D(W, H, pad, xmin, xmax, ymin, ymax);
|
||||
let g = ax.content;
|
||||
// эталоны
|
||||
if(cb1.checked) g += plotFunc(x => x, xmin, xmax, ax.toX, ax.toY, '#94a3b8');
|
||||
if(cb2.checked) g += plotFunc(x => x*x, xmin, xmax, ax.toX, ax.toY, '#a78bfa');
|
||||
if(cb3.checked) g += plotFunc(x => x*x*x, xmin, xmax, ax.toX, ax.toY, '#3b82f6');
|
||||
if(cbh.checked){
|
||||
g += plotFunc(x => 1/x, 0.001, xmax, ax.toX, ax.toY, '#ef4444');
|
||||
g += plotFunc(x => 1/x, xmin, -0.001, ax.toX, ax.toY, '#ef4444');
|
||||
}
|
||||
// главный график
|
||||
const col = alphaColor(a);
|
||||
const isIntA = Math.abs(a - Math.round(a)) < 0.001;
|
||||
const intA = Math.round(a);
|
||||
if(isIntA && intA !== 0){
|
||||
// целое: рисуем на обеих сторонах
|
||||
if(intA > 0){
|
||||
g += '<path d="' + (function(){
|
||||
// объединить два куска
|
||||
return '';
|
||||
})() + '" />';
|
||||
g += plotFunc(x => powSafe(x, intA), xmin, xmax, ax.toX, ax.toY, col, 300);
|
||||
} else {
|
||||
// отрицательное целое
|
||||
g += plotFunc(x => powSafe(x, intA), 0.05, xmax, ax.toX, ax.toY, col, 200);
|
||||
g += plotFunc(x => powSafe(x, intA), xmin, -0.05, ax.toX, ax.toY, col, 200);
|
||||
g += asymptote('v', 0, ax.toX, ax.toY, xmin, xmax, ymin, ymax, '#cbd5e1');
|
||||
}
|
||||
} else if(Math.abs(a) < 0.001){
|
||||
// y = 1
|
||||
g += plotFunc(x => 1, 0.001, xmax, ax.toX, ax.toY, col);
|
||||
g += plotFunc(x => 1, xmin, -0.001, ax.toX, ax.toY, col);
|
||||
} else {
|
||||
// дробное / иррациональное
|
||||
if(a > 0){
|
||||
g += plotFunc(x => Math.pow(x, a), 0.001, xmax, ax.toX, ax.toY, col, 250);
|
||||
// если a = 1/3 — рисуем и слева
|
||||
if(Math.abs(a - 1/3) < 0.05){
|
||||
g += plotFunc(x => -Math.pow(-x, a), xmin, -0.001, ax.toX, ax.toY, col, 250);
|
||||
}
|
||||
} else {
|
||||
g += plotFunc(x => Math.pow(x, a), 0.05, xmax, ax.toX, ax.toY, col, 250);
|
||||
g += asymptote('v', 0, ax.toX, ax.toY, xmin, xmax, ymin, ymax, '#cbd5e1');
|
||||
}
|
||||
}
|
||||
// точка (1, 1)
|
||||
g += pointWithDrop(1, 1, ax.toX, ax.toY, '#0f172a', '(1; 1)');
|
||||
svg.innerHTML = g;
|
||||
desc.innerHTML = describe(a);
|
||||
renderMath(desc);
|
||||
const key = (+a.toFixed(2)).toString();
|
||||
seen.add(key);
|
||||
if(!_done && seen.size >= 6){ _done = true; addXp(10, 'p2-iv1'); bumpProgress('p2', 15); }
|
||||
}
|
||||
sa.addEventListener('input', draw);
|
||||
[cb1,cb2,cb3,cbh].forEach(c => c.addEventListener('change', draw));
|
||||
draw();
|
||||
})();
|
||||
|
||||
/* IV2 — калькулятор D и E */
|
||||
(function(){
|
||||
const aI = document.getElementById('p2-iv2-a');
|
||||
const out = document.getElementById('p2-iv2-out');
|
||||
const fb = document.getElementById('p2-iv2-fb');
|
||||
const go = document.getElementById('p2-iv2-go');
|
||||
const used = new Set();
|
||||
let _done = false;
|
||||
|
||||
function findFraction(a, maxDen){
|
||||
maxDen = maxDen || 20;
|
||||
for(let n = 2; n <= maxDen; n++){
|
||||
for(let m = -3*n; m <= 3*n; m++){
|
||||
if(m === 0) continue;
|
||||
if(Math.abs(m/n - a) < 0.005){
|
||||
const g = gcd(Math.abs(m), n);
|
||||
return { num: m/g, den: n/g };
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function analyze(){
|
||||
const a = +aI.value;
|
||||
if(!isFinite(a)){ feedback(fb, false, '✗ Введи число.'); return; }
|
||||
let D = '', E = '', kind = '';
|
||||
const isInt = Math.abs(a - Math.round(a)) < 0.005;
|
||||
const intA = Math.round(a);
|
||||
|
||||
if(isInt){
|
||||
if(intA === 0){
|
||||
kind = '$\\alpha = 0$: константа $y = 1$';
|
||||
D = '$D = \\mathbb{R} \\setminus \\{0\\}$ (точка $x = 0$ исключена)';
|
||||
E = '$E = \\{1\\}$';
|
||||
} else if(intA > 0){
|
||||
if(intA % 2 === 0){
|
||||
kind = 'Натуральное чётное $\\alpha = '+intA+'$ → парабола';
|
||||
D = '$D = \\mathbb{R}$ — определена везде';
|
||||
E = '$E = [0; +\\infty)$ — значения неотрицательны';
|
||||
} else {
|
||||
kind = 'Натуральное нечётное $\\alpha = '+intA+'$';
|
||||
D = '$D = \\mathbb{R}$ — определена везде';
|
||||
E = '$E = \\mathbb{R}$ — принимает любые значения';
|
||||
}
|
||||
} else {
|
||||
if(intA % 2 === 0){
|
||||
kind = 'Целое отрицательное чётное $\\alpha = '+intA+'$ → гипербола';
|
||||
D = '$D = \\mathbb{R} \\setminus \\{0\\}$';
|
||||
E = '$E = (0; +\\infty)$';
|
||||
} else {
|
||||
kind = 'Целое отрицательное нечётное $\\alpha = '+intA+'$';
|
||||
D = '$D = \\mathbb{R} \\setminus \\{0\\}$';
|
||||
E = '$E = \\mathbb{R} \\setminus \\{0\\}$';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const fr = findFraction(a);
|
||||
if(fr){
|
||||
const { num, den } = fr;
|
||||
const denOdd = den % 2 === 1;
|
||||
if(num > 0){
|
||||
if(denOdd){
|
||||
kind = 'Дробный $\\alpha = \\dfrac{'+num+'}{'+den+'}$ — знаменатель нечётный';
|
||||
D = '$D = \\mathbb{R}$ (корень $\\sqrt['+den+']{x^{'+num+'}}$ определён везде)';
|
||||
E = (num % 2 === 0) ? '$E = [0; +\\infty)$' : '$E = \\mathbb{R}$';
|
||||
} else {
|
||||
kind = 'Дробный $\\alpha = \\dfrac{'+num+'}{'+den+'}$ — знаменатель чётный';
|
||||
D = '$D = [0; +\\infty)$ (корень чётной степени)';
|
||||
E = '$E = [0; +\\infty)$';
|
||||
}
|
||||
} else {
|
||||
kind = 'Дробный отрицательный $\\alpha = \\dfrac{'+num+'}{'+den+'}$';
|
||||
D = denOdd ? '$D = \\mathbb{R} \\setminus \\{0\\}$' : '$D = (0; +\\infty)$';
|
||||
E = (Math.abs(num) % 2 === 0) ? '$E = (0; +\\infty)$' : (denOdd ? '$E = \\mathbb{R} \\setminus \\{0\\}$' : '$E = (0; +\\infty)$');
|
||||
}
|
||||
} else {
|
||||
// иррациональное
|
||||
if(a > 0){
|
||||
kind = '$\\alpha \\approx '+(+a.toFixed(3))+'$ — рассматриваем как иррациональное';
|
||||
D = '$D = [0; +\\infty)$ (для иррационального $\\alpha > 0$, включая $x = 0$)';
|
||||
E = '$E = [0; +\\infty)$';
|
||||
} else {
|
||||
kind = '$\\alpha \\approx '+(+a.toFixed(3))+'$ — иррациональное отрицательное';
|
||||
D = '$D = (0; +\\infty)$';
|
||||
E = '$E = (0; +\\infty)$';
|
||||
}
|
||||
}
|
||||
}
|
||||
out.innerHTML = '<div style="font-weight:700;color:var(--sec-acc-d);margin-bottom:8px">'+kind+'</div>'
|
||||
+ '<div style="margin-bottom:6px">' + D + '</div>'
|
||||
+ '<div>' + E + '</div>';
|
||||
renderMath(out);
|
||||
feedback(fb, true, '✓ Готово.');
|
||||
used.add((+a.toFixed(3)).toString());
|
||||
if(!_done && used.size >= 4){ _done = true; addXp(10, 'p2-iv2'); bumpProgress('p2', 15); }
|
||||
}
|
||||
go.addEventListener('click', analyze);
|
||||
aI.addEventListener('keydown', e => { if(e.key === 'Enter') analyze(); });
|
||||
})();
|
||||
|
||||
/* IV3 — квикфайр «Какая функция?» */
|
||||
(function(){
|
||||
const Q = [
|
||||
{ q:'Парабола $y = x^2$', opts:['1','2','3','-1'], ans:1 },
|
||||
{ q:'Кубическая функция $y = x^3$', opts:['1','2','3','-1'], ans:2 },
|
||||
{ q:'Гипербола $y = \\dfrac{1}{x}$', opts:['1','-1','-2','1/2'], ans:1 },
|
||||
{ q:'Прямая $y = x$', opts:['0','1','2','-1'], ans:1 },
|
||||
{ q:'Корень $y = \\sqrt{x}$', opts:['2','-2','1/2','1/3'], ans:2 },
|
||||
{ q:'Гипербола $y = \\dfrac{1}{x^2}$', opts:['-1','-2','2','1/2'], ans:1 },
|
||||
{ q:'Кубический корень $y = \\sqrt[3]{x}$', opts:['3','-1/3','1/3','1/2'], ans:2 },
|
||||
{ q:'Парабола 4-й степени $y = x^4$', opts:['2','3','4','-4'], ans:2 },
|
||||
];
|
||||
let i = 0, score = 0;
|
||||
const qEl = document.getElementById('p2-iv3-q');
|
||||
const oEl = document.getElementById('p2-iv3-opts');
|
||||
const fb = document.getElementById('p2-iv3-fb');
|
||||
const iEl = document.getElementById('p2-iv3-i');
|
||||
const sEl = document.getElementById('p2-iv3-s');
|
||||
|
||||
function show(){
|
||||
if(i >= Q.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
|
||||
oEl.innerHTML = '';
|
||||
if(score === Q.length){ addXp(15, 'p2-iv3'); bumpProgress('p2', 25); }
|
||||
else if(score >= 5){ addXp(8, 'p2-iv3'); bumpProgress('p2', 15); }
|
||||
return;
|
||||
}
|
||||
iEl.textContent = (i+1);
|
||||
sEl.textContent = score;
|
||||
const item = Q[i];
|
||||
qEl.innerHTML = item.q;
|
||||
oEl.innerHTML = item.opts.map((o, k) => '<button class="btn primary" data-k="'+k+'" style="font-family:JetBrains Mono,monospace">$\\alpha = '+o+'$</button>').join('');
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl); renderMath(oEl);
|
||||
oEl.querySelectorAll('button').forEach(b => {
|
||||
b.addEventListener('click', () => {
|
||||
const k = +b.dataset.k;
|
||||
if(k === item.ans){ score++; feedback(fb, true, '✓ Верно! Дальше ▶'); }
|
||||
else feedback(fb, false, '✗ Неверно. Правильно: $\\alpha = '+item.opts[item.ans]+'$. Дальше ▶');
|
||||
sEl.textContent = score;
|
||||
oEl.querySelectorAll('button').forEach(x => x.disabled = true);
|
||||
i++;
|
||||
setTimeout(show, 1200);
|
||||
});
|
||||
});
|
||||
}
|
||||
document.getElementById('p2-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); });
|
||||
show();
|
||||
})();
|
||||
|
||||
/* IV4 — тренажёр свойств */
|
||||
(function(){
|
||||
const Q = [
|
||||
{ q:'Сколько решений у уравнения $x^4 = 16$?', ans:2, hint:'$x = \\pm 2$ — два корня' },
|
||||
{ q:'Сколько решений у уравнения $x^3 = -8$?', ans:1, hint:'$x = -2$ — единственный действительный корень' },
|
||||
{ q:'Найдите $y(4)$ для $y = x^{3/2}$', ans:8, hint:'$4^{3/2} = (\\sqrt{4})^3 = 2^3 = 8$' },
|
||||
{ q:'Чему равно $\\alpha$ у функции $y = \\sqrt[3]{x^4}$? (десятичная)', ans:4/3, hint:'$\\sqrt[3]{x^4} = x^{4/3} \\approx 1{,}33$' },
|
||||
{ q:'Для $y = x^{-2}$ найди $y(0{,}5)$', ans:4, hint:'$0{,}5^{-2} = \\dfrac{1}{0{,}25} = 4$' },
|
||||
{ q:'При $\\alpha = \\dfrac{1}{3}$ найди $y(-27)$', ans:-3, hint:'$\\sqrt[3]{-27} = -3$' },
|
||||
];
|
||||
let i = 0, score = 0;
|
||||
function show(){
|
||||
if(i >= Q.length){
|
||||
document.getElementById('p2-iv4-q').innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
|
||||
if(score === Q.length){ addXp(15, 'p2-iv4'); bumpProgress('p2', 25); }
|
||||
else if(score >= 4){ addXp(8, 'p2-iv4'); bumpProgress('p2', 15); }
|
||||
return;
|
||||
}
|
||||
document.getElementById('p2-iv4-i').textContent = (i+1);
|
||||
document.getElementById('p2-iv4-s').textContent = score;
|
||||
document.getElementById('p2-iv4-q').innerHTML = Q[i].q;
|
||||
document.getElementById('p2-iv4-ans').value = '';
|
||||
renderMath(document.getElementById('p2-iv4-q'));
|
||||
document.getElementById('p2-iv4-fb').style.display = 'none';
|
||||
}
|
||||
function go(){
|
||||
if(i >= Q.length) return;
|
||||
const fb = document.getElementById('p2-iv4-fb');
|
||||
const raw = document.getElementById('p2-iv4-ans').value.replace(',', '.');
|
||||
const ans = parseFloat(raw);
|
||||
if(isNaN(ans)){ feedback(fb, false, '✗ Введи число.'); return; }
|
||||
if(Math.abs(ans - Q[i].ans) < 0.05){ score++; feedback(fb, true, '✓ Верно! '+Q[i].hint+'. Дальше ▶'); }
|
||||
else feedback(fb, false, '✗ Неверно. Ответ $\\approx '+(+Q[i].ans.toFixed(2))+'$ ('+Q[i].hint+'). Дальше ▶');
|
||||
document.getElementById('p2-iv4-s').textContent = score;
|
||||
i++;
|
||||
setTimeout(show, 1300);
|
||||
}
|
||||
document.getElementById('p2-iv4-go').addEventListener('click', go);
|
||||
document.getElementById('p2-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); });
|
||||
document.getElementById('p2-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); });
|
||||
show();
|
||||
})();
|
||||
|
||||
wireReadBtn('p2');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user