feat(alg11 ch1 wave1): §1 «Степень с рациональным показателем»

This commit is contained in:
Maxim Dolgolyov
2026-05-29 11:40:37 +03:00
parent 54b8d06c61
commit 21c5ae2d91
+316 -6
View File
@@ -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,'&#10007; База $a$ должна быть положительной.'); return null; }
if(isNaN(pM)||isNaN(pN)||isNaN(qM)||isNaN(qN)){ feedback(fb,false,'&#10007; Введи все числа.'); return null; }
if(pN <= 0 || qN <= 0){ feedback(fb,false,'&#10007; Знаменатели дробей должны быть положительными.'); 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, '&#10003; Применено свойство.');
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, '&#10007; Размести все 8 записей.'); return; }
if(correct === items.length){ feedback(fb, true, '&#10003; Все 8 на месте! +15 XP'); addXp(15,'p1-iv3'); bumpProgress('p1', 25); }
else feedback(fb, false, '&#10007; Правильно ' + 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, '&#10007; Введи число.'); return; }
if(Math.abs(ans - Q[i].ans) < 0.05){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].hint+'. Дальше ▶'); }
else feedback(fb, false, '&#10007; Неверно. Ответ $\\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');
}