feat(alg9 ch3 wave2): §12 «Окружность» + §13 «Метод интервалов»
§12 «Длина отрезка. Уравнение окружности»: - 3 теорет. карточки (формула расстояния, уравнение окружности, особые случаи). - IV1 «Окружность-конструктор»: 3 слайдера a/b/R, SVG-окружность + центр + радиус-линия + динамическое уравнение. - IV2 «Калькулятор расстояния»: 4 input + пошаговый разбор + мини-SVG с отрезком AB. - IV3 «Точка на окружности?»: 6 квикфайр-задач (да/нет). - IV4 «Тренажёр радиуса/центра/длины»: 6 задач на ввод числа. §13 «Дробно-рациональные неравенства. Метод интервалов»: - 3 теорет. карточки (метод интервалов, правило знаков, пример). - IV1 «Числовая прямая знаков»: 5 неравенств, SVG-прямая с точками (закрашенными/выколотыми) и цветными знаками интервалов. - IV2 «Закрашена или выколота?»: DnD-сортер 6 карточек по 2 категориям. - IV3 «Сколько целых решений в [-5;5]»: 6 задач. - IV4 «Сумма концов интервалов»: 6 задач на ввод числа. Добавлены setupSorter() + DnD CSS (.dnd-pool/.dnd-chip/.drop-box/.drop-items).
This commit is contained in:
@@ -179,6 +179,24 @@ a{color:inherit;text-decoration:none}
|
||||
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
|
||||
.step-box{background:var(--card);border:1.5px solid var(--border);border-radius:10px;padding:12px 14px;margin-top:10px;font-size:.94rem;line-height:1.55}
|
||||
.step-box.show{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
|
||||
|
||||
.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}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -461,6 +479,21 @@ function makeCard(kind, title, num, body){
|
||||
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>';
|
||||
}
|
||||
|
||||
/* DnD-сортер для распределения карточек по категориям */
|
||||
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 */
|
||||
function axes2D(W, H, pad, xmin, xmax, ymin, ymax){
|
||||
const ux = (W - 2*pad) / (xmax - xmin);
|
||||
@@ -1112,38 +1145,598 @@ function buildP11(){
|
||||
}
|
||||
|
||||
function buildP12(){
|
||||
const root = document.getElementById('p12-body');
|
||||
root.innerHTML = `
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon theory">${ICONS.theory}</span>
|
||||
<span class="card-title">В разработке</span>
|
||||
<span class="card-num">§ 12</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Содержание параграфа <b>«Уравнение окружности»</b> будет добавлено в следующих обновлениях.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 1.</p>
|
||||
</div>
|
||||
</div>` + secNav('p11', 'p13') + readButton('p12');
|
||||
renderMath(root);
|
||||
const box = document.getElementById('p12-body');
|
||||
let html = '';
|
||||
|
||||
html += makeCard('theory', 'Длина отрезка (расстояние между точками)', '12.1', `
|
||||
<p>Для двух точек $A(x_1;\\ y_1)$ и $B(x_2;\\ y_2)$ длина отрезка $AB$ (= расстояние между точками) равна:</p>
|
||||
<p style="text-align:center;font-size:1.05rem">$|AB| = \\sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}$</p>
|
||||
<p>Это прямое следствие <b>теоремы Пифагора</b>: разности координат — катеты прямоугольного треугольника, а отрезок $AB$ — его гипотенуза.</p>
|
||||
<p><b>Пример.</b> $A(1;\\ 2),\\ B(4;\\ 6)$:
|
||||
$|AB| = \\sqrt{(4-1)^2 + (6-2)^2} = \\sqrt{9 + 16} = \\sqrt{25} = 5$.</p>
|
||||
<details class="spoiler"><summary>Почему именно квадраты?</summary><div class="spoiler-body">
|
||||
Если построить из $A$ горизонтальный, а из $B$ вертикальный отрезок до их пересечения, получится прямоугольный треугольник с катетами $|x_2 - x_1|$ и $|y_2 - y_1|$. По Пифагору квадрат гипотенузы $|AB|^2 = (x_2-x_1)^2 + (y_2-y_1)^2$, откуда и формула.
|
||||
</div></details>`);
|
||||
|
||||
html += makeCard('rule', 'Уравнение окружности', '12.2', `
|
||||
<p>Окружность с центром $C(a;\\ b)$ и радиусом $R$ задаётся уравнением:</p>
|
||||
<p style="text-align:center;font-size:1.1rem">$(x - a)^2 + (y - b)^2 = R^2$</p>
|
||||
<p>Геометрический смысл: <b>все точки $(x;\\ y)$ плоскости, удовлетворяющие этому равенству, лежат на окружности</b>, и наоборот. Это запись свойства «расстояние от $(x;y)$ до центра $C$ равно $R$»:
|
||||
$\\sqrt{(x - a)^2 + (y - b)^2} = R$, после возведения в квадрат получаем уравнение.</p>
|
||||
<p>Числа $a$ и $b$ — координаты центра, $R > 0$ — радиус.</p>`);
|
||||
|
||||
html += makeCard('example', 'Особые случаи и примеры', '12.3', `
|
||||
<p><b>1. Центр в начале координат.</b> При $a = 0,\\ b = 0$ уравнение упрощается:
|
||||
$x^2 + y^2 = R^2$. Например, $x^2 + y^2 = 9$ — окружность с центром $(0;0)$ и радиусом $R = 3$.</p>
|
||||
<p><b>2. Через центр и точку на окружности.</b> Радиус — расстояние от центра до этой точки.
|
||||
<i>Пример.</i> Центр $C(1;\\ 2)$, точка $M(4;\\ 6)$ лежит на окружности. Тогда
|
||||
$R = \\sqrt{(4-1)^2 + (6-2)^2} = 5$, и уравнение: $(x - 1)^2 + (y - 2)^2 = 25$.</p>
|
||||
<p><b>3. По заданным центру и радиусу.</b> Уравнение окружности с центром $(2;\\ -1)$ и радиусом $R = 4$:
|
||||
$(x - 2)^2 + (y + 1)^2 = 16$.</p>`);
|
||||
|
||||
/* INTERACTIVE 1 — Окружность-конструктор */
|
||||
html += `<div class="wg" id="p12-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Окружность-конструктор</div></div>
|
||||
<div class="wg-help">Двигай ползунки центра $a, b$ и радиуса $R$ — окружность перерисуется, а уравнение под графиком подстроится.</div>
|
||||
<div class="sliders">
|
||||
<label>центр $a$ =<b id="p12-iv1-aL">0</b><input type="range" id="p12-iv1-a" min="-5" max="5" step="1" value="0"></label>
|
||||
<label>центр $b$ =<b id="p12-iv1-bL">0</b><input type="range" id="p12-iv1-b" min="-5" max="5" step="1" value="0"></label>
|
||||
<label>радиус $R$ =<b id="p12-iv1-rL">3</b><input type="range" id="p12-iv1-r" min="1" max="6" step="1" value="3"></label>
|
||||
</div>
|
||||
<div style="background:var(--card);border-radius:10px;padding:10px;overflow-x:auto">
|
||||
<svg id="p12-iv1-svg" viewBox="0 0 400 400" style="width:100%;max-width:480px;height:auto;display:block;margin:0 auto"></svg>
|
||||
</div>
|
||||
<div id="p12-iv1-eq" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:1rem;text-align:center"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 2 — Калькулятор расстояния */
|
||||
html += `<div class="wg" id="p12-iv2">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор расстояния $|AB|$</div></div>
|
||||
<div class="wg-help">Введи целые координаты двух точек $A(x_1;y_1)$ и $B(x_2;y_2)$ — калькулятор покажет подробное вычисление и нарисует отрезок.</div>
|
||||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:10px">
|
||||
<span>$A(\\ $</span>
|
||||
<input type="number" id="p12-iv2-x1" class="tinp" style="width:70px;text-align:center" value="1">
|
||||
<span>;</span>
|
||||
<input type="number" id="p12-iv2-y1" class="tinp" style="width:70px;text-align:center" value="2">
|
||||
<span>$\\ )$</span>
|
||||
<span style="margin:0 6px">$B(\\ $</span>
|
||||
<input type="number" id="p12-iv2-x2" class="tinp" style="width:70px;text-align:center" value="4">
|
||||
<span>;</span>
|
||||
<input type="number" id="p12-iv2-y2" class="tinp" style="width:70px;text-align:center" value="6">
|
||||
<span>$\\ )$</span>
|
||||
<button class="btn primary" id="p12-iv2-go">Вычислить</button>
|
||||
</div>
|
||||
<div id="p12-iv2-out" style="padding:12px 14px;background:var(--card);border-radius:9px;text-align:center;font-size:1rem;min-height:48px"></div>
|
||||
<div style="background:var(--card);border-radius:10px;padding:8px;margin-top:10px;overflow-x:auto">
|
||||
<svg id="p12-iv2-svg" viewBox="0 0 360 280" style="width:100%;max-width:420px;height:auto;display:block;margin:0 auto"></svg>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 3 — Принадлежит ли точка окружности? */
|
||||
html += `<div class="wg" id="p12-iv3">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Точка на окружности?</div></div>
|
||||
<div class="wg-help">Для каждой пары «окружность + точка» определи: точка лежит на окружности или нет?</div>
|
||||
<div class="score-display">Задача: <b id="p12-iv3-idx">1</b> / 6 · Очки: <b id="p12-iv3-sc">0</b></div>
|
||||
<div id="p12-iv3-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:60px"></div>
|
||||
<div class="actions" style="justify-content:center">
|
||||
<button class="btn primary" id="p12-iv3-ok">Лежит на окружности</button>
|
||||
<button class="btn" id="p12-iv3-bad">Не лежит</button>
|
||||
</div>
|
||||
<div class="feedback" id="p12-iv3-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 4 — Найди радиус или координату */
|
||||
html += `<div class="wg" id="p12-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр: радиус / центр / длина</div></div>
|
||||
<div class="wg-help">Прочитай уравнение или условие и введи число (радиус, координату, длину).</div>
|
||||
<div class="score-display">Задача: <b id="p12-iv4-idx">1</b> / 6 · Очки: <b id="p12-iv4-sc">0</b></div>
|
||||
<div id="p12-iv4-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:10px;min-height:60px"></div>
|
||||
<div style="display:flex;gap:10px;align-items:center;justify-content:center;flex-wrap:wrap">
|
||||
<span>Ответ =</span>
|
||||
<input type="number" id="p12-iv4-inp" class="tinp" style="width:100px;text-align:center" step="1">
|
||||
<button class="btn primary" id="p12-iv4-go">Проверить</button>
|
||||
<button class="btn" id="p12-iv4-skip">Пропустить</button>
|
||||
</div>
|
||||
<div class="feedback" id="p12-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
box.innerHTML = html + secNav('p11', 'p13') + readButton('p12');
|
||||
renderMath(box);
|
||||
|
||||
/* ===== IV1 wiring — Окружность-конструктор ===== */
|
||||
(function(){
|
||||
const aIn = document.getElementById('p12-iv1-a');
|
||||
const bIn = document.getElementById('p12-iv1-b');
|
||||
const rIn = document.getElementById('p12-iv1-r');
|
||||
const aL = document.getElementById('p12-iv1-aL');
|
||||
const bL = document.getElementById('p12-iv1-bL');
|
||||
const rL = document.getElementById('p12-iv1-rL');
|
||||
const svg = document.getElementById('p12-iv1-svg');
|
||||
const eqEl = document.getElementById('p12-iv1-eq');
|
||||
let bumped = false;
|
||||
function redraw(){
|
||||
const a = +aIn.value, b = +bIn.value, R = +rIn.value;
|
||||
aL.textContent = a; bL.textContent = b; rL.textContent = R;
|
||||
const ax = axes2D(400, 400, 30, -7, 7, -7, 7);
|
||||
let g = ax.content;
|
||||
const cx = ax.toX(a), cy = ax.toY(b), rPx = R * ax.ux;
|
||||
g += '<circle cx="'+cx+'" cy="'+cy+'" r="'+rPx+'" fill="rgba(37,99,235,.10)" stroke="#2563eb" stroke-width="2.2"/>';
|
||||
const ex = ax.toX(a + R), ey = cy;
|
||||
g += '<line x1="'+cx+'" y1="'+cy+'" x2="'+ex+'" y2="'+ey+'" stroke="#db2777" stroke-width="2" stroke-dasharray="4 3"/>';
|
||||
g += '<text x="'+((cx + ex)/2)+'" y="'+(cy - 6)+'" font-size="11" fill="#9d174d" font-weight="700" text-anchor="middle">R = '+R+'</text>';
|
||||
g += '<circle cx="'+cx+'" cy="'+cy+'" r="4.5" fill="#ef4444" stroke="#fff" stroke-width="2"/>';
|
||||
g += '<text x="'+(cx + 8)+'" y="'+(cy - 8)+'" font-size="11" fill="#7f1d1d" font-weight="700">C('+a+'; '+b+')</text>';
|
||||
svg.innerHTML = g;
|
||||
const aS = a >= 0 ? '- ' + a : '+ ' + (-a);
|
||||
const bS = b >= 0 ? '- ' + b : '+ ' + (-b);
|
||||
eqEl.innerHTML = '$(x \\, ' + aS + ')^2 + (y \\, ' + bS + ')^2 = ' + (R*R) + '$';
|
||||
renderMath(eqEl);
|
||||
if (!bumped){ bumped = true; bumpProgress('p12', 15); addXp(10, 'p12-iv1'); }
|
||||
}
|
||||
[aIn, bIn, rIn].forEach(el => el.addEventListener('input', redraw));
|
||||
redraw();
|
||||
})();
|
||||
|
||||
/* ===== IV2 wiring — Калькулятор расстояния ===== */
|
||||
(function(){
|
||||
const x1In = document.getElementById('p12-iv2-x1');
|
||||
const y1In = document.getElementById('p12-iv2-y1');
|
||||
const x2In = document.getElementById('p12-iv2-x2');
|
||||
const y2In = document.getElementById('p12-iv2-y2');
|
||||
const out = document.getElementById('p12-iv2-out');
|
||||
const svg = document.getElementById('p12-iv2-svg');
|
||||
let bumped = false;
|
||||
function compute(){
|
||||
const x1 = +x1In.value, y1 = +y1In.value, x2 = +x2In.value, y2 = +y2In.value;
|
||||
const dx = x2 - x1, dy = y2 - y1;
|
||||
const sq = dx*dx + dy*dy;
|
||||
const d = Math.sqrt(sq);
|
||||
const dStr = Number.isInteger(d) ? String(d) : d.toFixed(2);
|
||||
let h = '<div>$|AB| = \\sqrt{(' + x2 + ' - ' + x1 + ')^2 + (' + y2 + ' - ' + y1 + ')^2}$</div>';
|
||||
h += '<div style="margin-top:6px">$= \\sqrt{(' + dx + ')^2 + (' + dy + ')^2} = \\sqrt{' + (dx*dx) + ' + ' + (dy*dy) + '} = \\sqrt{' + sq + '}$</div>';
|
||||
h += '<div style="margin-top:6px;color:var(--ok)"><b>$|AB| = ' + dStr + '$</b></div>';
|
||||
out.innerHTML = h;
|
||||
renderMath(out);
|
||||
const lo = Math.min(x1, y1, x2, y2, 0) - 1;
|
||||
const hi = Math.max(x1, y1, x2, y2, 0) + 1;
|
||||
const ax = axes2D(360, 280, 26, Math.floor(lo), Math.ceil(hi), Math.floor(lo), Math.ceil(hi));
|
||||
let g = ax.content;
|
||||
const ax1 = ax.toX(x1), ay1 = ax.toY(y1), ax2 = ax.toX(x2), ay2 = ax.toY(y2);
|
||||
g += '<line x1="'+ax1+'" y1="'+ay1+'" x2="'+ax2+'" y2="'+ay2+'" stroke="#7c3aed" stroke-width="2.4"/>';
|
||||
g += '<circle cx="'+ax1+'" cy="'+ay1+'" r="4" fill="#ef4444" stroke="#fff" stroke-width="2"/>';
|
||||
g += '<text x="'+(ax1 + 7)+'" y="'+(ay1 - 7)+'" font-size="11" fill="#7f1d1d" font-weight="700">A('+x1+';'+y1+')</text>';
|
||||
g += '<circle cx="'+ax2+'" cy="'+ay2+'" r="4" fill="#10b981" stroke="#fff" stroke-width="2"/>';
|
||||
g += '<text x="'+(ax2 + 7)+'" y="'+(ay2 - 7)+'" font-size="11" fill="#065f46" font-weight="700">B('+x2+';'+y2+')</text>';
|
||||
svg.innerHTML = g;
|
||||
if (!bumped){ bumped = true; bumpProgress('p12', 15); addXp(10, 'p12-iv2'); }
|
||||
}
|
||||
document.getElementById('p12-iv2-go').addEventListener('click', compute);
|
||||
compute();
|
||||
})();
|
||||
|
||||
/* ===== IV3 wiring — Точка на окружности? ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q: 'Окружность $x^2 + y^2 = 25$, точка $(3;\\ 4)$.', ans: true, hint: '$3^2 + 4^2 = 9 + 16 = 25$ — равно $R^2$. Точка лежит.' },
|
||||
{ q: 'Окружность $x^2 + y^2 = 25$, точка $(0;\\ 5)$.', ans: true, hint: '$0 + 25 = 25$. Точка лежит.' },
|
||||
{ q: 'Окружность $x^2 + y^2 = 25$, точка $(2;\\ 3)$.', ans: false, hint: '$4 + 9 = 13 \\ne 25$. Точка не лежит.' },
|
||||
{ q: 'Окружность $(x - 1)^2 + y^2 = 4$, точка $(3;\\ 0)$.', ans: true, hint: '$(3-1)^2 + 0 = 4$. Точка лежит.' },
|
||||
{ q: 'Окружность $(x - 2)^2 + (y + 1)^2 = 9$, точка $(2;\\ 2)$.', ans: true, hint: '$0 + (2+1)^2 = 9$. Точка лежит.' },
|
||||
{ q: 'Окружность $x^2 + (y - 3)^2 = 16$, точка $(4;\\ 3)$.', ans: true, hint: '$16 + 0 = 16$. Точка лежит.' }
|
||||
];
|
||||
let i = 0, sc = 0, bumped = false;
|
||||
const idxEl = document.getElementById('p12-iv3-idx');
|
||||
const scEl = document.getElementById('p12-iv3-sc');
|
||||
const qEl = document.getElementById('p12-iv3-q');
|
||||
const fb = document.getElementById('p12-iv3-fb');
|
||||
const okBtn = document.getElementById('p12-iv3-ok');
|
||||
const badBtn = document.getElementById('p12-iv3-bad');
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i + 1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
okBtn.disabled = true; badBtn.disabled = true;
|
||||
okBtn.style.opacity = .5; badBtn.style.opacity = .5;
|
||||
if (!bumped){ bumped = true; bumpProgress('p12', 25); addXp(15, 'p12-iv3'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
}
|
||||
function answer(v){
|
||||
if (i >= items.length) return;
|
||||
const it = items[i];
|
||||
const ok = (v === it.ans);
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok ? '✓ Верно. ' : '✗ Неверно. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1100);
|
||||
}
|
||||
okBtn.addEventListener('click', ()=>answer(true));
|
||||
badBtn.addEventListener('click', ()=>answer(false));
|
||||
render();
|
||||
})();
|
||||
|
||||
/* ===== IV4 wiring — Тренажёр: радиус / центр / длина ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q: 'Уравнение окружности: $(x - 3)^2 + (y - 5)^2 = 49$. Найди <b>радиус</b> $R$.', ans: 7, hint: '$R^2 = 49 \\Rightarrow R = 7$.' },
|
||||
{ q: 'Уравнение окружности: $(x + 2)^2 + (y - 4)^2 = 16$. Найди координату центра <b>$a$</b>.', ans: -2, hint: 'Сравни с $(x - a)^2$: $x + 2 = x - (-2) \\Rightarrow a = -2$.' },
|
||||
{ q: 'Уравнение окружности: $x^2 + (y + 1)^2 = 100$. Найди <b>радиус</b> $R$.', ans: 10, hint: '$R^2 = 100 \\Rightarrow R = 10$.' },
|
||||
{ q: 'Найди длину отрезка $AB$, где $A(0;\\ 0),\\ B(6;\\ 8)$.', ans: 10, hint: '$|AB| = \\sqrt{36 + 64} = \\sqrt{100} = 10$.' },
|
||||
{ q: 'Найди длину отрезка $AB$, где $A(-2;\\ 1),\\ B(4;\\ 1)$.', ans: 6, hint: 'Точки на одной горизонтали: $|AB| = |4 - (-2)| = 6$.' },
|
||||
{ q: 'Окружность $(x - 3)^2 + y^2 = 25$ пересекает ось $Ox$ в двух точках. Найди <b>меньшую</b> координату $x$ точки пересечения.', ans: -2, hint: 'При $y = 0$: $(x-3)^2 = 25 \\Rightarrow x - 3 = \\pm 5 \\Rightarrow x = 8$ или $x = -2$. Меньшая = $-2$.' }
|
||||
];
|
||||
let i = 0, sc = 0, bumped = false;
|
||||
const idxEl = document.getElementById('p12-iv4-idx');
|
||||
const scEl = document.getElementById('p12-iv4-sc');
|
||||
const qEl = document.getElementById('p12-iv4-q');
|
||||
const inp = document.getElementById('p12-iv4-inp');
|
||||
const fb = document.getElementById('p12-iv4-fb');
|
||||
const goBtn = document.getElementById('p12-iv4-go');
|
||||
const skipBtn = document.getElementById('p12-iv4-skip');
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i + 1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
inp.disabled = true; goBtn.disabled = true; skipBtn.disabled = true;
|
||||
inp.style.opacity = .5; goBtn.style.opacity = .5; skipBtn.style.opacity = .5;
|
||||
if (!bumped){ bumped = true; bumpProgress('p12', 25); addXp(15, 'p12-iv4'); achievement('p12_done'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
inp.value = '';
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
}
|
||||
function check(){
|
||||
if (i >= items.length) return;
|
||||
const v = parseFloat(inp.value);
|
||||
const it = items[i];
|
||||
if (isNaN(v)){ feedback(fb, false, 'Введи число.'); return; }
|
||||
const ok = Math.abs(v - it.ans) < 1e-6;
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok ? '✓ Верно! ' : '✗ Неверно. Ответ: $' + it.ans + '$. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1200);
|
||||
}
|
||||
function skip(){
|
||||
if (i >= items.length) return;
|
||||
const it = items[i];
|
||||
feedback(fb, false, 'Пропущено. Ответ: $' + it.ans + '$. ' + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1200);
|
||||
}
|
||||
goBtn.addEventListener('click', check);
|
||||
skipBtn.addEventListener('click', skip);
|
||||
inp.addEventListener('keydown', e => { if (e.key === 'Enter') check(); });
|
||||
render();
|
||||
})();
|
||||
|
||||
wireReadBtn('p12');
|
||||
}
|
||||
|
||||
function buildP13(){
|
||||
const root = document.getElementById('p13-body');
|
||||
root.innerHTML = `
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon theory">${ICONS.theory}</span>
|
||||
<span class="card-title">В разработке</span>
|
||||
<span class="card-num">§ 13</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Содержание параграфа <b>«Метод интервалов»</b> будет добавлено в следующих обновлениях.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 1.</p>
|
||||
</div>
|
||||
</div>` + secNav('p12', 'final3') + readButton('p13');
|
||||
renderMath(root);
|
||||
const box = document.getElementById('p13-body');
|
||||
let html = '';
|
||||
|
||||
html += makeCard('theory', 'Метод интервалов', '13.1', `
|
||||
<p>Для неравенств вида $\\dfrac{P(x)}{Q(x)} \\, [><] \\, 0$ применяют <b>метод интервалов</b>:</p>
|
||||
<ol style="padding-left:22px;line-height:1.85">
|
||||
<li>Найти все корни уравнений $P(x) = 0$ <i>(нули числителя)</i> и $Q(x) = 0$ <i>(нули знаменателя)</i>.</li>
|
||||
<li>Отметить корни на числовой прямой. Корни знаменателя — <b>всегда выколоты</b> (в них дробь не определена). Корни числителя — закрашены при нестрогом неравенстве ($\\le,\\ \\ge$) и выколоты при строгом ($<,\\ >$).</li>
|
||||
<li>На каждом интервале определить <b>знак</b> выражения (например, подставив пробное число).</li>
|
||||
<li>Записать ответ — объединение интервалов с нужным знаком, учитывая закрашенные/выколотые точки.</li>
|
||||
</ol>`);
|
||||
|
||||
html += makeCard('rule', 'Правило знаков (чередование)', '13.2', `
|
||||
<p>Если все корни <b>простые</b> (степени 1), знаки на интервалах <b>чередуются</b>: $\\ldots\\,+\\,-\\,+\\,-\\,\\ldots$ Достаточно определить знак на одном интервале (обычно крайнем правом) — остальные восстановятся.</p>
|
||||
<p>Если корень с <b>чётной кратностью</b> (например, $(x - 2)^2$) — при переходе через него знак <b>не меняется</b>.</p>
|
||||
<p>На крайнем правом интервале знак удобно проверить, подставив очень большое $x$ — обычно знак совпадает со знаком старшего коэффициента в числителе $\\div$ знаменателя.</p>`);
|
||||
|
||||
html += makeCard('example', 'Пример пошагово', '13.3', `
|
||||
<p><b>Решить:</b> $\\dfrac{x - 1}{x + 2} \\le 0$.</p>
|
||||
<p><b>1.</b> Корни: $x = 1$ (числитель, закрашен — неравенство нестрогое) и $x = -2$ (знаменатель, всегда выколота).</p>
|
||||
<p><b>2.</b> На числовой прямой: $\\ldots \\;[-]\\; \\circ_{-2} \\;[+]\\; \\bullet_{1} \\;[-]\\; \\ldots$</p>
|
||||
<p><b>3.</b> Проверка знака при $x = 5$: $\\dfrac{4}{7} > 0$ — крайний правый интервал «$+$». Значит, чередование такое, как показано.</p>
|
||||
<p><b>4.</b> Нужен $\\le 0$ — берём «$-$»-интервалы. Слева от $-2$ — но $x = -2$ выколота. Справа от $-2$ — «$+$», пропускаем. Между $-2$ и $1$ — это «$+$»-интервал? Перепроверим: при $x = 0$: $\\dfrac{-1}{2} < 0$ — да, «$-$». Берём $(-2;\\ 1]$.</p>
|
||||
<p style="color:var(--ok);font-weight:700">Ответ: $x \\in (-2;\\ 1]$.</p>`);
|
||||
|
||||
/* INTERACTIVE 1 — Числовая прямая знаков */
|
||||
html += `<div class="wg" id="p13-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Числовая прямая знаков</div></div>
|
||||
<div class="wg-help">Выбери неравенство ползунком — на числовой прямой увидишь корни (закрашенные/выколотые) и знаки на интервалах. Внизу — ответ.</div>
|
||||
<div class="sliders">
|
||||
<label>Задача №<b id="p13-iv1-idx">1</b> / 5<input type="range" id="p13-iv1-slider" min="1" max="5" step="1" value="1"></label>
|
||||
</div>
|
||||
<div id="p13-iv1-ineq" style="text-align:center;font-size:1.1rem;padding:10px;background:var(--card);border-radius:9px;margin-bottom:10px"></div>
|
||||
<div style="background:var(--card);border-radius:10px;padding:10px;overflow-x:auto">
|
||||
<svg id="p13-iv1-svg" viewBox="0 0 600 120" style="width:100%;max-width:680px;height:auto;display:block;margin:0 auto"></svg>
|
||||
</div>
|
||||
<div id="p13-iv1-out" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.98rem;text-align:center"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 2 — Закрашена или выколота? (DnD) */
|
||||
html += `<div class="wg" id="p13-iv2">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Закрашена или выколота?</div></div>
|
||||
<div class="wg-help">Перетащи каждую карточку «корень в неравенстве» в нужную колонку. Корни числителя при нестрогом неравенстве — закрашены ($\\bullet$); корни знаменателя и любые корни при строгом неравенстве — выколоты ($\\circ$).</div>
|
||||
<div id="p13-iv2-pool"></div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
|
||||
<div class="drop-box"><h5>Закрашена ●</h5><div class="drop-items" data-cat="full"></div></div>
|
||||
<div class="drop-box"><h5>Выколота ○</h5><div class="drop-items" data-cat="empty"></div></div>
|
||||
</div>
|
||||
<div class="actions" style="justify-content:center;margin-top:12px">
|
||||
<button class="btn primary" id="p13-iv2-check">Проверить</button>
|
||||
<button class="btn" id="p13-iv2-reset">Сбросить</button>
|
||||
</div>
|
||||
<div class="feedback" id="p13-iv2-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 3 — Сколько целых решений? */
|
||||
html += `<div class="wg" id="p13-iv3">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Сколько целых $x \\in [-5;5]$ — решения?</div></div>
|
||||
<div class="wg-help">Для каждого неравенства подсчитай, сколько целых $x$ из отрезка $[-5;\\ 5]$ ему удовлетворяют.</div>
|
||||
<div class="score-display">Задача: <b id="p13-iv3-idx">1</b> / 6 · Очки: <b id="p13-iv3-sc">0</b></div>
|
||||
<div id="p13-iv3-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:10px;min-height:60px"></div>
|
||||
<div style="display:flex;gap:10px;align-items:center;justify-content:center;flex-wrap:wrap">
|
||||
<span>Количество =</span>
|
||||
<input type="number" id="p13-iv3-inp" class="tinp" style="width:90px;text-align:center" step="1">
|
||||
<button class="btn primary" id="p13-iv3-go">Проверить</button>
|
||||
<button class="btn" id="p13-iv3-skip">Пропустить</button>
|
||||
</div>
|
||||
<div class="feedback" id="p13-iv3-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 4 — Тренажёр интервалов (сумма концов) */
|
||||
html += `<div class="wg" id="p13-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Сумма концов интервалов</div></div>
|
||||
<div class="wg-help">Реши неравенство, запиши ответ в виде объединения интервалов, и введи <b>сумму всех конечных концов</b> (бесконечности не учитываются).</div>
|
||||
<div class="score-display">Задача: <b id="p13-iv4-idx">1</b> / 6 · Очки: <b id="p13-iv4-sc">0</b></div>
|
||||
<div id="p13-iv4-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:10px;min-height:60px"></div>
|
||||
<div style="display:flex;gap:10px;align-items:center;justify-content:center;flex-wrap:wrap">
|
||||
<span>Сумма =</span>
|
||||
<input type="number" id="p13-iv4-inp" class="tinp" style="width:100px;text-align:center" step="1">
|
||||
<button class="btn primary" id="p13-iv4-go">Проверить</button>
|
||||
<button class="btn" id="p13-iv4-skip">Пропустить</button>
|
||||
</div>
|
||||
<div class="feedback" id="p13-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
box.innerHTML = html + secNav('p12', 'final3') + readButton('p13');
|
||||
renderMath(box);
|
||||
|
||||
/* ===== IV1 wiring — Числовая прямая ===== */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{
|
||||
ineq: '$\\dfrac{x}{x - 3} > 0$',
|
||||
points: [{x:0, full:false}, {x:3, full:false}],
|
||||
signs: [{from:-8, to:0, s:'+'}, {from:0, to:3, s:'-'}, {from:3, to:8, s:'+'}],
|
||||
answer: '$(-\\infty;\\ 0) \\cup (3;\\ +\\infty)$'
|
||||
},
|
||||
{
|
||||
ineq: '$\\dfrac{x - 2}{x + 1} \\le 0$',
|
||||
points: [{x:-1, full:false}, {x:2, full:true}],
|
||||
signs: [{from:-8, to:-1, s:'+'}, {from:-1, to:2, s:'-'}, {from:2, to:8, s:'+'}],
|
||||
answer: '$(-1;\\ 2]$'
|
||||
},
|
||||
{
|
||||
ineq: '$(x - 1)(x - 3) > 0$',
|
||||
points: [{x:1, full:false}, {x:3, full:false}],
|
||||
signs: [{from:-8, to:1, s:'+'}, {from:1, to:3, s:'-'}, {from:3, to:8, s:'+'}],
|
||||
answer: '$(-\\infty;\\ 1) \\cup (3;\\ +\\infty)$'
|
||||
},
|
||||
{
|
||||
ineq: '$\\dfrac{1}{x^2 - 4} < 0$',
|
||||
points: [{x:-2, full:false}, {x:2, full:false}],
|
||||
signs: [{from:-8, to:-2, s:'+'}, {from:-2, to:2, s:'-'}, {from:2, to:8, s:'+'}],
|
||||
answer: '$(-2;\\ 2)$'
|
||||
},
|
||||
{
|
||||
ineq: '$\\dfrac{x + 2}{(x - 1)(x + 1)} \\ge 0$',
|
||||
points: [{x:-2, full:true}, {x:-1, full:false}, {x:1, full:false}],
|
||||
signs: [{from:-8, to:-2, s:'-'}, {from:-2, to:-1, s:'+'}, {from:-1, to:1, s:'-'}, {from:1, to:8, s:'+'}],
|
||||
answer: '$[-2;\\ -1) \\cup (1;\\ +\\infty)$'
|
||||
}
|
||||
];
|
||||
const sl = document.getElementById('p13-iv1-slider');
|
||||
const idxEl = document.getElementById('p13-iv1-idx');
|
||||
const ineqEl = document.getElementById('p13-iv1-ineq');
|
||||
const svg = document.getElementById('p13-iv1-svg');
|
||||
const out = document.getElementById('p13-iv1-out');
|
||||
let bumped = false;
|
||||
|
||||
function draw(){
|
||||
const idx = (+sl.value) - 1;
|
||||
const t = tasks[idx];
|
||||
idxEl.textContent = idx + 1;
|
||||
ineqEl.innerHTML = t.ineq;
|
||||
const W = 600, H = 120, padX = 30, y0 = 70;
|
||||
const xmin = -8, xmax = 8;
|
||||
const toX = v => padX + (v - xmin) * (W - 2*padX) / (xmax - xmin);
|
||||
let g = '';
|
||||
g += '<line x1="'+padX+'" y1="'+y0+'" x2="'+(W - padX)+'" y2="'+y0+'" stroke="#0f172a" stroke-width="2"/>';
|
||||
g += '<polygon points="'+(W-padX-10)+','+(y0-5)+' '+(W-padX)+','+y0+' '+(W-padX-10)+','+(y0+5)+'" fill="#0f172a"/>';
|
||||
for (let x = xmin + 1; x <= xmax - 1; x++){
|
||||
g += '<line x1="'+toX(x)+'" y1="'+(y0-4)+'" x2="'+toX(x)+'" y2="'+(y0+4)+'" stroke="#94a3b8" stroke-width="1"/>';
|
||||
g += '<text x="'+toX(x)+'" y="'+(y0+18)+'" font-size="10" fill="#64748b" text-anchor="middle">'+x+'</text>';
|
||||
}
|
||||
t.signs.forEach(s => {
|
||||
const cx = (toX(s.from) + toX(s.to)) / 2;
|
||||
const col = s.s === '+' ? '#10b981' : '#ef4444';
|
||||
g += '<text x="'+cx+'" y="'+(y0-14)+'" font-size="20" font-weight="800" fill="'+col+'" text-anchor="middle">'+s.s+'</text>';
|
||||
});
|
||||
t.points.forEach(p => {
|
||||
const px = toX(p.x);
|
||||
if (p.full){
|
||||
g += '<circle cx="'+px+'" cy="'+y0+'" r="6" fill="#0f172a" stroke="#0f172a" stroke-width="2"/>';
|
||||
} else {
|
||||
g += '<circle cx="'+px+'" cy="'+y0+'" r="6" fill="#fff" stroke="#0f172a" stroke-width="2"/>';
|
||||
}
|
||||
g += '<text x="'+px+'" y="'+(y0+34)+'" font-size="11" fill="#0f172a" font-weight="700" text-anchor="middle">'+p.x+'</text>';
|
||||
});
|
||||
svg.innerHTML = g;
|
||||
out.innerHTML = '<b>Ответ:</b> $x \\in $ ' + t.answer;
|
||||
renderMath(ineqEl); renderMath(out);
|
||||
if (!bumped){ bumped = true; bumpProgress('p13', 15); addXp(10, 'p13-iv1'); }
|
||||
}
|
||||
sl.addEventListener('input', draw);
|
||||
draw();
|
||||
})();
|
||||
|
||||
/* ===== IV2 wiring — DnD: закрашена/выколота ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ id:'a', html:'$x = 0$ в $\\dfrac{x}{x - 3} \\ge 0$', cat:'full' },
|
||||
{ id:'b', html:'$x = 3$ в $\\dfrac{x}{x - 3} \\ge 0$', cat:'empty' },
|
||||
{ id:'c', html:'$x = 1$ в $\\dfrac{x - 1}{x + 2} > 0$', cat:'empty' },
|
||||
{ id:'d', html:'$x = -2$ в $\\dfrac{x - 1}{x + 2} > 0$', cat:'empty' },
|
||||
{ id:'e', html:'$x = 5$ в $(x - 5)(x + 1) \\ge 0$', cat:'full' },
|
||||
{ id:'f', html:'$x = -3$ в $(x + 3)^2 > 0$', cat:'empty' }
|
||||
];
|
||||
const sorter = setupSorter({
|
||||
poolId: 'p13-iv2-pool',
|
||||
scopeSelector: '#p13-iv2',
|
||||
cats: ['full', 'empty'],
|
||||
items: items
|
||||
});
|
||||
let bumped = false;
|
||||
document.getElementById('p13-iv2-check').addEventListener('click', () => {
|
||||
const fb = document.getElementById('p13-iv2-fb');
|
||||
const total = items.length;
|
||||
let correct = 0, placed = 0;
|
||||
items.forEach(it => { if (sorter.placed[it.id]){ placed++; if (sorter.placed[it.id] === it.cat) correct++; } });
|
||||
if (placed < total){
|
||||
feedback(fb, false, 'Размещены не все: ' + placed + ' / ' + total + '.');
|
||||
return;
|
||||
}
|
||||
const ok = (correct === total);
|
||||
feedback(fb, ok, ok ? '✓ Все верно! ' + correct + ' / ' + total : '✗ Правильно: ' + correct + ' / ' + total);
|
||||
if (ok && !bumped){ bumped = true; bumpProgress('p13', 15); addXp(10, 'p13-iv2'); }
|
||||
});
|
||||
document.getElementById('p13-iv2-reset').addEventListener('click', () => {
|
||||
sorter.reset();
|
||||
const fb = document.getElementById('p13-iv2-fb'); fb.style.display = 'none';
|
||||
});
|
||||
})();
|
||||
|
||||
/* ===== IV3 wiring — Сколько целых решений? ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q: '$\\dfrac{x}{x - 2} > 0$', ans: 8, hint: 'Решение $(-\\infty;0) \\cup (2;+\\infty)$. Целые из $[-5;5]$: $\\{-5,-4,-3,-2,-1,3,4,5\\}$ — 8 шт.' },
|
||||
{ q: '$\\dfrac{1}{x + 1} < 0$', ans: 4, hint: 'Решение $x < -1$. Целые из $[-5;5]$: $\\{-5,-4,-3,-2\\}$ — 4 шт.' },
|
||||
{ q: '$\\dfrac{x - 2}{x + 3} \\le 0$', ans: 5, hint: 'Решение $(-3;\\ 2]$. Целые: $\\{-2,-1,0,1,2\\}$ — 5 шт.' },
|
||||
{ q: '$(x - 1)(x + 1) > 0$', ans: 8, hint: 'Решение $|x| > 1$. Целые из $[-5;5]$: $\\{-5,-4,-3,-2,2,3,4,5\\}$ — 8 шт.' },
|
||||
{ q: '$\\dfrac{x}{x^2 + 1} \\ge 0$', ans: 6, hint: 'Знаменатель $> 0$, значит $x \\ge 0$. Целые: $\\{0,1,2,3,4,5\\}$ — 6 шт.' },
|
||||
{ q: '$\\dfrac{1}{x^2 - 4} > 0$', ans: 6, hint: 'Решение $|x| > 2$. Целые из $[-5;5]$: $\\{-5,-4,-3,3,4,5\\}$ — 6 шт.' }
|
||||
];
|
||||
let i = 0, sc = 0, bumped = false;
|
||||
const idxEl = document.getElementById('p13-iv3-idx');
|
||||
const scEl = document.getElementById('p13-iv3-sc');
|
||||
const qEl = document.getElementById('p13-iv3-q');
|
||||
const inp = document.getElementById('p13-iv3-inp');
|
||||
const fb = document.getElementById('p13-iv3-fb');
|
||||
const goBtn = document.getElementById('p13-iv3-go');
|
||||
const skipBtn = document.getElementById('p13-iv3-skip');
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i + 1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
inp.disabled = true; goBtn.disabled = true; skipBtn.disabled = true;
|
||||
inp.style.opacity = .5; goBtn.style.opacity = .5; skipBtn.style.opacity = .5;
|
||||
if (!bumped){ bumped = true; bumpProgress('p13', 25); addXp(15, 'p13-iv3'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
inp.value = '';
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
}
|
||||
function check(){
|
||||
if (i >= items.length) return;
|
||||
const v = parseFloat(inp.value);
|
||||
const it = items[i];
|
||||
if (isNaN(v)){ feedback(fb, false, 'Введи число.'); return; }
|
||||
const ok = Math.abs(v - it.ans) < 1e-6;
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok ? '✓ Верно! ' : '✗ Неверно. Ответ: ' + it.ans + '. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1300);
|
||||
}
|
||||
function skip(){
|
||||
if (i >= items.length) return;
|
||||
const it = items[i];
|
||||
feedback(fb, false, 'Пропущено. Ответ: ' + it.ans + '. ' + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1300);
|
||||
}
|
||||
goBtn.addEventListener('click', check);
|
||||
skipBtn.addEventListener('click', skip);
|
||||
inp.addEventListener('keydown', e => { if (e.key === 'Enter') check(); });
|
||||
render();
|
||||
})();
|
||||
|
||||
/* ===== IV4 wiring — Сумма концов интервалов ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q: '$\\dfrac{x}{x - 3} > 0$', ans: 3, hint: 'Ответ $(-\\infty;0) \\cup (3;+\\infty)$. Конечные концы: $0,\\ 3$. Сумма $= 3$.' },
|
||||
{ q: '$\\dfrac{x - 2}{x + 1} \\le 0$', ans: 1, hint: 'Ответ $(-1;\\ 2]$. Концы $-1,\\ 2$. Сумма $= 1$.' },
|
||||
{ q: '$(x - 1)(x - 3) > 0$', ans: 4, hint: 'Ответ $(-\\infty;1) \\cup (3;+\\infty)$. Концы $1,\\ 3$. Сумма $= 4$.' },
|
||||
{ q: '$\\dfrac{x + 2}{x - 4} < 0$', ans: 2, hint: 'Ответ $(-2;\\ 4)$. Концы $-2,\\ 4$. Сумма $= 2$.' },
|
||||
{ q: '$(x - 5)(x + 5) \\le 0$', ans: 0, hint: 'Ответ $[-5;\\ 5]$. Концы $-5,\\ 5$. Сумма $= 0$.' },
|
||||
{ q: '$\\dfrac{x}{(x - 1)(x + 1)} \\ge 0$', ans: 0, hint: 'Корни $0$ (закрашен), $\\pm 1$ (выколоты). Знаки $-,+,-,+$. Ответ $(-1;\\ 0] \\cup (1;+\\infty)$. Концы $-1,\\ 0,\\ 1$. Сумма $= 0$.' }
|
||||
];
|
||||
let i = 0, sc = 0, bumped = false;
|
||||
const idxEl = document.getElementById('p13-iv4-idx');
|
||||
const scEl = document.getElementById('p13-iv4-sc');
|
||||
const qEl = document.getElementById('p13-iv4-q');
|
||||
const inp = document.getElementById('p13-iv4-inp');
|
||||
const fb = document.getElementById('p13-iv4-fb');
|
||||
const goBtn = document.getElementById('p13-iv4-go');
|
||||
const skipBtn = document.getElementById('p13-iv4-skip');
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i + 1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
inp.disabled = true; goBtn.disabled = true; skipBtn.disabled = true;
|
||||
inp.style.opacity = .5; goBtn.style.opacity = .5; skipBtn.style.opacity = .5;
|
||||
if (!bumped){ bumped = true; bumpProgress('p13', 25); addXp(15, 'p13-iv4'); achievement('p13_done'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
inp.value = '';
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
}
|
||||
function check(){
|
||||
if (i >= items.length) return;
|
||||
const v = parseFloat(inp.value);
|
||||
const it = items[i];
|
||||
if (isNaN(v)){ feedback(fb, false, 'Введи число.'); return; }
|
||||
const ok = Math.abs(v - it.ans) < 1e-6;
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok ? '✓ Верно! ' : '✗ Неверно. Сумма $= ' + it.ans + '$. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1300);
|
||||
}
|
||||
function skip(){
|
||||
if (i >= items.length) return;
|
||||
const it = items[i];
|
||||
feedback(fb, false, 'Пропущено. Сумма $= ' + it.ans + '$. ' + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1300);
|
||||
}
|
||||
goBtn.addEventListener('click', check);
|
||||
skipBtn.addEventListener('click', skip);
|
||||
inp.addEventListener('keydown', e => { if (e.key === 'Enter') check(); });
|
||||
render();
|
||||
})();
|
||||
|
||||
wireReadBtn('p13');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user