feat(alg11 ch3 wave1): §7 «Свойства логарифмов»
This commit is contained in:
@@ -130,6 +130,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:.82rem;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)}
|
||||
@@ -450,6 +470,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, геом.) === */
|
||||
|
||||
@@ -604,15 +637,422 @@ function wireReadBtn(paraId){
|
||||
function buildP7(){
|
||||
const box = document.getElementById('p7-body');
|
||||
let html = '';
|
||||
html += makeCard('theory', 'В разработке', '7.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">Ключевая формула: $\log_a(bc) = \log_a b + \log_a c$</p>
|
||||
|
||||
/* === ТЕОРИЯ === */
|
||||
html += makeCard('theory', 'Произведение, частное, степень', '7.1', `
|
||||
<p>Пусть $a > 0$, $a \\ne 1$ и $b > 0$, $c > 0$. Тогда справедливы три основных свойства:</p>
|
||||
<p style="text-align:center;font-size:1.04rem">$\\log_a(bc) = \\log_a b + \\log_a c$</p>
|
||||
<p style="text-align:center;font-size:1.04rem">$\\log_a \\dfrac{b}{c} = \\log_a b - \\log_a c$</p>
|
||||
<p style="text-align:center;font-size:1.04rem">$\\log_a b^n = n \\cdot \\log_a b$</p>
|
||||
<details class="spoiler"><summary>Доказательство свойства произведения</summary><div class="spoiler-body">
|
||||
<p>Пусть $\\log_a b = p$ и $\\log_a c = q$. По определению логарифма $b = a^p$ и $c = a^q$.</p>
|
||||
<p>Тогда $bc = a^p \\cdot a^q = a^{p+q}$, значит $\\log_a(bc) = p + q = \\log_a b + \\log_a c$.</p>
|
||||
<p>Свойства для частного и степени доказываются аналогично — через определение логарифма и свойства степеней.</p>
|
||||
</div></details>
|
||||
<p style="margin-top:10px"><b>Примеры:</b></p>
|
||||
<p>$\\log_2 6 = \\log_2(2 \\cdot 3) = \\log_2 2 + \\log_2 3 = 1 + \\log_2 3$.</p>
|
||||
<p>$\\log_5 \\dfrac{25}{8} = \\log_5 25 - \\log_5 8 = 2 - 3 \\log_5 2$.</p>
|
||||
<p>$\\log_2 8^3 = 3 \\log_2 8 = 3 \\cdot 3 = 9$.</p>
|
||||
`);
|
||||
|
||||
html += makeCard('rule', 'Корень и перенос показателя из основания', '7.2', `
|
||||
<p><b>Логарифм корня.</b> Поскольку $\\sqrt[n]{b} = b^{1/n}$, по свойству степени:</p>
|
||||
<p style="text-align:center;font-size:1.04rem">$\\log_a \\sqrt[n]{b} = \\log_a b^{1/n} = \\dfrac{1}{n} \\log_a b$</p>
|
||||
<p><b>Перенос показателя из основания.</b></p>
|
||||
<p style="text-align:center;font-size:1.04rem">$\\log_{a^n} b = \\dfrac{1}{n} \\log_a b$</p>
|
||||
<p>Эти два свойства часто объединяют в одно:</p>
|
||||
<p style="text-align:center;font-size:1.06rem">$\\log_{a^k} b^m = \\dfrac{m}{k} \\log_a b$</p>
|
||||
<p style="margin-top:10px"><b>Примеры:</b></p>
|
||||
<p>$\\log_2 \\sqrt{8} = \\dfrac{1}{2} \\log_2 8 = \\dfrac{3}{2}$.</p>
|
||||
<p>$\\log_4 16 = \\log_{2^2} 2^4 = \\dfrac{4}{2} \\log_2 2 = 2$.</p>
|
||||
<p>$\\log_{27} \\sqrt[3]{9} = \\log_{3^3} 3^{2/3} = \\dfrac{2/3}{3} = \\dfrac{2}{9}$.</p>
|
||||
`);
|
||||
|
||||
html += makeCard('example', 'Переход к новому основанию', '7.3', `
|
||||
<p>Иногда удобно перейти от $\\log_a b$ к логарифму по другому основанию $c$ ($c > 0$, $c \\ne 1$):</p>
|
||||
<p style="text-align:center;font-size:1.06rem">$\\log_a b = \\dfrac{\\log_c b}{\\log_c a}$</p>
|
||||
<p>Чаще всего берут $c = 10$ (десятичные) или $c = e$ (натуральные). Полезное следствие при $a \\ne 1$, $b \\ne 1$:</p>
|
||||
<p style="text-align:center;font-size:1.04rem">$\\log_a b = \\dfrac{1}{\\log_b a}$</p>
|
||||
<p style="margin-top:10px"><b>Применение:</b></p>
|
||||
<p>$\\log_2 7 = \\dfrac{\\lg 7}{\\lg 2} \\approx \\dfrac{0{,}845}{0{,}301} \\approx 2{,}807$.</p>
|
||||
<p>$\\log_3 5 = \\dfrac{1}{\\log_5 3}$.</p>
|
||||
<p><b>Связь $\\lg$ и $\\ln$:</b></p>
|
||||
<p>$\\lg b = \\dfrac{\\ln b}{\\ln 10} \\approx \\dfrac{\\ln b}{2{,}303}$, $\\quad \\ln b = \\dfrac{\\lg b}{\\lg e} \\approx \\dfrac{\\lg b}{0{,}4343}$.</p>
|
||||
`);
|
||||
|
||||
/* === ИНТЕРАКТИВ 1 — пошаговый «применитель» свойств === */
|
||||
html += `<div class="wg" id="p7-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Применение свойств логарифма</div></div>
|
||||
<div class="wg-help">Выбери выражение ползунком и нажимай «Следующий шаг ▶», чтобы открывать решение по одному шагу. Просмотри все 5 выражений — получишь XP.</div>
|
||||
<div class="sliders">
|
||||
<label>Выражение № <b id="p7-iv1-n">1</b> / 5<input type="range" id="p7-iv1-sn" min="1" max="5" step="1" value="1"></label>
|
||||
</div>
|
||||
<div id="p7-iv1-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.10rem;text-align:center;margin-bottom:10px"></div>
|
||||
<div id="p7-iv1-steps" style="display:flex;flex-direction:column;gap:8px;margin-bottom:10px"></div>
|
||||
<div class="actions" style="justify-content:center">
|
||||
<button class="btn primary" id="p7-iv1-next">Следующий шаг ▶</button>
|
||||
<button class="btn" id="p7-iv1-all">Показать все шаги</button>
|
||||
<button class="btn" id="p7-iv1-reset">Скрыть шаги</button>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
/* === ИНТЕРАКТИВ 2 — калькулятор логарифмов === */
|
||||
html += `<div class="wg" id="p7-iv2">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор логарифмов</div></div>
|
||||
<div class="wg-help">Выбери свойство, заполни поля и нажми «Вычислить» — увидишь применение свойства пошагово и численное приближение.</div>
|
||||
<div style="display:flex;gap:6px;flex-wrap:wrap;justify-content:center;margin-bottom:12px">
|
||||
<button class="btn" data-mode="prod" id="p7-iv2-m-prod">Произведение $\\log_a(bc)$</button>
|
||||
<button class="btn" data-mode="quot" id="p7-iv2-m-quot">Частное $\\log_a(b/c)$</button>
|
||||
<button class="btn" data-mode="pow" id="p7-iv2-m-pow">Степень $\\log_a b^n$</button>
|
||||
<button class="btn" data-mode="base" id="p7-iv2-m-base">Переход к новому основанию</button>
|
||||
</div>
|
||||
<div id="p7-iv2-inputs" style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:10px"></div>
|
||||
<div style="text-align:center;margin-bottom:10px"><button class="btn primary" id="p7-iv2-go">Вычислить</button></div>
|
||||
<div id="p7-iv2-out" style="padding:12px 14px;background:var(--card);border-radius:9px;font-size:.96rem;min-height:60px;line-height:1.8"></div>
|
||||
<div class="feedback" id="p7-iv2-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* === ИНТЕРАКТИВ 3 — DnD-сортер === */
|
||||
html += `<div class="wg" id="p7-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 выражений — 4 ящика</div>
|
||||
<div id="p7-iv3-pool"></div>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-top:8px">
|
||||
<div class="drop-box"><h5 data-cat="v1">$=1$</h5><div class="drop-items" data-cat="v1"></div></div>
|
||||
<div class="drop-box"><h5 data-cat="v2">$=2$</h5><div class="drop-items" data-cat="v2"></div></div>
|
||||
<div class="drop-box"><h5 data-cat="v3">$=3$</h5><div class="drop-items" data-cat="v3"></div></div>
|
||||
<div class="drop-box"><h5 data-cat="v5">$=5$</h5><div class="drop-items" data-cat="v5"></div></div>
|
||||
</div>
|
||||
<div class="actions"><button class="btn primary" id="p7-iv3-check">Проверить</button><button class="btn" id="p7-iv3-reset">Сначала</button></div>
|
||||
<div class="feedback" id="p7-iv3-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* === ИНТЕРАКТИВ 4 — тренажёр === */
|
||||
html += `<div class="wg" id="p7-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр свойств</div></div>
|
||||
<div class="wg-help">6 задач на применение свойств. Введи число (целое или десятичное, допуск $\\pm 0{,}05$).</div>
|
||||
<div class="score-display"><span>Задача <b id="p7-iv4-i">1</b> / 6</span><span>Очки: <b id="p7-iv4-s">0</b> / 6</span></div>
|
||||
<div id="p7-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.12rem;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="p7-iv4-ans" class="tinp" style="width:120px;text-align:center" step="0.01">
|
||||
<button class="btn primary" id="p7-iv4-go">Проверить</button>
|
||||
<button class="btn" id="p7-iv4-start">Заново</button>
|
||||
</div>
|
||||
<div class="feedback" id="p7-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
html += secNavFor('p7');
|
||||
html += readButton('p7');
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
|
||||
/* === IV1 — пошаговый «применитель» === */
|
||||
(function(){
|
||||
const TASKS = [
|
||||
{
|
||||
q: '$\\log_2 24 - \\log_2 3$',
|
||||
steps: [
|
||||
'Используем свойство <b>логарифма частного</b>: $\\log_a b - \\log_a c = \\log_a \\dfrac{b}{c}$.',
|
||||
'Получаем $\\log_2 24 - \\log_2 3 = \\log_2 \\dfrac{24}{3} = \\log_2 8$.',
|
||||
'Так как $8 = 2^3$, имеем $\\log_2 8 = 3$.',
|
||||
'<b>Ответ:</b> $3$.'
|
||||
]
|
||||
},
|
||||
{
|
||||
q: '$\\log_3 5 + \\log_3 18$',
|
||||
steps: [
|
||||
'Используем свойство <b>логарифма произведения</b>: $\\log_a b + \\log_a c = \\log_a(bc)$.',
|
||||
'Получаем $\\log_3 5 + \\log_3 18 = \\log_3(5 \\cdot 18) = \\log_3 90$.',
|
||||
'Заметим, что $90 = 9 \\cdot 10$, поэтому $\\log_3 90 = \\log_3 9 + \\log_3 10 = 2 + \\log_3 10$.',
|
||||
'<b>Ответ:</b> $2 + \\log_3 10 \\approx 4{,}096$.'
|
||||
]
|
||||
},
|
||||
{
|
||||
q: '$2 \\log_5 3 + \\log_5 \\dfrac{25}{9}$',
|
||||
steps: [
|
||||
'По свойству степени: $2 \\log_5 3 = \\log_5 3^2 = \\log_5 9$.',
|
||||
'Получаем $\\log_5 9 + \\log_5 \\dfrac{25}{9} = \\log_5\\left(9 \\cdot \\dfrac{25}{9}\\right) = \\log_5 25$.',
|
||||
'Так как $25 = 5^2$, имеем $\\log_5 25 = 2$.',
|
||||
'<b>Ответ:</b> $2$.'
|
||||
]
|
||||
},
|
||||
{
|
||||
q: '$\\log_2 \\sqrt[3]{32}$',
|
||||
steps: [
|
||||
'Применяем свойство <b>логарифма корня</b>: $\\log_a \\sqrt[n]{b} = \\dfrac{1}{n} \\log_a b$.',
|
||||
'Получаем $\\log_2 \\sqrt[3]{32} = \\dfrac{1}{3} \\log_2 32$.',
|
||||
'Так как $32 = 2^5$, имеем $\\log_2 32 = 5$, значит $\\dfrac{1}{3} \\cdot 5 = \\dfrac{5}{3}$.',
|
||||
'<b>Ответ:</b> $\\dfrac{5}{3} \\approx 1{,}667$.'
|
||||
]
|
||||
},
|
||||
{
|
||||
q: '$\\log_{16} 8$',
|
||||
steps: [
|
||||
'Перепишем основание и аргумент по основанию $2$: $16 = 2^4$, $8 = 2^3$.',
|
||||
'Применяем формулу $\\log_{a^k} b^m = \\dfrac{m}{k} \\log_a b$: $\\log_{2^4} 2^3 = \\dfrac{3}{4} \\log_2 2 = \\dfrac{3}{4}$.',
|
||||
'<b>Ответ:</b> $\\dfrac{3}{4} = 0{,}75$.'
|
||||
]
|
||||
}
|
||||
];
|
||||
const sn = document.getElementById('p7-iv1-sn');
|
||||
const nL = document.getElementById('p7-iv1-n');
|
||||
const qEl = document.getElementById('p7-iv1-q');
|
||||
const stepsEl = document.getElementById('p7-iv1-steps');
|
||||
const nextBtn = document.getElementById('p7-iv1-next');
|
||||
const allBtn = document.getElementById('p7-iv1-all');
|
||||
const resetBtn = document.getElementById('p7-iv1-reset');
|
||||
const seen = new Set();
|
||||
let _done = false;
|
||||
let cur = 0, shown = 0;
|
||||
|
||||
function render(){
|
||||
const t = TASKS[cur];
|
||||
nL.textContent = (cur + 1);
|
||||
qEl.innerHTML = t.q;
|
||||
stepsEl.innerHTML = t.steps.map((s, i) => {
|
||||
const visible = i < shown;
|
||||
const isLast = i === t.steps.length - 1 && visible;
|
||||
const bg = isLast ? '#dcfce7' : 'var(--card)';
|
||||
const brd = isLast ? '2px solid #16a34a' : '1px solid var(--border)';
|
||||
return '<div data-i="'+i+'" style="padding:10px 12px;background:'+bg+';border:'+brd+';border-radius:8px;font-size:.95rem;display:'+(visible?'block':'none')+'"><span style="color:var(--muted);font-weight:700;margin-right:6px">Шаг '+(i+1)+':</span>'+s+'</div>';
|
||||
}).join('');
|
||||
renderMath(qEl);
|
||||
renderMath(stepsEl);
|
||||
if(shown >= t.steps.length){
|
||||
seen.add(cur);
|
||||
if(!_done && seen.size >= 5){ _done = true; addXp(10, 'p7-iv1'); bumpProgress('p7', 15); }
|
||||
}
|
||||
}
|
||||
function load(n){ cur = Math.max(0, Math.min(TASKS.length - 1, n)); shown = 1; render(); }
|
||||
sn.addEventListener('input', () => load((+sn.value) - 1));
|
||||
nextBtn.addEventListener('click', () => {
|
||||
if(shown < TASKS[cur].steps.length){ shown++; render(); }
|
||||
});
|
||||
allBtn.addEventListener('click', () => { shown = TASKS[cur].steps.length; render(); });
|
||||
resetBtn.addEventListener('click', () => { shown = 1; render(); });
|
||||
load(0);
|
||||
})();
|
||||
|
||||
/* === IV2 — калькулятор === */
|
||||
(function(){
|
||||
const modes = ['prod','quot','pow','base'];
|
||||
const inputsEl = document.getElementById('p7-iv2-inputs');
|
||||
const outEl = document.getElementById('p7-iv2-out');
|
||||
const fbEl = document.getElementById('p7-iv2-fb');
|
||||
const goBtn = document.getElementById('p7-iv2-go');
|
||||
let mode = 'prod';
|
||||
let used = new Set();
|
||||
let _done = false;
|
||||
|
||||
function setMode(m){
|
||||
mode = m;
|
||||
modes.forEach(mm => {
|
||||
const btn = document.getElementById('p7-iv2-m-'+mm);
|
||||
if(btn) btn.classList.toggle('primary', mm === m);
|
||||
});
|
||||
fbEl.style.display = 'none';
|
||||
outEl.innerHTML = '<span style="color:var(--muted)">Нажми «Вычислить», чтобы увидеть шаги.</span>';
|
||||
if(m === 'prod'){
|
||||
inputsEl.innerHTML =
|
||||
'<span style="font-family:JetBrains Mono,monospace">$a$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-a" class="tinp" style="width:70px;text-align:center" value="2" step="1" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$b$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-b" class="tinp" style="width:70px;text-align:center" value="4" step="1" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$c$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-c" class="tinp" style="width:70px;text-align:center" value="8" step="1" min="0.1">';
|
||||
} else if(m === 'quot'){
|
||||
inputsEl.innerHTML =
|
||||
'<span style="font-family:JetBrains Mono,monospace">$a$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-a" class="tinp" style="width:70px;text-align:center" value="2" step="1" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$b$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-b" class="tinp" style="width:70px;text-align:center" value="32" step="1" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$c$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-c" class="tinp" style="width:70px;text-align:center" value="8" step="1" min="0.1">';
|
||||
} else if(m === 'pow'){
|
||||
inputsEl.innerHTML =
|
||||
'<span style="font-family:JetBrains Mono,monospace">$a$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-a" class="tinp" style="width:70px;text-align:center" value="2" step="1" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$b$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-b" class="tinp" style="width:70px;text-align:center" value="8" step="1" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$n$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-n" class="tinp" style="width:70px;text-align:center" value="3" step="1">';
|
||||
} else { // base
|
||||
inputsEl.innerHTML =
|
||||
'<span style="font-family:JetBrains Mono,monospace">$a$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-a" class="tinp" style="width:70px;text-align:center" value="2" step="0.5" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$b$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-b" class="tinp" style="width:70px;text-align:center" value="7" step="1" min="0.1">'+
|
||||
'<span style="font-family:JetBrains Mono,monospace">$c$ =</span>'+
|
||||
'<input type="number" id="p7-iv2-c" class="tinp" style="width:70px;text-align:center" value="10" step="1" min="0.1">';
|
||||
}
|
||||
renderMath(inputsEl);
|
||||
}
|
||||
modes.forEach(m => {
|
||||
const btn = document.getElementById('p7-iv2-m-'+m);
|
||||
if(btn) btn.addEventListener('click', () => setMode(m));
|
||||
});
|
||||
setMode('prod');
|
||||
|
||||
function num(id){ const el = document.getElementById(id); return el ? +el.value : NaN; }
|
||||
function r(n){ return (Math.abs(n - Math.round(n)) < 1e-9) ? Math.round(n) : (+n.toFixed(4)); }
|
||||
|
||||
goBtn.addEventListener('click', () => {
|
||||
fbEl.style.display = 'none';
|
||||
const a = num('p7-iv2-a'), b = num('p7-iv2-b'), c = num('p7-iv2-c'), n = num('p7-iv2-n');
|
||||
// Базовая валидация
|
||||
if(mode !== 'pow'){
|
||||
if(!isFinite(a) || a <= 0 || a === 1 || !isFinite(b) || b <= 0 || !isFinite(c) || c <= 0){
|
||||
feedback(fbEl, false, '✗ Требуется $a > 0$, $a \\ne 1$, $b > 0$, $c > 0$.'); return;
|
||||
}
|
||||
} else {
|
||||
if(!isFinite(a) || a <= 0 || a === 1 || !isFinite(b) || b <= 0 || !isFinite(n)){
|
||||
feedback(fbEl, false, '✗ Требуется $a > 0$, $a \\ne 1$, $b > 0$.'); return;
|
||||
}
|
||||
}
|
||||
let out = '';
|
||||
if(mode === 'prod'){
|
||||
const sum = Math.log(b*c) / Math.log(a);
|
||||
const lb = Math.log(b) / Math.log(a);
|
||||
const lc = Math.log(c) / Math.log(a);
|
||||
out =
|
||||
'<div>$\\log_{'+r(a)+'}('+r(b)+' \\cdot '+r(c)+') = \\log_{'+r(a)+'} '+r(b)+' + \\log_{'+r(a)+'} '+r(c)+'$</div>'+
|
||||
'<div>$= '+r(lb)+' + '+r(lc)+' \\approx '+r(sum)+'$</div>'+
|
||||
'<div style="color:var(--muted);font-size:.86rem;margin-top:6px">Проверка через Math.log: $\\log_{'+r(a)+'}('+r(b*c)+') \\approx '+r(sum)+'$.</div>';
|
||||
} else if(mode === 'quot'){
|
||||
const diff = Math.log(b/c) / Math.log(a);
|
||||
const lb = Math.log(b) / Math.log(a);
|
||||
const lc = Math.log(c) / Math.log(a);
|
||||
out =
|
||||
'<div>$\\log_{'+r(a)+'} \\dfrac{'+r(b)+'}{'+r(c)+'} = \\log_{'+r(a)+'} '+r(b)+' - \\log_{'+r(a)+'} '+r(c)+'$</div>'+
|
||||
'<div>$= '+r(lb)+' - '+r(lc)+' \\approx '+r(diff)+'$</div>'+
|
||||
'<div style="color:var(--muted);font-size:.86rem;margin-top:6px">Проверка: $\\log_{'+r(a)+'}('+r(b/c)+') \\approx '+r(diff)+'$.</div>';
|
||||
} else if(mode === 'pow'){
|
||||
const lb = Math.log(b) / Math.log(a);
|
||||
const val = n * lb;
|
||||
out =
|
||||
'<div>$\\log_{'+r(a)+'} '+r(b)+'^{'+r(n)+'} = '+r(n)+' \\cdot \\log_{'+r(a)+'} '+r(b)+'$</div>'+
|
||||
'<div>$= '+r(n)+' \\cdot '+r(lb)+' \\approx '+r(val)+'$</div>'+
|
||||
'<div style="color:var(--muted);font-size:.86rem;margin-top:6px">Проверка: $\\log_{'+r(a)+'}('+r(Math.pow(b,n))+') \\approx '+r(val)+'$.</div>';
|
||||
} else { // base
|
||||
if(c === 1){ feedback(fbEl, false, '✗ Новое основание $c$ не должно быть равно $1$.'); return; }
|
||||
const lab = Math.log(b) / Math.log(a);
|
||||
const lcb = Math.log(b) / Math.log(c);
|
||||
const lca = Math.log(a) / Math.log(c);
|
||||
out =
|
||||
'<div>$\\log_{'+r(a)+'} '+r(b)+' = \\dfrac{\\log_{'+r(c)+'} '+r(b)+'}{\\log_{'+r(c)+'} '+r(a)+'}$</div>'+
|
||||
'<div>$\\approx \\dfrac{'+r(lcb)+'}{'+r(lca)+'} \\approx '+r(lab)+'$</div>'+
|
||||
'<div style="color:var(--muted);font-size:.86rem;margin-top:6px">Прямое значение: $\\log_{'+r(a)+'} '+r(b)+' \\approx '+r(lab)+'$.</div>';
|
||||
}
|
||||
outEl.innerHTML = out;
|
||||
renderMath(outEl);
|
||||
used.add(mode);
|
||||
if(!_done && used.size >= 3){ _done = true; addXp(10, 'p7-iv2'); bumpProgress('p7', 15); }
|
||||
});
|
||||
})();
|
||||
|
||||
/* === IV3 — DnD-сортер === */
|
||||
(function(){
|
||||
const items = [
|
||||
{id:'s1', html:'$\\log_2 8 + \\log_2 4$', cat:'v5'},
|
||||
{id:'s2', html:'$\\log_3 81 - \\log_3 3$', cat:'v3'},
|
||||
{id:'s3', html:'$2 \\log_5 5$', cat:'v2'},
|
||||
{id:'s4', html:'$\\log_2 32 - \\log_2 8$', cat:'v2'},
|
||||
{id:'s5', html:'$\\log_3 9 + \\log_3 3$', cat:'v3'},
|
||||
{id:'s6', html:'$\\log_2 \\sqrt[3]{8}$', cat:'v1'},
|
||||
{id:'s7', html:'$\\log_5 125 + \\log_5 1$', cat:'v3'},
|
||||
{id:'s8', html:'$\\log_4 16 + \\log_4 4$', cat:'v3'}
|
||||
];
|
||||
const cats = ['v1','v2','v3','v5'];
|
||||
const sorter = setupSorter({
|
||||
poolId: 'p7-iv3-pool',
|
||||
scopeSelector: '#p7-iv3',
|
||||
items, cats
|
||||
});
|
||||
const checkBtn = document.getElementById('p7-iv3-check');
|
||||
const resetBtn = document.getElementById('p7-iv3-reset');
|
||||
const fbEl = document.getElementById('p7-iv3-fb');
|
||||
let _done = false;
|
||||
|
||||
checkBtn.addEventListener('click', () => {
|
||||
let ok = 0, total = items.length;
|
||||
let missed = [];
|
||||
items.forEach(it => {
|
||||
if(sorter.placed[it.id] === it.cat) ok++;
|
||||
else if(!sorter.placed[it.id]) missed.push(it.id);
|
||||
});
|
||||
if(ok === total){
|
||||
feedback(fbEl, true, '✓ Отлично! Все 8 выражений на месте.');
|
||||
if(!_done){ _done = true; addXp(15, 'p7-iv3'); bumpProgress('p7', 25); }
|
||||
} else {
|
||||
const left = missed.length;
|
||||
feedback(fbEl, false, '✗ Верно: '+ok+' / '+total+'. '+(left ? 'Не размещено: '+left+'.' : 'Проверь свойства логарифмов.'));
|
||||
}
|
||||
});
|
||||
resetBtn.addEventListener('click', () => {
|
||||
sorter.reset();
|
||||
fbEl.style.display = 'none';
|
||||
});
|
||||
})();
|
||||
|
||||
/* === IV4 — тренажёр === */
|
||||
(function(){
|
||||
const TASKS = [
|
||||
{ q: '$\\log_2 6 + \\log_2 \\dfrac{16}{3}$', a: 5, hint: '$\\log_2(6 \\cdot 16/3) = \\log_2 32 = 5$.' },
|
||||
{ q: '$\\log_3 \\sqrt{27}$', a: 1.5, hint: '$\\dfrac{1}{2} \\log_3 27 = \\dfrac{3}{2}$.' },
|
||||
{ q: '$\\log_5 100 - \\log_5 4$', a: 2, hint: '$\\log_5 (100/4) = \\log_5 25 = 2$.' },
|
||||
{ q: '$\\log_4 64$', a: 3, hint: '$\\log_{2^2} 2^6 = 6/2 = 3$.' },
|
||||
{ q: '$\\log_2 3 \\cdot \\log_3 8$', a: 3, hint: '$\\log_2 3 \\cdot \\dfrac{\\log_2 8}{\\log_2 3} = \\log_2 8 = 3$.' },
|
||||
{ q: '$\\dfrac{\\lg 100}{\\lg 10}$', a: 2, hint: '$\\lg 100 / \\lg 10 = 2/1 = 2$.' }
|
||||
];
|
||||
const qEl = document.getElementById('p7-iv4-q');
|
||||
const ansEl = document.getElementById('p7-iv4-ans');
|
||||
const goBtn = document.getElementById('p7-iv4-go');
|
||||
const startBtn = document.getElementById('p7-iv4-start');
|
||||
const iEl = document.getElementById('p7-iv4-i');
|
||||
const sEl = document.getElementById('p7-iv4-s');
|
||||
const fbEl = document.getElementById('p7-iv4-fb');
|
||||
let idx = 0, score = 0;
|
||||
let _done = false;
|
||||
|
||||
function render(){
|
||||
iEl.textContent = (idx + 1);
|
||||
sEl.textContent = score;
|
||||
if(idx >= TASKS.length){
|
||||
qEl.innerHTML = '<b style="color:var(--ok)">Все задачи решены! Очков: '+score+' / '+TASKS.length+'.</b>';
|
||||
ansEl.disabled = true; goBtn.disabled = true;
|
||||
if(!_done){ _done = true; addXp(15, 'p7-iv4'); bumpProgress('p7', 25); }
|
||||
renderMath(qEl);
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = TASKS[idx].q;
|
||||
ansEl.value = '';
|
||||
ansEl.disabled = false; goBtn.disabled = false;
|
||||
fbEl.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
setTimeout(() => ansEl.focus(), 30);
|
||||
}
|
||||
goBtn.addEventListener('click', () => {
|
||||
if(idx >= TASKS.length) return;
|
||||
const v = +ansEl.value;
|
||||
if(!isFinite(v) || ansEl.value === ''){ feedback(fbEl, false, '✗ Введи число.'); return; }
|
||||
const t = TASKS[idx];
|
||||
if(Math.abs(v - t.a) < 0.05){
|
||||
score++; sEl.textContent = score;
|
||||
feedback(fbEl, true, '✓ Верно! '+t.hint);
|
||||
setTimeout(() => { idx++; render(); }, 950);
|
||||
} else {
|
||||
feedback(fbEl, false, '✗ Неверно. Подсказка: '+t.hint+' Правильный ответ: <b>'+t.a+'</b>.');
|
||||
setTimeout(() => { idx++; render(); }, 1900);
|
||||
}
|
||||
});
|
||||
ansEl.addEventListener('keydown', e => { if(e.key === 'Enter'){ e.preventDefault(); goBtn.click(); } });
|
||||
startBtn.addEventListener('click', () => { idx = 0; score = 0; _done = false; render(); });
|
||||
render();
|
||||
})();
|
||||
|
||||
wireReadBtn('p7');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user