feat(alg11 ch1 wave1): §1 «Степень с рациональным показателем»
This commit is contained in:
@@ -129,6 +129,26 @@ a{color:inherit;text-decoration:none}
|
||||
.spoiler[open] summary::before{content:'\2212'}
|
||||
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
|
||||
|
||||
.dnd-pool{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;min-height:54px;transition:border-color .18s,background .18s}
|
||||
.dnd-pool.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid}
|
||||
.dnd-pool.col{flex-direction:column;align-items:stretch}
|
||||
.dnd-pool.col .dnd-chip{width:auto}
|
||||
.dnd-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--card);border:1.5px solid var(--border);border-radius:10px;cursor:grab;user-select:none;font-size:.92rem;line-height:1.4;transition:transform .12s,box-shadow .12s,border-color .12s;touch-action:none;max-width:100%}
|
||||
.dnd-chip:hover{transform:translateY(-1px);border-color:var(--sec-acc,var(--pri));box-shadow:var(--sh)}
|
||||
.dnd-chip:active{cursor:grabbing}
|
||||
.dnd-chip.armed{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));box-shadow:0 0 0 3px rgba(217,119,6,.22);transform:translateY(-1px)}
|
||||
.dnd-chip.dragging{opacity:.28}
|
||||
.dnd-chip.placed{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
|
||||
.dnd-chip .dnd-x{padding:0 5px;color:var(--muted);font-weight:700;font-size:1.05rem;border-radius:4px;cursor:pointer}
|
||||
.dnd-chip .dnd-x:hover{color:var(--bad,var(--fail));background:var(--fail-bg)}
|
||||
.drop-box{background:var(--card);border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:90px;transition:border-color .15s,background .15s}
|
||||
.drop-box:hover{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
|
||||
.drop-box h5{font-family:'Unbounded',sans-serif;font-size:.78rem;color:var(--sec-acc-d,var(--pri2));margin-bottom:8px;text-transform:uppercase;letter-spacing:.05em}
|
||||
.drop-box.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid;transform:scale(1.015)}
|
||||
.drop-items{display:flex;flex-wrap:wrap;gap:6px;min-height:32px}
|
||||
.dnd-hint{font-size:.78rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:6px}
|
||||
.dnd-hint svg{width:14px;height:14px;flex-shrink:0}
|
||||
|
||||
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
|
||||
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
|
||||
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
||||
@@ -444,6 +464,19 @@ function makeCard(kind, title, num, body){
|
||||
const labels = {repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно'};
|
||||
return '<div class="card"><div class="card-header"><div class="card-icon '+kind+'">'+ICONS[kind]+'</div><div class="card-title">'+(labels[kind]||'')+(title&&title!==labels[kind]?' \xb7 '+title:'')+'</div>'+(num?'<div class="card-num">'+num+'</div>':'')+'</div><div class="card-body">'+body+'</div></div>';
|
||||
}
|
||||
function setupSorter(cfg){
|
||||
const placed = {}; const pool = document.getElementById(cfg.poolId); const scope = document.querySelector(cfg.scopeSelector);
|
||||
if(!pool||!scope) return {placed,render:()=>{},reset:()=>{}};
|
||||
pool.classList.add('dnd-pool'); if(cfg.columnLayout) pool.classList.add('col');
|
||||
let armed = null;
|
||||
function buildChip(it,isPlaced){ const e=document.createElement('div'); e.className='dnd-chip'+(isPlaced?' placed':''); e.dataset.id=it.id; e.innerHTML='<span class="dnd-txt">'+it.html+'</span><span class="dnd-x" title="Убрать">\xd7</span>'; attach(e,it.id); return e; }
|
||||
function attach(elm,itId){ let ghost=null,dragging=false,sx=0,sy=0; elm.addEventListener('pointerdown',ev=>{ if(ev.button!==undefined&&ev.button!==0) return;
|
||||
ev.preventDefault(); if(ev.target.classList&&ev.target.classList.contains('dnd-x')){ ev.stopPropagation(); if(placed[itId]){delete placed[itId];render();}else if(armed===itId){armed=null;render();} return; } sx=ev.clientX;sy=ev.clientY; const r=elm.getBoundingClientRect(); const ox=ev.clientX-r.left,oy=ev.clientY-r.top; try{elm.setPointerCapture(ev.pointerId);}catch(e){} function onMove(e){ const dx=e.clientX-sx,dy=e.clientY-sy; if(!dragging&&Math.hypot(dx,dy)>8){ dragging=true; ghost=elm.cloneNode(true); ghost.classList.remove('armed'); ghost.style.cssText='position:fixed;z-index:9999;pointer-events:none;opacity:.9;transform:rotate(-2.5deg);box-shadow:0 14px 36px rgba(0,0,0,.32);width:'+r.width+'px;left:'+(e.clientX-ox)+'px;top:'+(e.clientY-oy)+'px'; document.body.appendChild(ghost); elm.classList.add('dragging'); } if(dragging&&ghost){ ghost.style.left=(e.clientX-ox)+'px';ghost.style.top=(e.clientY-oy)+'px'; const under=document.elementsFromPoint(e.clientX,e.clientY); scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); const tgt=under.find(n=>n.classList&&(n.classList.contains('drop-box')||n.classList.contains('dnd-pool'))); if(tgt)tgt.classList.add('over'); } } function onUp(e){ elm.removeEventListener('pointermove',onMove);elm.removeEventListener('pointerup',onUp);elm.removeEventListener('pointercancel',onUp);elm.classList.remove('dragging'); if(ghost){ghost.remove();ghost=null;} scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); if(dragging){ const under=document.elementsFromPoint(e.clientX,e.clientY); const box=under.find(n=>n.classList&&n.classList.contains('drop-box')); const pl=under.find(n=>n.classList&&n.classList.contains('dnd-pool')); if(box){const di=box.querySelector('[data-cat]');if(di){placed[itId]=di.dataset.cat;armed=null;render();return;}}else if(pl){delete placed[itId];armed=null;render();return;} }else{ if(placed[itId]){delete placed[itId];armed=null;render();}else{armed=(armed===itId)?null:itId;render();} } dragging=false; } elm.addEventListener('pointermove',onMove);elm.addEventListener('pointerup',onUp);elm.addEventListener('pointercancel',onUp); }); }
|
||||
function attachBoxTaps(){ scope.querySelectorAll('.drop-box').forEach(box=>{ box.addEventListener('click',ev=>{ if(!armed)return; if(ev.target.closest('.dnd-chip'))return; const di=box.querySelector('[data-cat]'); if(di){placed[armed]=di.dataset.cat;armed=null;render();} }); }); }
|
||||
function render(){ pool.innerHTML=''; cfg.items.forEach(it=>{if(placed[it.id])return;const c=buildChip(it,false);if(armed===it.id)c.classList.add('armed');pool.appendChild(c);}); cfg.cats.forEach(cat=>{const box=scope.querySelector('.drop-items[data-cat="'+cat+'"]');if(!box)return;box.innerHTML='';cfg.items.forEach(it=>{if(placed[it.id]!==cat)return;box.appendChild(buildChip(it,true));});}); if(window.renderMathInElement)try{renderMath(scope);}catch(_){} }
|
||||
attachBoxTaps(); render();
|
||||
return {placed,render,reset(){ for(const k in placed)delete placed[k];armed=null;render(); }};
|
||||
}
|
||||
|
||||
/* === SVG-хелперы (axes2D, plotFunc, pointWithDrop, asymptote, snapToValue, геом.) === */
|
||||
|
||||
@@ -598,15 +631,292 @@ function wireReadBtn(paraId){
|
||||
function buildP1(){
|
||||
const box = document.getElementById('p1-body');
|
||||
let html = '';
|
||||
html += makeCard('theory', 'В разработке', '1.0', `
|
||||
<p>Содержание параграфа <b>Степень с рациональным показателем</b> будет добавлено в Phase 1+.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Ключевая формула: $a^{m/n} = \sqrt[n]{a^m}$</p>
|
||||
`);
|
||||
html += secNavFor('p1');
|
||||
|
||||
html += makeCard('theory', 'Определение степени с дробным показателем', '1.1', `
|
||||
<p>Пусть $a > 0$, $m$ — целое число, $n$ — натуральное число, $n > 1$. Тогда:</p>
|
||||
\\[ a^{m/n} = \\sqrt[n]{a^m} \\]
|
||||
<p>В частности, при $m = 1$ получаем $a^{1/n} = \\sqrt[n]{a}$ — это <b>корень $n$-й степени</b> из $a$.</p>
|
||||
<p><b>Пример.</b> $8^{2/3} = \\sqrt[3]{8^2} = \\sqrt[3]{64} = 4.$</p>
|
||||
<p><b>Отрицательный показатель:</b> $a^{-m/n} = \\dfrac{1}{a^{m/n}} = \\dfrac{1}{\\sqrt[n]{a^m}}.$</p>
|
||||
<details class="spoiler"><summary>Почему $a > 0$?</summary><div class="spoiler-body">
|
||||
Если $a < 0$, то $\\sqrt[n]{a}$ при чётном $n$ не определён в $\\mathbb{R}$. Кроме того, одно и то же рациональное число может быть записано разными дробями ($\\tfrac{1}{2} = \\tfrac{2}{4}$), и для отрицательной базы значения корней $\\sqrt{a}$ и $\\sqrt[4]{a^2}$ не совпадают. Поэтому для $a < 0$ дробный показатель не определяют.<br>Для $a = 0$ полагают $0^{m/n} = 0$ при положительном показателе $m/n > 0$.
|
||||
</div></details>`);
|
||||
|
||||
html += makeCard('rule', 'Свойства степени с рациональным показателем', '1.2', `
|
||||
<p>Для $a > 0$, $b > 0$ и любых рациональных $p$, $q$ выполнены те же свойства, что и для целых показателей:</p>
|
||||
\\[ a^p \\cdot a^q = a^{p+q}, \\qquad \\dfrac{a^p}{a^q} = a^{p-q}, \\qquad (a^p)^q = a^{pq} \\]
|
||||
\\[ (ab)^p = a^p \\cdot b^p, \\qquad \\left(\\dfrac{a}{b}\\right)^p = \\dfrac{a^p}{b^p} \\]
|
||||
<p>Это <b>те же самые</b> свойства, что и для натурального показателя — просто теперь $p$ и $q$ могут быть любыми рациональными числами (целыми, дробными, отрицательными).</p>
|
||||
<p><b>Пример.</b> $3^{1/2} \\cdot 3^{3/2} = 3^{1/2 + 3/2} = 3^2 = 9.$</p>
|
||||
<p><b>Пример.</b> $\\left(4^{3/4}\\right)^{4/3} = 4^{(3/4) \\cdot (4/3)} = 4^1 = 4.$</p>`);
|
||||
|
||||
html += makeCard('example', 'Степень с иррациональным и действительным показателем', '1.3', `
|
||||
<p>А что такое $2^{\\sqrt{3}}$? Ведь $\\sqrt{3} \\approx 1{,}732...$ — иррациональное число.</p>
|
||||
<p>Идея: возьмём последовательность <b>рациональных</b> приближений к $\\sqrt{3}$:</p>
|
||||
\\[ r_1 = 1{,}7,\\ \\ r_2 = 1{,}73,\\ \\ r_3 = 1{,}732,\\ \\ r_4 = 1{,}7320,\\ \\ldots \\to \\sqrt{3} \\]
|
||||
<p>Каждое $2^{r_n}$ — уже определённая степень с рациональным показателем. Эта последовательность сходится:</p>
|
||||
\\[ 2^{\\sqrt{3}} = \\lim_{n \\to \\infty} 2^{r_n} \\approx 3{,}3219... \\]
|
||||
<p>Так определяется <b>степень с любым действительным показателем</b> $a^\\alpha$ при $a > 0$ и $\\alpha \\in \\mathbb{R}$.</p>
|
||||
<p><b>Все свойства степени сохраняются</b> и для действительных показателей — ими можно пользоваться так же, как привычными свойствами для целых степеней.</p>`);
|
||||
|
||||
/* INTERACTIVE 1 — конструктор a^(m/n) */
|
||||
html += `<div class="wg" id="p1-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Конструктор степени $a^{m/n}$</div></div>
|
||||
<div class="wg-help">Подвигай ползунки — увидишь, как вычисляется $a^{m/n} = \\sqrt[n]{a^m}$ при разных значениях.</div>
|
||||
<div class="sliders">
|
||||
<label>База $a$ = <b id="p1-iv1-a">4</b><input type="range" id="p1-iv1-sa" min="1" max="16" step="0.5" value="4"></label>
|
||||
<label>Числитель $m$ = <b id="p1-iv1-m">2</b><input type="range" id="p1-iv1-sm" min="-5" max="5" step="1" value="2"></label>
|
||||
<label>Знаменатель $n$ = <b id="p1-iv1-n">3</b><input type="range" id="p1-iv1-sn" min="2" max="6" step="1" value="3"></label>
|
||||
</div>
|
||||
<div id="p1-iv1-formula" style="text-align:center;font-size:1.15rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:10px;min-height:70px;line-height:1.9"></div>
|
||||
<div id="p1-iv1-val" style="text-align:center;font-size:1.05rem;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 2 — калькулятор свойств */
|
||||
html += `<div class="wg" id="p1-iv2">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор свойств степени</div></div>
|
||||
<div class="wg-help">Введи базу $a$ и две дроби $p = m_1/n_1$, $q = m_2/n_2$. Нажми кнопку свойства — увидишь пошаговое применение.</div>
|
||||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:10px">
|
||||
<span style="font-family:'JetBrains Mono',monospace">$a$ =</span>
|
||||
<input type="number" id="p1-iv2-a" class="tinp" style="width:64px;text-align:center" value="2" step="0.5">
|
||||
<span style="font-family:'JetBrains Mono',monospace;margin-left:8px">$p$ =</span>
|
||||
<input type="number" id="p1-iv2-pm" class="tinp" style="width:54px;text-align:center" value="1" step="1">
|
||||
<span>/</span>
|
||||
<input type="number" id="p1-iv2-pn" class="tinp" style="width:54px;text-align:center" value="2" min="1" step="1">
|
||||
<span style="font-family:'JetBrains Mono',monospace;margin-left:8px">$q$ =</span>
|
||||
<input type="number" id="p1-iv2-qm" class="tinp" style="width:54px;text-align:center" value="3" step="1">
|
||||
<span>/</span>
|
||||
<input type="number" id="p1-iv2-qn" class="tinp" style="width:54px;text-align:center" value="2" min="1" step="1">
|
||||
</div>
|
||||
<div class="actions" style="justify-content:center">
|
||||
<button class="btn primary" id="p1-iv2-mul">$a^p \\cdot a^q$</button>
|
||||
<button class="btn primary" id="p1-iv2-div">$a^p / a^q$</button>
|
||||
<button class="btn primary" id="p1-iv2-pow">$(a^p)^q$</button>
|
||||
</div>
|
||||
<div id="p1-iv2-out" style="margin-top:10px;padding:12px 14px;background:var(--card);border-radius:9px;text-align:center;font-size:1rem;min-height:60px;line-height:1.9"></div>
|
||||
<div class="feedback" id="p1-iv2-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 3 — DnD: корень или степень */
|
||||
html += `<div class="wg" id="p1-iv3">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Радикал или степень?</div></div>
|
||||
<div class="wg-help">Перетащи каждую запись в ящик «через корень» или «через степень».</div>
|
||||
<div class="dnd-hint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11V6a3 3 0 0 1 6 0v5"/><path d="M9 11h6v8a4 4 0 0 1-8 0z"/></svg> 8 записей — 2 ящика</div>
|
||||
<div id="p1-iv3-pool"></div>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px;margin-top:8px">
|
||||
<div class="drop-box"><h5 data-cat="rad">Запись через корень</h5><div class="drop-items" data-cat="rad"></div></div>
|
||||
<div class="drop-box"><h5 data-cat="pow">Запись через степень</h5><div class="drop-items" data-cat="pow"></div></div>
|
||||
</div>
|
||||
<div class="actions"><button class="btn primary" id="p1-iv3-check">Проверить</button><button class="btn" id="p1-iv3-reset">Сначала</button></div>
|
||||
<div class="feedback" id="p1-iv3-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 4 — тренажёр упрощения */
|
||||
html += `<div class="wg" id="p1-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр: упрости степень</div></div>
|
||||
<div class="wg-help">Вычисли значение и введи число (целое или десятичное до 2 знаков, допуск $\\pm 0{,}05$).</div>
|
||||
<div class="score-display"><span>Задача <b id="p1-iv4-i">1</b> / 6</span><span>Очки: <b id="p1-iv4-s">0</b> / 6</span></div>
|
||||
<div id="p1-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.15rem;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="p1-iv4-ans" class="tinp" style="width:110px;text-align:center" step="0.01">
|
||||
<button class="btn primary" id="p1-iv4-go">Проверить</button>
|
||||
<button class="btn" id="p1-iv4-start">Заново</button>
|
||||
</div>
|
||||
<div class="feedback" id="p1-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
html += secNav(null, 'p2');
|
||||
html += readButton('p1');
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
|
||||
/* IV1 — конструктор a^(m/n) */
|
||||
(function(){
|
||||
const sa = document.getElementById('p1-iv1-sa');
|
||||
const sm = document.getElementById('p1-iv1-sm');
|
||||
const sn = document.getElementById('p1-iv1-sn');
|
||||
const aL = document.getElementById('p1-iv1-a');
|
||||
const mL = document.getElementById('p1-iv1-m');
|
||||
const nL = document.getElementById('p1-iv1-n');
|
||||
const fEl = document.getElementById('p1-iv1-formula');
|
||||
const vEl = document.getElementById('p1-iv1-val');
|
||||
const seen = new Set();
|
||||
function draw(){
|
||||
const a = +sa.value, m = +sm.value, n = +sn.value;
|
||||
aL.textContent = (Number.isInteger(a) ? a : a.toFixed(1));
|
||||
mL.textContent = m;
|
||||
nL.textContent = n;
|
||||
let formula = '';
|
||||
if(m === 0){
|
||||
formula = '$a^{0} = 1$ при $a \\ne 0$. Здесь: $' + a + '^{0} = 1$.';
|
||||
vEl.innerHTML = 'Значение: $\\mathbf{1}$';
|
||||
} else if(m > 0){
|
||||
const aPowM = Math.pow(a, m);
|
||||
const val = Math.pow(a, m/n);
|
||||
formula = '$' + a + '^{' + m + '/' + n + '} \\;=\\; \\sqrt[' + n + ']{' + a + '^{' + m + '}} \\;=\\; \\sqrt[' + n + ']{' + (+aPowM.toFixed(4)) + '} \\;\\approx\\; ' + (+val.toFixed(4)) + '$';
|
||||
vEl.innerHTML = 'Значение: $\\mathbf{' + (+val.toFixed(4)) + '}$';
|
||||
} else {
|
||||
const am = Math.abs(m);
|
||||
const aPowM = Math.pow(a, am);
|
||||
const val = 1 / Math.pow(a, am/n);
|
||||
formula = '$' + a + '^{' + m + '/' + n + '} \\;=\\; \\dfrac{1}{' + a + '^{' + am + '/' + n + '}} \\;=\\; \\dfrac{1}{\\sqrt[' + n + ']{' + (+aPowM.toFixed(4)) + '}} \\;\\approx\\; ' + (+val.toFixed(4)) + '$';
|
||||
vEl.innerHTML = 'Значение: $\\mathbf{' + (+val.toFixed(4)) + '}$';
|
||||
}
|
||||
fEl.innerHTML = formula;
|
||||
renderMath(fEl); renderMath(vEl);
|
||||
const sig = a + ':' + m + ':' + n;
|
||||
seen.add(sig);
|
||||
if(seen.size >= 6 && !seen.has('_done')){ addXp(10,'p1-iv1'); bumpProgress('p1', 15); seen.add('_done'); }
|
||||
}
|
||||
sa.addEventListener('input', draw);
|
||||
sm.addEventListener('input', draw);
|
||||
sn.addEventListener('input', draw);
|
||||
draw();
|
||||
})();
|
||||
|
||||
/* IV2 — калькулятор свойств */
|
||||
(function(){
|
||||
const aI = document.getElementById('p1-iv2-a');
|
||||
const pm = document.getElementById('p1-iv2-pm');
|
||||
const pn = document.getElementById('p1-iv2-pn');
|
||||
const qm = document.getElementById('p1-iv2-qm');
|
||||
const qn = document.getElementById('p1-iv2-qn');
|
||||
const out = document.getElementById('p1-iv2-out');
|
||||
const fb = document.getElementById('p1-iv2-fb');
|
||||
const bMul = document.getElementById('p1-iv2-mul');
|
||||
const bDiv = document.getElementById('p1-iv2-div');
|
||||
const bPow = document.getElementById('p1-iv2-pow');
|
||||
const used = new Set();
|
||||
|
||||
function simplify(num, den){
|
||||
if(den < 0){ num = -num; den = -den; }
|
||||
const g = gcd(Math.abs(num), Math.abs(den)) || 1;
|
||||
return [num/g, den/g];
|
||||
}
|
||||
function fracStr(num, den){
|
||||
if(den === 1) return String(num);
|
||||
if(num === 0) return '0';
|
||||
return '\\dfrac{'+num+'}{'+den+'}';
|
||||
}
|
||||
function getVals(){
|
||||
const a = +aI.value;
|
||||
const pM = parseInt(pm.value,10), pN = parseInt(pn.value,10);
|
||||
const qM = parseInt(qm.value,10), qN = parseInt(qn.value,10);
|
||||
if(!isFinite(a) || a <= 0){ feedback(fb,false,'✗ База $a$ должна быть положительной.'); return null; }
|
||||
if(isNaN(pM)||isNaN(pN)||isNaN(qM)||isNaN(qN)){ feedback(fb,false,'✗ Введи все числа.'); return null; }
|
||||
if(pN <= 0 || qN <= 0){ feedback(fb,false,'✗ Знаменатели дробей должны быть положительными.'); return null; }
|
||||
return { a, pM, pN, qM, qN };
|
||||
}
|
||||
function doOp(op){
|
||||
const v = getVals(); if(!v) return;
|
||||
const { a, pM, pN, qM, qN } = v;
|
||||
const p = pM/pN, q = qM/qN;
|
||||
let sumNum, sumDen, label, exprBefore, exprAfter, valNum;
|
||||
if(op === 'mul'){
|
||||
sumNum = pM*qN + qM*pN; sumDen = pN*qN;
|
||||
label = '$a^p \\cdot a^q = a^{p+q}$';
|
||||
exprBefore = a+'^{'+fracStr(pM,pN)+'} \\cdot '+a+'^{'+fracStr(qM,qN)+'}';
|
||||
valNum = Math.pow(a, p+q);
|
||||
} else if(op === 'div'){
|
||||
sumNum = pM*qN - qM*pN; sumDen = pN*qN;
|
||||
label = '$\\dfrac{a^p}{a^q} = a^{p-q}$';
|
||||
exprBefore = '\\dfrac{'+a+'^{'+fracStr(pM,pN)+'}}{'+a+'^{'+fracStr(qM,qN)+'}}';
|
||||
valNum = Math.pow(a, p-q);
|
||||
} else {
|
||||
sumNum = pM*qM; sumDen = pN*qN;
|
||||
label = '$(a^p)^q = a^{pq}$';
|
||||
exprBefore = '\\left('+a+'^{'+fracStr(pM,pN)+'}\\right)^{'+fracStr(qM,qN)+'}';
|
||||
valNum = Math.pow(a, p*q);
|
||||
}
|
||||
const [sn, sd] = simplify(sumNum, sumDen);
|
||||
const expSimpl = fracStr(sn, sd);
|
||||
out.innerHTML = '<div style="font-size:.86rem;color:var(--muted);margin-bottom:6px">Свойство: '+label+'</div>'
|
||||
+ '$'+exprBefore+' \\;=\\; '+a+'^{'+expSimpl+'} \\;\\approx\\; '+ (+valNum.toFixed(4)) +'$';
|
||||
renderMath(out);
|
||||
feedback(fb, true, '✓ Применено свойство.');
|
||||
used.add(op);
|
||||
if(used.size === 3 && !used.has('_done')){ addXp(10,'p1-iv2'); bumpProgress('p1', 15); used.add('_done'); }
|
||||
}
|
||||
bMul.addEventListener('click', ()=>doOp('mul'));
|
||||
bDiv.addEventListener('click', ()=>doOp('div'));
|
||||
bPow.addEventListener('click', ()=>doOp('pow'));
|
||||
})();
|
||||
|
||||
/* IV3 — DnD радикал / степень */
|
||||
(function(){
|
||||
const items = [
|
||||
{ id:'r1', cat:'rad', html:'$\\sqrt[3]{a^2}$' },
|
||||
{ id:'r2', cat:'pow', html:'$a^{1/2}$' },
|
||||
{ id:'r3', cat:'rad', html:'$\\sqrt{a^3}$' },
|
||||
{ id:'r4', cat:'pow', html:'$a^{-1/4}$' },
|
||||
{ id:'r5', cat:'rad', html:'$\\sqrt[5]{a}$' },
|
||||
{ id:'r6', cat:'pow', html:'$a^{3/7}$' },
|
||||
{ id:'r7', cat:'rad', html:'$\\dfrac{1}{\\sqrt[4]{a}}$' },
|
||||
{ id:'r8', cat:'pow', html:'$a^{0{,}5}$' },
|
||||
];
|
||||
const sorter = setupSorter({
|
||||
poolId:'p1-iv3-pool',
|
||||
scopeSelector:'#p1-iv3',
|
||||
items: items,
|
||||
cats:['rad','pow'],
|
||||
columnLayout:false,
|
||||
});
|
||||
document.getElementById('p1-iv3-check').addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p1-iv3-fb');
|
||||
const placedCount = items.filter(it => sorter.placed[it.id]).length;
|
||||
const correct = items.filter(it => sorter.placed[it.id] === it.cat).length;
|
||||
if(placedCount < items.length){ feedback(fb, false, '✗ Размести все 8 записей.'); return; }
|
||||
if(correct === items.length){ feedback(fb, true, '✓ Все 8 на месте! +15 XP'); addXp(15,'p1-iv3'); bumpProgress('p1', 25); }
|
||||
else feedback(fb, false, '✗ Правильно ' + correct + ' из 8. Попробуй ещё.');
|
||||
});
|
||||
document.getElementById('p1-iv3-reset').addEventListener('click', ()=>{ sorter.reset(); document.getElementById('p1-iv3-fb').style.display = 'none'; });
|
||||
})();
|
||||
|
||||
/* IV4 — тренажёр упрощения */
|
||||
(function(){
|
||||
const Q = [
|
||||
{ q:'$8^{2/3} = \\;?$', ans:4, hint:'$\\sqrt[3]{8^2} = \\sqrt[3]{64} = 4$' },
|
||||
{ q:'$16^{3/4} = \\;?$', ans:8, hint:'$\\sqrt[4]{16^3} = \\sqrt[4]{4096} = 8$' },
|
||||
{ q:'$27^{-1/3} = \\;?$', ans:1/3, hint:'$\\dfrac{1}{\\sqrt[3]{27}} = \\dfrac{1}{3} \\approx 0{,}33$' },
|
||||
{ q:'$32^{0{,}4} = \\;?$', ans:4, hint:'$0{,}4 = \\tfrac{2}{5}$, $\\sqrt[5]{32^2} = \\sqrt[5]{1024} = 4$' },
|
||||
{ q:'$\\left(\\dfrac{1}{4}\\right)^{-1/2} = \\;?$', ans:2, hint:'$\\left(\\tfrac{1}{4}\\right)^{-1/2} = 4^{1/2} = \\sqrt{4} = 2$' },
|
||||
{ q:'$9^{1{,}5} = \\;?$', ans:27, hint:'$9^{3/2} = \\sqrt{9^3} = \\sqrt{729} = 27$' },
|
||||
];
|
||||
let i = 0, score = 0;
|
||||
function show(){
|
||||
if(i >= Q.length){
|
||||
document.getElementById('p1-iv4-q').innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
|
||||
if(score === Q.length){ addXp(15,'p1-iv4'); bumpProgress('p1', 25); }
|
||||
else if(score >= 4){ addXp(8,'p1-iv4'); bumpProgress('p1', 15); }
|
||||
return;
|
||||
}
|
||||
document.getElementById('p1-iv4-i').textContent = (i+1);
|
||||
document.getElementById('p1-iv4-s').textContent = score;
|
||||
document.getElementById('p1-iv4-q').innerHTML = Q[i].q;
|
||||
document.getElementById('p1-iv4-ans').value = '';
|
||||
renderMath(document.getElementById('p1-iv4-q'));
|
||||
document.getElementById('p1-iv4-fb').style.display = 'none';
|
||||
}
|
||||
function go(){
|
||||
if(i >= Q.length) return;
|
||||
const fb = document.getElementById('p1-iv4-fb');
|
||||
const raw = document.getElementById('p1-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('p1-iv4-s').textContent = score;
|
||||
i++;
|
||||
setTimeout(show, 1300);
|
||||
}
|
||||
document.getElementById('p1-iv4-go').addEventListener('click', go);
|
||||
document.getElementById('p1-iv4-ans').addEventListener('keydown', e=>{ if(e.key === 'Enter') go(); });
|
||||
document.getElementById('p1-iv4-start').addEventListener('click', ()=>{ i=0; score=0; show(); });
|
||||
show();
|
||||
})();
|
||||
|
||||
wireReadBtn('p1');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user