2c8eb84c65
§7 «Квадратные уравнения. Неполные»: - Теория, правила, алгоритм, примеры - INTERACT 1: Конструктор уравнения (3 слайдера a/b/c, live-расчёт типа и корней) - INTERACT 2: Сортировка 8 уравнений по 3 типам (полное/неполное/не квадратное) - INTERACT 3: Пошаговый решатель неполных (2 типа: bc=0, ac=0) - INTERACT 4: Задача про страницу книги (165 см²) - INTERACT 5: Тренажёр 10 неполных с таймером - INTERACT 6: «Имеет ли корни?» — 8 раундов на знаки §8 «Формулы корней. Дискриминант»: - Вывод формулы, таблица 3 случаев, алгоритм 5 шагов - INTERACT 1: Калькулятор дискриминанта (пошагово) - INTERACT 2: SVG-парабола (a, b, c слайдеры) + точки пересечения с OX - INTERACT 3: 3 случая D (>0, =0, <0) с мини-графиками - INTERACT 4: Тренажёр «сколько корней?» 10 уравнений - INTERACT 5: Пошаговый решатель полного квадратного - INTERACT 6: «Угадай знак D» только по графику параболы Скелет: 6 параграфов (§7-§12) + финал, цвета по секциям, LocalStorage, 12 достижений, hero-прогресс, KaTeX, тёмная тема. §§9-12 + final — stubs до следующих волн.
1440 lines
89 KiB
HTML
1440 lines
89 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||
<meta http-equiv="Pragma" content="no-cache">
|
||
<meta http-equiv="Expires" content="0">
|
||
<title>Алгебра 8 · Глава 2 · Квадратные уравнения</title>
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
|
||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
|
||
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Manrope:wght@400;500;600;700;800&family=Unbounded:wght@400;700;800;900&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{
|
||
--pri:#e91e63; --pri2:#c2185b; --pri-soft:#fce7f3;
|
||
--acc:#03a9f4; --acc2:#0288d1; --acc-soft:#e0f4ff;
|
||
--ok:#10b981; --ok-bg:#d1fae5;
|
||
--fail:#ef4444; --fail-bg:#fee2e2;
|
||
--warn:#f59e0b; --warn-bg:#fef3c7;
|
||
--bg:#fdf2f8; --card:#fff;
|
||
--text:#1a1a2e; --muted:#6b5b73;
|
||
--border:#fce7f3;
|
||
--sh:0 2px 12px rgba(233,30,99,.07);
|
||
--sh2:0 6px 24px rgba(233,30,99,.10);
|
||
}
|
||
.dark{
|
||
--bg:#1a0f1a; --card:#2a1929;
|
||
--text:#f5e6f0; --muted:#b0a0b0;
|
||
--border:#5a2a5a; --pri-soft:#4a1a3a;
|
||
--acc-soft:#1a3a4a;
|
||
--sh:0 2px 12px rgba(0,0,0,.4);
|
||
--sh2:0 6px 24px rgba(0,0,0,.5);
|
||
}
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
html,body{height:100%}
|
||
body{font-family:'Inter','Manrope',system-ui,sans-serif;background:var(--bg);color:var(--text);display:flex;flex-direction:column;min-height:100vh;line-height:1.5;transition:background .25s,color .25s}
|
||
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
|
||
input,select,textarea{font-family:inherit}
|
||
.ic{width:1em;height:1em;display:inline-block;vertical-align:-.125em;flex-shrink:0;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
|
||
|
||
/* HEADER */
|
||
.hdr{position:relative;background:linear-gradient(110deg,#c2185b 0%,#e91e63 55%,#ec407a 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(255,180,210,.2);min-height:130px}
|
||
.hdr::before{content:'ГЛАВА 2';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(5rem,15vw,11rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(255,220,235,.08);line-height:1;pointer-events:none;user-select:none;z-index:0}
|
||
.hdr-row{position:relative;z-index:1;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
|
||
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:900;letter-spacing:-.01em;line-height:1.3;padding-top:4px}
|
||
.hdr-sub{font-size:.85rem;opacity:.88;margin-top:6px;font-weight:500;line-height:1.4}
|
||
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center}
|
||
.hdr-btn{padding:7px 12px;border-radius:9px;background:rgba(255,255,255,.14);color:#fff;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;text-decoration:none}
|
||
.hdr-btn:hover{background:rgba(255,255,255,.24)}
|
||
|
||
/* MAIN */
|
||
.main{max-width:1240px;margin:0 auto;padding:22px;width:100%;display:grid;grid-template-columns:1fr 280px;gap:24px}
|
||
@media(max-width:980px){.main{grid-template-columns:1fr;padding:14px}}
|
||
.col-main{min-width:0}
|
||
|
||
/* HERO */
|
||
.hero{background:linear-gradient(135deg,var(--pri-soft) 0%,var(--acc-soft) 50%,var(--pri-soft) 100%);background-size:200% 200%;animation:heroShift 12s ease-in-out infinite;border:1px solid var(--border);border-radius:18px;padding:24px 22px;margin-bottom:24px;position:relative;overflow:hidden}
|
||
@keyframes heroShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
|
||
.hero::before{content:'ax² + bx + c = 0';position:absolute;right:-10px;top:-20px;font-family:'JetBrains Mono',monospace;font-size:clamp(2rem,8vw,5.5rem);font-weight:900;color:var(--pri);opacity:.08;line-height:1;pointer-events:none}
|
||
.hero h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px;letter-spacing:-.01em}
|
||
.hero p{font-size:.95rem;color:var(--text);opacity:.88;margin-bottom:14px;max-width:640px}
|
||
.hero-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
|
||
.btn-primary{padding:11px 22px;background:linear-gradient(135deg,var(--pri),var(--pri2));color:#fff;border-radius:11px;font-weight:700;font-size:.92rem;display:inline-flex;align-items:center;gap:8px;box-shadow:var(--sh2);transition:transform .15s,box-shadow .15s}
|
||
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(233,30,99,.28)}
|
||
.hero-progress{flex:1;min-width:200px;max-width:280px}
|
||
.hp-label{font-size:.7rem;font-weight:700;color:var(--pri2);text-transform:uppercase;letter-spacing:.06em;margin-bottom:4px;display:block}
|
||
.hp-bar{height:8px;background:rgba(233,30,99,.12);border-radius:6px;overflow:hidden}
|
||
.hp-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:6px;width:0%;transition:width .4s}
|
||
.hp-text{font-size:.72rem;color:var(--muted);margin-top:3px;display:block}
|
||
|
||
/* PARA SELECTOR */
|
||
.psel{margin-bottom:24px}
|
||
.psel-title{font-size:.72rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:10px}
|
||
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:10px}
|
||
.psel-card{background:var(--card);border:1.5px solid var(--border);border-radius:13px;padding:14px;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s;text-align:left;position:relative}
|
||
.psel-card:hover{transform:translateY(-3px);box-shadow:var(--sh2);border-color:var(--pri)}
|
||
.psel-card.active{border-color:var(--pri);background:linear-gradient(135deg,var(--pri-soft),var(--card));box-shadow:var(--sh2)}
|
||
.psel-card.active::after{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:13px 13px 0 0}
|
||
.psel-num{font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;color:var(--pri);text-transform:uppercase;letter-spacing:.08em;margin-bottom:5px}
|
||
.psel-name{font-size:.88rem;font-weight:700;color:var(--text);line-height:1.3;margin-bottom:8px}
|
||
.psel-prog{height:4px;background:rgba(233,30,99,.10);border-radius:3px;overflow:hidden}
|
||
.psel-prog-fill{height:100%;background:var(--pri);width:0%;transition:width .4s}
|
||
.psel-card.final{background:linear-gradient(135deg,#fff5e1,#fce7f3)}
|
||
.dark .psel-card.final{background:linear-gradient(135deg,#3a2818,#4a1a3a)}
|
||
.psel-card.final .psel-num{color:var(--warn)}
|
||
|
||
/* SECTION COLORS */
|
||
.sec[id="sec-p7"] { --sec-acc:#f43f5e; --sec-acc-d:#be123c; --sec-acc-soft:#ffe4e6; }
|
||
.sec[id="sec-p8"] { --sec-acc:#06b6d4; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
|
||
.sec[id="sec-p9"] { --sec-acc:#d97706; --sec-acc-d:#b45309; --sec-acc-soft:#fef3c7; }
|
||
.sec[id="sec-p10"] { --sec-acc:#6366f1; --sec-acc-d:#4338ca; --sec-acc-soft:#e0e7ff; }
|
||
.sec[id="sec-p11"] { --sec-acc:#059669; --sec-acc-d:#047857; --sec-acc-soft:#d1fae5; }
|
||
.sec[id="sec-p12"] { --sec-acc:#a21caf; --sec-acc-d:#86198f; --sec-acc-soft:#fae8ff; }
|
||
.sec[id="sec-final2"] { --sec-acc:#d97706; --sec-acc-d:#b45309; --sec-acc-soft:#fef3c7; }
|
||
|
||
/* SECTIONS */
|
||
.sec{display:none;position:relative;animation:fadeIn .35s ease}
|
||
.sec.active{display:block}
|
||
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
|
||
.sec::before{content:attr(data-watermark);position:absolute;right:-20px;top:10%;font-family:'Unbounded',sans-serif;font-size:clamp(6rem,18vw,14rem);font-weight:900;color:transparent;-webkit-text-stroke:1.5px var(--sec-acc-soft,var(--pri-soft));line-height:1;pointer-events:none;user-select:none;z-index:0;opacity:.35}
|
||
.sec-header{margin-bottom:22px;padding-bottom:14px;border-bottom:2px solid var(--sec-acc-soft,var(--pri-soft));position:relative;z-index:1}
|
||
.sec-num{display:inline-block;padding:4px 10px;background:linear-gradient(135deg,var(--sec-acc,var(--pri)),var(--sec-acc-d,var(--pri2)));color:#fff;border-radius:7px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;margin-bottom:8px}
|
||
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.7rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));letter-spacing:-.01em;line-height:1.25}
|
||
|
||
/* CARDS */
|
||
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:18px 20px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04),0 8px 24px rgba(233,30,99,.06);position:relative;z-index:1;transition:transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s}
|
||
.card:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(0,0,0,.06),0 16px 36px rgba(233,30,99,.12)}
|
||
.card-header{display:flex;align-items:center;gap:10px;margin-bottom:12px;padding-bottom:10px;border-bottom:1px dashed var(--border)}
|
||
.card-icon{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff;outline:2px solid var(--sec-acc-soft,transparent);outline-offset:1px}
|
||
.card-icon.repeat{background:#0ea5e9}
|
||
.card-icon.theory{background:#8b5cf6}
|
||
.card-icon.algo{background:#f59e0b}
|
||
.card-icon.rule{background:#ec4899}
|
||
.card-icon.example{background:#10b981}
|
||
.card-icon.oral{background:#06b6d4}
|
||
.card-icon.class{background:#3b82f6}
|
||
.card-icon.home{background:#f97316}
|
||
.card-icon.prev{background:#6366f1}
|
||
.card-icon .ic{width:18px;height:18px}
|
||
.card-title{font-family:'Unbounded',sans-serif;font-size:.82rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);flex:1}
|
||
.card-num{font-size:.74rem;font-weight:700;color:var(--muted);background:var(--sec-acc-soft,var(--pri-soft));padding:3px 7px;border-radius:5px}
|
||
.card-body{font-size:.95rem;line-height:1.65}
|
||
.card-body p{margin-bottom:10px}
|
||
.card-body p:last-child{margin-bottom:0}
|
||
.card-body b{color:var(--sec-acc-d,var(--pri2));font-weight:700}
|
||
.card-body ul,.card-body ol{padding-left:22px;margin:8px 0}
|
||
.card-body li{margin-bottom:4px}
|
||
.formula-box{background:var(--sec-acc-soft,var(--pri-soft));border-left:4px solid var(--sec-acc,var(--pri));border-radius:8px;padding:12px 16px;margin:10px 0;font-size:1.05rem}
|
||
.def-box{background:linear-gradient(135deg,var(--acc-soft),var(--card));border:1.5px solid var(--acc);border-radius:11px;padding:14px 16px;margin:12px 0}
|
||
.def-box-title{font-size:.78rem;font-weight:800;color:var(--acc2);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px;font-family:'Unbounded',sans-serif}
|
||
.note-warn{background:var(--warn-bg);border-left:4px solid var(--warn);border-radius:7px;padding:10px 14px;font-size:.9rem;margin:10px 0}
|
||
.dark .note-warn{background:rgba(245,158,11,.15);color:#fef3c7}
|
||
|
||
/* WIDGETS */
|
||
.wg{background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)));border:1.5px solid var(--sec-acc,var(--pri));border-radius:14px;padding:18px 20px;margin-bottom:18px;box-shadow:var(--sh2);position:relative;z-index:1;transition:box-shadow .25s}
|
||
.wg:hover{box-shadow:0 4px 12px rgba(0,0,0,.08),0 16px 40px rgba(233,30,99,.18)}
|
||
.wg-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}
|
||
.wg-badge{padding:4px 9px;background:var(--sec-acc,var(--pri));color:#fff;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
|
||
.wg-title{font-family:'Unbounded',sans-serif;font-size:1.05rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));flex:1}
|
||
.wg-help{font-size:.78rem;color:var(--muted);font-style:italic;margin-bottom:10px;line-height:1.5}
|
||
|
||
.btn{padding:8px 16px;border-radius:8px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:600;font-size:.88rem;transition:background .15s,border-color .15s,transform .1s}
|
||
.btn:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
|
||
.btn:active{transform:scale(.96)}
|
||
.btn.primary{background:var(--sec-acc,var(--pri));color:#fff;border-color:var(--sec-acc,var(--pri))}
|
||
.btn.primary:hover{background:var(--sec-acc-d,var(--pri2));border-color:var(--sec-acc-d,var(--pri2))}
|
||
.btn.acc{background:var(--acc);color:#fff;border-color:var(--acc)}
|
||
.btn.ok{background:var(--ok);color:#fff;border-color:var(--ok)}
|
||
.btn.small{padding:5px 11px;font-size:.78rem}
|
||
|
||
.inp{padding:7px 12px;border-radius:8px;background:var(--card);border:1.5px solid var(--border);font-size:.92rem;color:var(--text);font-family:'JetBrains Mono',monospace;width:auto;min-width:60px}
|
||
.inp:focus{outline:none;border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
|
||
.inp.num{width:100px;text-align:center}
|
||
.slider{appearance:none;-webkit-appearance:none;height:6px;background:rgba(233,30,99,.18);border-radius:5px;width:100%;outline:none}
|
||
.slider::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;width:18px;height:18px;background:var(--sec-acc,var(--pri));border-radius:50%;cursor:pointer;box-shadow:0 0 0 3px rgba(233,30,99,.25),0 2px 5px rgba(0,0,0,.18)}
|
||
.slider::-moz-range-thumb{width:18px;height:18px;background:var(--sec-acc,var(--pri));border-radius:50%;cursor:pointer;border:none}
|
||
.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:10px}
|
||
.row-c{display:flex;gap:10px;align-items:center;justify-content:center;flex-wrap:wrap;margin-bottom:10px}
|
||
.lab{font-size:.85rem;font-weight:600;color:var(--text);margin-right:4px}
|
||
.lab-mono{font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--sec-acc-d,var(--pri2))}
|
||
.chip{display:inline-flex;align-items:center;gap:5px;padding:5px 10px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:7px;font-size:.84rem;font-weight:600;color:var(--sec-acc-d,var(--pri2))}
|
||
.chip.acc{background:var(--acc-soft);color:var(--acc2)}
|
||
.chip.ok{background:var(--ok-bg);color:#065f46}
|
||
.chip.fail{background:var(--fail-bg);color:#7f1d1d}
|
||
.feedback{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none}
|
||
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
|
||
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
|
||
|
||
/* DRAG-DROP */
|
||
.dz{min-height:60px;padding:12px;border:2px dashed var(--border);border-radius:10px;background:var(--card);display:flex;flex-wrap:wrap;gap:6px;align-content:flex-start;transition:border-color .15s,background .15s}
|
||
.dz.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
|
||
.dz-label{font-size:.78rem;font-weight:700;color:var(--muted);margin-bottom:6px;text-transform:uppercase;letter-spacing:.06em}
|
||
.drag-item{padding:6px 12px;background:linear-gradient(135deg,var(--acc),var(--acc2));color:#fff;border-radius:8px;font-weight:600;font-size:.88rem;cursor:grab;user-select:none;font-family:'JetBrains Mono',monospace;box-shadow:var(--sh);transition:transform .12s}
|
||
.drag-item:hover{transform:translateY(-1px)}
|
||
.drag-item:active{cursor:grabbing}
|
||
.drag-item.dragging{opacity:.5}
|
||
.drag-item.selected{outline:3px solid #FFD166;outline-offset:2px}
|
||
|
||
/* SIDEBAR */
|
||
.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)}
|
||
.sidecard-row{margin-bottom:8px;font-size:.86rem;line-height:1.6}
|
||
.sidecard-row b{color:var(--pri);font-weight:700}
|
||
@media(max-width:980px){.col-side{position:static;max-height:none}}
|
||
|
||
/* ACHIEVEMENT POPUP */
|
||
.ach-popup{position:fixed;top:18px;right:18px;background:linear-gradient(135deg,#fcd34d,#f59e0b);color:#451a03;padding:13px 18px;border-radius:11px;font-weight:700;font-size:.9rem;font-family:'Unbounded',sans-serif;box-shadow:0 8px 32px rgba(245,158,11,.4);z-index:1000;display:none;align-items:center;gap:10px;animation:slideIn .35s ease}
|
||
.ach-popup.show{display:flex}
|
||
@keyframes slideIn{from{transform:translateX(110%);opacity:0}to{transform:none;opacity:1}}
|
||
|
||
.spoiler{margin:10px 0;border:1px dashed var(--sec-acc,var(--pri));border-radius:8px;overflow:hidden}
|
||
.spoiler summary{padding:8px 14px;background:var(--sec-acc-soft,var(--pri-soft));font-weight:700;cursor:pointer;font-size:.88rem;color:var(--sec-acc-d,var(--pri2));list-style:none;display:flex;align-items:center;gap:8px}
|
||
.spoiler summary::-webkit-details-marker{display:none}
|
||
.spoiler summary::before{content:'+';font-size:1.2rem;font-weight:900;color:var(--sec-acc,var(--pri));width:18px}
|
||
.spoiler[open] summary::before{content:'−'}
|
||
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
|
||
|
||
.sec-nav{display:flex;gap:10px;margin-top:24px;padding-top:20px;border-top:1px solid var(--border);justify-content:space-between;flex-wrap:wrap}
|
||
|
||
.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
|
||
|
||
/* QUIZ */
|
||
.quiz{background:var(--card);border:1.5px solid var(--border);border-radius:12px;padding:14px 16px;margin-bottom:12px}
|
||
.quiz-q{font-weight:600;margin-bottom:10px;font-size:.94rem}
|
||
.quiz-opts{display:flex;flex-wrap:wrap;gap:6px}
|
||
.quiz-opt{padding:6px 12px;border:1.5px solid var(--border);border-radius:8px;font-size:.86rem;font-weight:600;cursor:pointer;background:var(--card);transition:background .12s,border-color .12s}
|
||
.quiz-opt:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
|
||
.quiz-opt.correct{background:var(--ok-bg);border-color:var(--ok);color:#065f46}
|
||
.quiz-opt.wrong{background:var(--fail-bg);border-color:var(--fail);color:#7f1d1d}
|
||
|
||
.tbl{width:100%;border-collapse:collapse;margin:12px 0;font-size:.88rem}
|
||
.tbl th,.tbl td{padding:7px 10px;border:1px solid var(--border);text-align:center;font-family:'JetBrains Mono',monospace}
|
||
.tbl th{background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));font-weight:700}
|
||
|
||
/* SPECIFIC WIDGETS — added per § */
|
||
.live-ind{display:inline-block;margin-left:6px;font-weight:900;font-size:1.1rem}
|
||
.live-ind.ok{color:var(--ok)}
|
||
.live-ind.fail{color:var(--fail)}
|
||
|
||
/* CONSTRUCTOR uravnenia (§7) */
|
||
.uconstr-display{font-family:'JetBrains Mono',monospace;font-size:1.8rem;font-weight:800;text-align:center;padding:18px;background:var(--card);border-radius:11px;border:1px solid var(--border);margin:14px 0;color:var(--sec-acc-d,var(--pri2))}
|
||
.uconstr-type{display:inline-block;padding:6px 14px;border-radius:99px;font-size:.85rem;font-weight:700;margin-top:8px}
|
||
.uconstr-type.full{background:var(--ok-bg);color:#065f46}
|
||
.uconstr-type.incomp{background:var(--warn-bg);color:#92400e}
|
||
.uconstr-type.notq{background:var(--fail-bg);color:#7f1d1d}
|
||
|
||
/* BOOK PAGE задача */
|
||
.bookpage-svg{display:block;margin:0 auto;max-width:280px}
|
||
|
||
/* PIPELINE — пошаговый решатель */
|
||
.pipe-step{margin:8px 0;padding:10px 14px;background:var(--card);border-left:3px solid var(--sec-acc,var(--pri));border-radius:7px;font-family:'JetBrains Mono',monospace;font-size:.95rem;opacity:0;transform:translateX(-12px);transition:opacity .35s,transform .35s}
|
||
.pipe-step.show{opacity:1;transform:none}
|
||
.pipe-step b{color:var(--sec-acc-d,var(--pri2));font-family:'Inter',sans-serif;display:block;font-size:.78rem;margin-bottom:4px}
|
||
|
||
/* PARABOLA (§8) */
|
||
.parab-wrap{background:var(--card);border-radius:11px;border:1px solid var(--border);padding:8px;margin:14px 0}
|
||
|
||
/* CASES (§8) */
|
||
.case-card{background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px;text-align:center;cursor:pointer;transition:transform .15s,box-shadow .15s,border-color .15s}
|
||
.case-card:hover{transform:translateY(-2px);border-color:var(--sec-acc,var(--pri));box-shadow:var(--sh)}
|
||
.case-card.active{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));box-shadow:var(--sh2)}
|
||
.case-card h5{font-family:'Unbounded',sans-serif;font-size:.85rem;color:var(--sec-acc-d,var(--pri2));margin-bottom:4px}
|
||
|
||
/* SCORE display */
|
||
.score-display{display:flex;gap:14px;flex-wrap:wrap;align-items:center;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-bottom:12px}
|
||
.score-display b{color:var(--sec-acc-d,var(--pri2));font-size:1.15rem}
|
||
|
||
/* SLIDERS / DROP / ACTIONS */
|
||
.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:10px}
|
||
.sliders label{display:flex;flex-direction:column;gap:4px;font-size:.85rem;color:var(--muted);background:var(--card);padding:8px 10px;border-radius:8px;border:1px solid var(--border)}
|
||
.sliders label b{font-family:'JetBrains Mono',monospace;font-size:1.05rem;color:var(--sec-acc-d,var(--pri2))}
|
||
.sliders input[type="range"]{width:100%;accent-color:var(--sec-acc,var(--pri))}
|
||
.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-items{display:flex;flex-wrap:wrap;gap:6px;min-height:32px}
|
||
.drop-items .chip{cursor:pointer}
|
||
#p7s-pool .chip{cursor:pointer}
|
||
.actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
|
||
.eq-show{font-family:'JetBrains Mono',monospace}
|
||
.pipe-tabs .btn.active{background:var(--sec-acc,var(--pri));color:#fff;border-color:var(--sec-acc,var(--pri))}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header class="hdr">
|
||
<div class="hdr-row">
|
||
<div>
|
||
<h1>Алгебра 8 · Глава 2</h1>
|
||
<div class="hdr-sub">Квадратные уравнения</div>
|
||
</div>
|
||
<div class="hdr-side">
|
||
<a href="/textbook/algebra-8" class="hdr-btn" title="К Главе 1">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
|
||
Глава 1
|
||
</a>
|
||
<button id="theme-btn" class="hdr-btn" title="Сменить тему">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
|
||
<span id="theme-lab">Тёмная</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="main">
|
||
<div class="col-main">
|
||
|
||
<section class="hero">
|
||
<h2>Самый знаменитый тип уравнений</h2>
|
||
<p>Квадратные уравнения встречаются везде: от расчёта траектории брошенного камня до планировки сада. Эта глава покажет полный арсенал: <b>дискриминант</b>, <b>теорему Виета</b>, разложение на множители, решение через подстановку. После неё вы сможете решить любое квадратное уравнение.</p>
|
||
<div class="hero-row">
|
||
<button class="btn-primary" onclick="goTo('p7')">
|
||
<svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg>
|
||
Начать § 7
|
||
</button>
|
||
<div class="hero-progress">
|
||
<span class="hp-label">Прогресс по главе</span>
|
||
<div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div>
|
||
<span id="hero-hp-text" class="hp-text">0%</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="psel">
|
||
<div class="psel-title">Параграфы главы</div>
|
||
<div id="psel-grid" class="psel-grid"></div>
|
||
</section>
|
||
|
||
<section id="sec-p7" class="sec" data-watermark="ax²">
|
||
<div class="sec-header"><span class="sec-num">§ 7</span><h2 class="sec-h">Квадратные уравнения. Решение неполных квадратных уравнений</h2></div>
|
||
<div id="p7-body"></div>
|
||
</section>
|
||
|
||
<section id="sec-p8" class="sec" data-watermark="D">
|
||
<div class="sec-header"><span class="sec-num">§ 8</span><h2 class="sec-h">Формулы корней квадратного уравнения</h2></div>
|
||
<div id="p8-body"></div>
|
||
</section>
|
||
|
||
<section id="sec-p9" class="sec" data-watermark="Виета">
|
||
<div class="sec-header"><span class="sec-num">§ 9</span><h2 class="sec-h">Теорема Виета</h2></div>
|
||
<div id="p9-body"></div>
|
||
</section>
|
||
|
||
<section id="sec-p10" class="sec" data-watermark="( )( )">
|
||
<div class="sec-header"><span class="sec-num">§ 10</span><h2 class="sec-h">Квадратный трёхчлен. Разложение на множители</h2></div>
|
||
<div id="p10-body"></div>
|
||
</section>
|
||
|
||
<section id="sec-p11" class="sec" data-watermark="задачи">
|
||
<div class="sec-header"><span class="sec-num">§ 11</span><h2 class="sec-h">Решение текстовых задач с помощью квадратных уравнений</h2></div>
|
||
<div id="p11-body"></div>
|
||
</section>
|
||
|
||
<section id="sec-p12" class="sec" data-watermark="t = x²">
|
||
<div class="sec-header"><span class="sec-num">§ 12</span><h2 class="sec-h">Целые рациональные уравнения, сводящиеся к квадратным</h2></div>
|
||
<div id="p12-body"></div>
|
||
</section>
|
||
|
||
<section id="sec-final2" class="sec" data-watermark="★">
|
||
<div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#f59e0b,#ec4899)">Финал главы</span><h2 class="sec-h">Итоги. Практическая и увлекательная математика</h2></div>
|
||
<div id="final2-body"></div>
|
||
</section>
|
||
|
||
</div>
|
||
|
||
<aside class="col-side"><div id="sidebar-content"></div></aside>
|
||
</main>
|
||
|
||
<footer class="foot">Интерактивный учебник «Алгебра 8» · Глава 2 · LearnSpace · версия 1.0</footer>
|
||
|
||
<div id="ach-popup" class="ach-popup">
|
||
<svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><circle cx="12" cy="8" r="5"/><path d="M8 13l-2 8 6-4 6 4-2-8"/></svg>
|
||
<span id="ach-text">Достижение!</span>
|
||
</div>
|
||
|
||
<script>
|
||
'use strict';
|
||
|
||
/* STATE & PROGRESS */
|
||
const STATE = {
|
||
current: 'p7',
|
||
progress: { p7:0, p8:0, p9:0, p10:0, p11:0, p12:0, final2:0 },
|
||
achievements: new Map(),
|
||
xp: 0,
|
||
};
|
||
|
||
const ACH_LABELS = {
|
||
start: 'Начало главы 2!',
|
||
p7_constr: 'Конструктор уравнений',
|
||
p7_sort: 'Сортировка по типам',
|
||
p7_pipeline: 'Решил неполное по шагам',
|
||
p7_book: 'Задача про страницу',
|
||
p7_train: 'Тренажёр неполных',
|
||
p7_roots: 'Угадал есть ли корни',
|
||
p8_disc: 'Калькулятор дискриминанта',
|
||
p8_parab: 'Парабола и корни',
|
||
p8_cases: '3 случая дискриминанта',
|
||
p8_disc_train: 'Тренажёр дискриминанта',
|
||
p8_steps: 'Пошаговое решение',
|
||
p8_graph: 'Знак D по графику',
|
||
};
|
||
|
||
function loadProgress(){
|
||
try{
|
||
const s = localStorage.getItem('algebra8_ch2_progress');
|
||
if(s) Object.assign(STATE.progress, JSON.parse(s));
|
||
const a = localStorage.getItem('algebra8_ch2_achievements');
|
||
if(a){
|
||
const p = JSON.parse(a);
|
||
if(Array.isArray(p)) p.forEach(id => STATE.achievements.set(id, ACH_LABELS[id] || id));
|
||
else if(p && typeof p === 'object'){
|
||
for(const [id, t] of Object.entries(p)) STATE.achievements.set(id, (t && t !== id) ? t : (ACH_LABELS[id] || id));
|
||
}
|
||
}
|
||
const xp = localStorage.getItem('algebra8_ch2_xp');
|
||
if(xp) STATE.xp = +xp;
|
||
}catch(e){}
|
||
}
|
||
function saveProgress(){
|
||
try{
|
||
localStorage.setItem('algebra8_ch2_progress', JSON.stringify(STATE.progress));
|
||
localStorage.setItem('algebra8_ch2_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
|
||
localStorage.setItem('algebra8_ch2_xp', String(STATE.xp));
|
||
}catch(e){}
|
||
}
|
||
function bumpProgress(key, delta){
|
||
STATE.progress[key] = Math.max(0, Math.min(100, (STATE.progress[key]||0) + delta));
|
||
saveProgress();
|
||
refreshProgressUI();
|
||
}
|
||
function addXp(n, src){ STATE.xp = (STATE.xp||0) + n; saveProgress(); refreshProgressUI(); }
|
||
function refreshProgressUI(){
|
||
const total = Math.round(Object.values(STATE.progress).reduce((a,b)=>a+b,0) / 7);
|
||
const f = document.getElementById('hero-hp-fill');
|
||
if(f) f.style.width = total + '%';
|
||
const t = document.getElementById('hero-hp-text');
|
||
if(t) t.textContent = total + '% пройдено';
|
||
document.querySelectorAll('[data-prog-card]').forEach(el=>{
|
||
const k = el.dataset.progCard;
|
||
const fl = el.querySelector('.psel-prog-fill');
|
||
if(fl) fl.style.width = (STATE.progress[k]||0) + '%';
|
||
});
|
||
}
|
||
function achievement(id, text){
|
||
if(STATE.achievements.has(id)) return;
|
||
STATE.achievements.set(id, text || ACH_LABELS[id] || id);
|
||
saveProgress();
|
||
const pop = document.getElementById('ach-popup');
|
||
if(pop){
|
||
document.getElementById('ach-text').textContent = text || ACH_LABELS[id] || id;
|
||
pop.classList.add('show');
|
||
setTimeout(()=>pop.classList.remove('show'), 3300);
|
||
}
|
||
addXp(20, 'ach');
|
||
}
|
||
|
||
/* PARA SELECTOR */
|
||
const PARAS = [
|
||
{ id:'p7', num:'§ 7', name:'Квадратные уравнения', sub:'Неполные' },
|
||
{ id:'p8', num:'§ 8', name:'Формулы корней', sub:'Дискриминант' },
|
||
{ id:'p9', num:'§ 9', name:'Теорема Виета', sub:'Подбор корней' },
|
||
{ id:'p10', num:'§ 10', name:'Квадратный трёхчлен', sub:'Разложение' },
|
||
{ id:'p11', num:'§ 11', name:'Текстовые задачи', sub:'4 шага' },
|
||
{ id:'p12', num:'§ 12', name:'Сводящиеся к квадратным', sub:'Биквадратные' },
|
||
{ id:'final2', num:'★', name:'Финал главы', sub:'Итоги · Практика', final:true },
|
||
];
|
||
|
||
function buildParaSelector(){
|
||
const g = document.getElementById('psel-grid');
|
||
g.innerHTML = '';
|
||
PARAS.forEach(p=>{
|
||
const card = document.createElement('div');
|
||
card.className = 'psel-card' + (p.final ? ' final' : '');
|
||
card.dataset.id = p.id;
|
||
card.dataset.progCard = p.id;
|
||
card.innerHTML = `
|
||
<div class="psel-num">${p.num}</div>
|
||
<div class="psel-name">${p.name}</div>
|
||
<div class="psel-prog"><div class="psel-prog-fill"></div></div>`;
|
||
card.addEventListener('click', ()=>goTo(p.id));
|
||
g.appendChild(card);
|
||
});
|
||
}
|
||
|
||
const BUILT = new Set();
|
||
const BUILDERS = {
|
||
p7:()=>buildP7(), p8:()=>buildP8(),
|
||
p9:()=>buildP9stub(), p10:()=>buildP10stub(),
|
||
p11:()=>buildP11stub(), p12:()=>buildP12stub(),
|
||
final2:()=>buildFinal2stub(),
|
||
};
|
||
function ensureBuilt(id){
|
||
if(BUILT.has(id)) return;
|
||
const fn = BUILDERS[id];
|
||
if(fn){ fn(); BUILT.add(id); }
|
||
}
|
||
function goTo(id){
|
||
STATE.current = id;
|
||
ensureBuilt(id);
|
||
document.querySelectorAll('.sec').forEach(s=>s.classList.remove('active'));
|
||
const el = document.getElementById('sec-' + id);
|
||
if(el) el.classList.add('active');
|
||
document.querySelectorAll('.psel-card').forEach(c=>c.classList.toggle('active', c.dataset.id === id));
|
||
buildSidebar(id);
|
||
window.scrollTo({top:0, behavior:'smooth'});
|
||
if((STATE.progress[id]||0) < 10) bumpProgress(id, 10);
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(el), 0);
|
||
}
|
||
|
||
/* SIDEBAR */
|
||
const SIDEBARS = {
|
||
p7: { title:'Шпаргалка § 7', rows:[
|
||
['$ax^2+bx+c=0$','квадратное, $a \\neq 0$'],
|
||
['$ax^2+bx=0$','неполное: $x(ax+b)=0$'],
|
||
['$ax^2+c=0$','неполное: $x^2 = -c/a$'],
|
||
['$ax^2=0$','неполное: $x=0$'],
|
||
['Свойство','$ab=0 \\Leftrightarrow a=0$ или $b=0$'],
|
||
]},
|
||
p8: { title:'Шпаргалка § 8', rows:[
|
||
['$D = b^2 - 4ac$','дискриминант'],
|
||
['$D > 0$','два корня: $x_{1,2} = \\dfrac{-b \\pm \\sqrt{D}}{2a}$'],
|
||
['$D = 0$','один корень: $x = \\dfrac{-b}{2a}$'],
|
||
['$D < 0$','корней нет'],
|
||
]},
|
||
p9: { title:'§ 9 — скоро', rows:[['Теорема Виета','будет в Wave 2']]},
|
||
p10:{ title:'§ 10 — скоро', rows:[['Разложение','будет в Wave 2']]},
|
||
p11:{ title:'§ 11 — скоро', rows:[['Текстовые задачи','будет в Wave 3']]},
|
||
p12:{ title:'§ 12 — скоро', rows:[['Сводящиеся к квадратным','будет в Wave 3']]},
|
||
final2:{ title:'Финал', rows:[['Итоги главы','будет в Wave 4']]},
|
||
};
|
||
function buildSidebar(id){
|
||
const box = document.getElementById('sidebar-content');
|
||
const sb = SIDEBARS[id] || SIDEBARS.p7;
|
||
let html = `<div class="sidecard"><h4>${sb.title}</h4>`;
|
||
sb.rows.forEach(([k,v])=>{
|
||
html += `<div class="sidecard-row"><b>${k}</b> ${v ? '— ' + v : ''}</div>`;
|
||
});
|
||
html += '</div>';
|
||
if(STATE.achievements.size > 0){
|
||
html += `<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">${STATE.achievements.size}</span></h4>`;
|
||
[...STATE.achievements.values()].slice(-4).forEach(text=>{
|
||
html += `<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">✓ ${text}</div>`;
|
||
});
|
||
html += '</div>';
|
||
}
|
||
box.innerHTML = html;
|
||
if(window.renderMathInElement) try{ renderMath(box); }catch(e){}
|
||
}
|
||
|
||
/* THEME */
|
||
function initTheme(){
|
||
const t = localStorage.getItem('algebra8_ch2_theme') || 'light';
|
||
if(t === 'dark') document.documentElement.classList.add('dark');
|
||
document.getElementById('theme-lab').textContent = t === 'dark' ? 'Светлая' : 'Тёмная';
|
||
document.getElementById('theme-btn').addEventListener('click', ()=>{
|
||
document.documentElement.classList.toggle('dark');
|
||
const dark = document.documentElement.classList.contains('dark');
|
||
localStorage.setItem('algebra8_ch2_theme', dark ? 'dark' : 'light');
|
||
document.getElementById('theme-lab').textContent = dark ? 'Светлая' : 'Тёмная';
|
||
});
|
||
}
|
||
|
||
/* HELPERS */
|
||
function $(sel, root){ return (root||document).querySelector(sel); }
|
||
function $$(sel, root){ return [...(root||document).querySelectorAll(sel)]; }
|
||
function el(tag, attrs, html){
|
||
const e = document.createElement(tag);
|
||
if(attrs) Object.entries(attrs).forEach(([k,v])=>{
|
||
if(k === 'class') e.className = v;
|
||
else if(k === 'style') e.style.cssText = v;
|
||
else if(k.startsWith('on') && typeof v === 'function') e.addEventListener(k.slice(2), v);
|
||
else e.setAttribute(k, v);
|
||
});
|
||
if(html != null) e.innerHTML = html;
|
||
return e;
|
||
}
|
||
function renderMath(root){
|
||
if(window.renderMathInElement){
|
||
try{ renderMathInElement(root, {delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false}); }catch(e){}
|
||
}
|
||
}
|
||
function feedback(elm, ok, text){
|
||
elm.className = 'feedback ' + (ok ? 'ok' : 'fail');
|
||
elm.innerHTML = text || (ok ? '✓ Верно!' : '✗ Неверно');
|
||
}
|
||
function sleep(ms){ return new Promise(r => setTimeout(r, ms)); }
|
||
function fmt(n){ if(!isFinite(n)) return '?'; if(Number.isInteger(n)) return String(n); return Math.abs(n - Math.round(n)) < 1e-9 ? String(Math.round(n)) : (+n.toFixed(4)).toString(); }
|
||
|
||
const ICONS = {
|
||
repeat: '<svg class="ic" viewBox="0 0 24 24"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',
|
||
theory: '<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>',
|
||
algo: '<svg class="ic" viewBox="0 0 24 24"><polyline points="17 11 21 7 17 3"/><line x1="21" y1="7" x2="9" y2="7"/><polyline points="7 13 3 17 7 21"/><line x1="3" y1="17" x2="15" y2="17"/></svg>',
|
||
rule: '<svg class="ic" viewBox="0 0 24 24"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>',
|
||
example: '<svg class="ic" viewBox="0 0 24 24"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 13c1 1 2 2 2 4h4c0-2 1-3 2-4a7 7 0 0 0-4-13z"/></svg>',
|
||
oral: '<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
|
||
class: '<svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="14" rx="1"/><line x1="3" y1="21" x2="21" y2="21"/><polyline points="7 14 10 11 13 14 17 10"/></svg>',
|
||
home: '<svg class="ic" viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>',
|
||
};
|
||
function makeCard(kind, title, num, body){
|
||
const labels = {repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно',class:'Класс',home:'Домашка'};
|
||
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] ? '· ' + title : ''}</div>
|
||
${num ? `<div class="card-num">${num}</div>` : ''}
|
||
</div>
|
||
<div class="card-body">${body}</div>
|
||
</div>`;
|
||
}
|
||
function widget(title, badge, helpText, body){
|
||
return `<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">${badge||'INTERACT'}</span><div class="wg-title">${title}</div></div>
|
||
${helpText ? `<div class="wg-help">${helpText}</div>` : ''}
|
||
${body}
|
||
</div>`;
|
||
}
|
||
function secNav(prev, next){
|
||
const NAMES = {p7:'§7',p8:'§8',p9:'§9',p10:'§10',p11:'§11',p12:'§12',final2:'Финал'};
|
||
let h = '<div class="sec-nav">';
|
||
h += prev ? `<button class="btn" onclick="goTo('${prev}')"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> ${NAMES[prev]}</button>` : '<span></span>';
|
||
h += next ? `<button class="btn primary" onclick="goTo('${next}')">${NAMES[next]} <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>` : '<span></span>';
|
||
h += '</div>';
|
||
return h;
|
||
}
|
||
|
||
/* CONFETTI (simplified) */
|
||
let _confettiCanvas = null, _confettiParticles = [], _confettiRaf = null;
|
||
function confetti(){
|
||
if(!_confettiCanvas){
|
||
_confettiCanvas = document.createElement('canvas');
|
||
_confettiCanvas.id = 'confetti-canvas';
|
||
_confettiCanvas.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9999';
|
||
document.body.appendChild(_confettiCanvas);
|
||
}
|
||
const c = _confettiCanvas;
|
||
c.width = window.innerWidth; c.height = window.innerHeight;
|
||
const ctx = c.getContext('2d');
|
||
const colors = ['#e91e63','#03a9f4','#f59e0b','#10b981','#a855f7'];
|
||
for(let i = 0; i < 80; i++){
|
||
_confettiParticles.push({
|
||
x: window.innerWidth/2 + (Math.random()-0.5)*200,
|
||
y: window.innerHeight/2,
|
||
vx: (Math.random()-0.5)*14,
|
||
vy: -10 - Math.random()*10,
|
||
g: 0.4, life: 100, color: colors[i%colors.length], r: 4+Math.random()*4, rot: 0, vRot: (Math.random()-0.5)*0.3,
|
||
});
|
||
}
|
||
if(_confettiRaf) cancelAnimationFrame(_confettiRaf);
|
||
function frame(){
|
||
ctx.clearRect(0,0,c.width,c.height);
|
||
_confettiParticles = _confettiParticles.filter(p=>{
|
||
p.x += p.vx; p.y += p.vy; p.vy += p.g; p.life--; p.rot += p.vRot;
|
||
ctx.save(); ctx.translate(p.x, p.y); ctx.rotate(p.rot);
|
||
ctx.fillStyle = p.color;
|
||
ctx.fillRect(-p.r, -p.r/2, p.r*2, p.r);
|
||
ctx.restore();
|
||
return p.life > 0 && p.y < c.height + 50;
|
||
});
|
||
if(_confettiParticles.length > 0) _confettiRaf = requestAnimationFrame(frame);
|
||
else { ctx.clearRect(0,0,c.width,c.height); _confettiRaf = null; }
|
||
}
|
||
frame();
|
||
}
|
||
|
||
/* INIT */
|
||
function init(){
|
||
loadProgress();
|
||
initTheme();
|
||
buildParaSelector();
|
||
refreshProgressUI();
|
||
goTo('p7');
|
||
setTimeout(()=>achievement('start','Начало главы 2!'), 600);
|
||
}
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
|
||
/* STUBS for paragraphs not yet implemented */
|
||
function buildP9stub(){ document.getElementById('p9-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 9 — Теорема Виета</b><br><br>Этот параграф будет реализован в следующей волне обновлений.<br><br><small>Wave 2: § 9 + § 10</small></p></div></div>${secNav('p8','p10')}`; }
|
||
function buildP10stub(){ document.getElementById('p10-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 10 — Квадратный трёхчлен. Разложение на множители</b><br><br>Скоро в Wave 2.</p></div></div>${secNav('p9','p11')}`; }
|
||
function buildP11stub(){ document.getElementById('p11-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 11 — Текстовые задачи</b><br><br>Скоро в Wave 3.</p></div></div>${secNav('p10','p12')}`; }
|
||
function buildP12stub(){ document.getElementById('p12-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>§ 12 — Сводящиеся к квадратным</b><br><br>Скоро в Wave 3.</p></div></div>${secNav('p11','final2')}`; }
|
||
function buildFinal2stub(){ document.getElementById('final2-body').innerHTML = `<div class="card"><div class="card-body"><p style="text-align:center;padding:20px"><b>Финал главы</b><br><br>Итоговая самооценка, практика, увлекательная математика и финальный босс — в Wave 4.</p></div></div>${secNav('p12',null)}`; }
|
||
</script>
|
||
|
||
<script>
|
||
/* ============================================================
|
||
§ 7 — КВАДРАТНЫЕ УРАВНЕНИЯ. НЕПОЛНЫЕ
|
||
============================================================ */
|
||
function buildP7(){
|
||
const box = document.getElementById('p7-body');
|
||
let html = '';
|
||
|
||
/* Card: повторение */
|
||
html += makeCard('repeat','Повторение',null, `
|
||
<ul style="margin-left:18px;line-height:1.7">
|
||
<li><b>Линейное уравнение</b> $ax+b=0$: при $a \\neq 0$ один корень $x=-b/a$.</li>
|
||
<li><b>Раскрытие скобок:</b> $(a+b)^2 = a^2+2ab+b^2$, $(a-b)^2=a^2-2ab+b^2$.</li>
|
||
<li><b>Свойство нуля:</b> произведение равно нулю $\\Leftrightarrow$ хотя бы один множитель равен нулю.</li>
|
||
<li><b>Квадратный корень:</b> $\\sqrt{a}$ определён только для $a \\geq 0$.</li>
|
||
</ul>`);
|
||
|
||
/* Card: теория */
|
||
html += makeCard('theory','Что такое квадратное уравнение','7.1',`
|
||
<p style="margin-bottom:8px"><b>Определение.</b> Уравнение вида $ax^2 + bx + c = 0$, где $a \\neq 0$, называется <b>квадратным</b>. Числа $a$, $b$, $c$ — <b>коэффициенты</b>:</p>
|
||
<ul style="margin-left:18px;line-height:1.7">
|
||
<li>$a$ — старший (первый) коэффициент;</li>
|
||
<li>$b$ — второй коэффициент;</li>
|
||
<li>$c$ — свободный член.</li>
|
||
</ul>
|
||
<p style="margin-top:8px">Если $a=1$, уравнение называют <b>приведённым</b>. Если хотя бы один из коэффициентов $b$ или $c$ равен нулю — <b>неполным</b>.</p>`);
|
||
|
||
/* Card: правило */
|
||
html += makeCard('rule','Три типа неполных уравнений','7.2',`
|
||
<table class="tbl" style="width:100%;border-collapse:collapse;font-size:.95rem">
|
||
<thead><tr style="background:var(--sec-acc-soft,var(--pri-soft))"><th style="padding:8px;text-align:left">Вид</th><th style="padding:8px;text-align:left">Метод</th><th style="padding:8px;text-align:left">Корни</th></tr></thead>
|
||
<tbody>
|
||
<tr><td style="padding:8px;border-bottom:1px solid var(--border)">$ax^2 + bx = 0$</td><td style="padding:8px;border-bottom:1px solid var(--border)">$x(ax+b)=0$</td><td style="padding:8px;border-bottom:1px solid var(--border)">$x_1=0,\\ x_2=-b/a$</td></tr>
|
||
<tr><td style="padding:8px;border-bottom:1px solid var(--border)">$ax^2 + c = 0$</td><td style="padding:8px;border-bottom:1px solid var(--border)">$x^2 = -c/a$</td><td style="padding:8px;border-bottom:1px solid var(--border)">$x = \\pm\\sqrt{-c/a}$ или нет</td></tr>
|
||
<tr><td style="padding:8px">$ax^2 = 0$</td><td style="padding:8px">очевидно</td><td style="padding:8px">$x = 0$</td></tr>
|
||
</tbody>
|
||
</table>`);
|
||
|
||
/* Card: алгоритм */
|
||
html += makeCard('algo','Универсальная стратегия',null,`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>Привести уравнение к виду $ax^2+bx+c=0$.</li>
|
||
<li>Определить, какие коэффициенты равны нулю.</li>
|
||
<li>Выбрать метод по таблице выше.</li>
|
||
<li>Проверить ответ подстановкой.</li>
|
||
</ol>`);
|
||
|
||
/* Card: пример */
|
||
html += makeCard('example','Решим вместе','7.3',`
|
||
<p><b>Пример 1.</b> $3x^2 - 12x = 0$. Выносим $x$ за скобки: $x(3x - 12) = 0$. Откуда $x_1 = 0$ или $3x-12 = 0 \\Rightarrow x_2 = 4$. Ответ: $\\{0;\\ 4\\}$.</p>
|
||
<p style="margin-top:6px"><b>Пример 2.</b> $2x^2 - 18 = 0$. Получаем $x^2 = 9 \\Rightarrow x = \\pm 3$.</p>
|
||
<p style="margin-top:6px"><b>Пример 3.</b> $5x^2 + 20 = 0 \\Rightarrow x^2 = -4$. Корней нет.</p>`);
|
||
|
||
/* ===== INTERACTIVE 1: Конструктор уравнения ===== */
|
||
html += widget('Конструктор квадратного уравнения','INTERACT 1','Перетягивайте слайдеры $a$, $b$, $c$. Смотрите, как уравнение оживает и меняет тип.', `
|
||
<div class="sliders">
|
||
<label>$a$ = <b id="p7c-a-val">1</b><input type="range" min="-5" max="5" step="1" value="1" id="p7c-a"></label>
|
||
<label>$b$ = <b id="p7c-b-val">0</b><input type="range" min="-9" max="9" step="1" value="0" id="p7c-b"></label>
|
||
<label>$c$ = <b id="p7c-c-val">-9</b><input type="range" min="-12" max="12" step="1" value="-9" id="p7c-c"></label>
|
||
</div>
|
||
<div class="eq-show" id="p7c-eq" style="text-align:center;font-size:1.4rem;margin:10px 0;padding:14px;background:var(--sec-acc-soft);border-radius:10px"></div>
|
||
<div id="p7c-type" style="text-align:center;font-weight:600;color:var(--sec-acc-d);margin-bottom:6px"></div>
|
||
<div id="p7c-roots" style="text-align:center;margin-bottom:6px"></div>`);
|
||
|
||
/* ===== INTERACTIVE 2: Drag-сортировка ===== */
|
||
html += widget('Сортировка уравнений по типу','INTERACT 2','Кликом отправьте каждое уравнение в нужный ящик. Серый — лишнее (не квадратное).',`
|
||
<div id="p7s-pool" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px"></div>
|
||
<div class="drop-row" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px">
|
||
<div class="drop-box" data-type="full"><h5>Полное</h5><div class="drop-items" data-cat="full"></div></div>
|
||
<div class="drop-box" data-type="incomplete"><h5>Неполное</h5><div class="drop-items" data-cat="incomplete"></div></div>
|
||
<div class="drop-box" data-type="notquad"><h5>Не квадратное</h5><div class="drop-items" data-cat="notquad"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p7s-check">Проверить</button><button class="btn" id="p7s-reset">Сначала</button></div>
|
||
<div class="feedback" id="p7s-fb" style="display:none"></div>`);
|
||
|
||
/* ===== INTERACTIVE 3: Пошаговый решатель ===== */
|
||
html += widget('Пошаговый решатель неполных','INTERACT 3','Выберите тип, нажимайте «Дальше» и наблюдайте за решением пошагово.',`
|
||
<div class="pipe-tabs" style="display:flex;gap:6px;margin-bottom:10px">
|
||
<button class="btn small p7p-tab active" data-tp="bc0">$ax^2+bx=0$</button>
|
||
<button class="btn small p7p-tab" data-tp="ac0">$ax^2+c=0$</button>
|
||
</div>
|
||
<div id="p7p-stage" style="padding:14px;background:var(--card-soft);border-radius:10px;min-height:160px;font-size:1.05rem"></div>
|
||
<div class="actions" style="margin-top:10px"><button class="btn primary" id="p7p-next">Дальше</button><button class="btn" id="p7p-reset">Сначала</button></div>`);
|
||
|
||
/* ===== INTERACTIVE 4: Задача про страницу книги ===== */
|
||
html += widget('Задача про страницу книги','INTERACT 4','Длина страницы на 4 см больше ширины, а площадь — 165 см². Найдите ширину.',`
|
||
<p style="margin-bottom:10px">Пусть ширина $= x$, тогда длина $= x+4$. Уравнение: $x(x+4) = 165 \\Rightarrow x^2 + 4x - 165 = 0$.</p>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<label>Ваш ответ (ширина, см): <input type="number" id="p7b-inp" style="width:80px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
|
||
<button class="btn primary" id="p7b-check">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p7b-fb" style="display:none;margin-top:10px"></div>
|
||
<svg id="p7b-svg" viewBox="0 0 320 200" style="width:100%;max-width:320px;margin-top:12px;display:block">
|
||
<rect x="40" y="40" width="240" height="120" fill="var(--sec-acc-soft)" stroke="var(--sec-acc)" stroke-width="2"/>
|
||
<text x="160" y="32" text-anchor="middle" font-size="14" fill="var(--sec-acc-d)">длина = x + 4</text>
|
||
<text x="22" y="105" font-size="14" fill="var(--sec-acc-d)" transform="rotate(-90 22 105)">x</text>
|
||
<text x="160" y="108" text-anchor="middle" font-size="20" fill="var(--ink)" id="p7b-area">S = 165</text>
|
||
</svg>`);
|
||
|
||
/* ===== INTERACTIVE 5: Тренажёр 10 неполных ===== */
|
||
html += widget('Тренажёр: 10 неполных','INTERACT 5','Решайте устно. Ответ — большее значение корня (через запятую: если корней два — оба, по возрастанию).',`
|
||
<div class="score-display"><span>Задача <b id="p7t-i">1</b> / 10</span><span>Очки: <b id="p7t-score">0</b></span><span>Время: <b id="p7t-time">0</b> c</span></div>
|
||
<div id="p7t-task" style="font-size:1.4rem;text-align:center;padding:18px;background:var(--sec-acc-soft);border-radius:10px;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap">
|
||
<input type="text" id="p7t-inp" placeholder="например 0; 4 или -3; 3 или нет" style="width:240px;padding:8px;border:1.5px solid var(--border);border-radius:8px">
|
||
<button class="btn primary" id="p7t-go">Ответ</button>
|
||
<button class="btn" id="p7t-skip">Пропустить</button>
|
||
</div>
|
||
<div class="feedback" id="p7t-fb" style="display:none;margin-top:10px"></div>
|
||
<button class="btn primary" id="p7t-start" style="margin-top:10px">Начать</button>`);
|
||
|
||
/* ===== INTERACTIVE 6: Есть ли корни у ax²+c=0 ===== */
|
||
html += widget('«Имеет ли корни?» — $ax^2 + c = 0$','INTERACT 6','Быстрый тренажёр на знаки. Нужно сообразить, имеет ли уравнение корни.',`
|
||
<div class="score-display"><span>Раунд <b id="p7r-i">1</b> / 8</span><span>Правильно: <b id="p7r-score">0</b></span></div>
|
||
<div id="p7r-task" style="font-size:1.5rem;text-align:center;padding:18px;background:var(--sec-acc-soft);border-radius:10px;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;justify-content:center">
|
||
<button class="btn primary" id="p7r-yes">Имеет корни</button>
|
||
<button class="btn" id="p7r-no">Корней нет</button>
|
||
</div>
|
||
<div class="feedback" id="p7r-fb" style="display:none;margin-top:10px"></div>
|
||
<button class="btn primary" id="p7r-start" style="margin-top:10px">Начать</button>`);
|
||
|
||
/* ===== Устно / Класс / Дом ===== */
|
||
html += makeCard('oral','Устные вопросы',null,`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>Какое уравнение называется квадратным? Какое — неполным?</li>
|
||
<li>Может ли коэффициент $a$ быть равен нулю? Почему?</li>
|
||
<li>Сколько корней может быть у уравнения $ax^2+c=0$?</li>
|
||
<li>Назовите коэффициенты уравнения $5x^2 - 2x + 7 = 0$.</li>
|
||
</ol>`);
|
||
|
||
html += makeCard('class','Класс — решите в тетради',null,`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>$4x^2 - 9 = 0$</li>
|
||
<li>$3x^2 + 6x = 0$</li>
|
||
<li>$x^2 + 25 = 0$</li>
|
||
<li>$2x^2 = 50$</li>
|
||
<li>$x(x-7) = 0$</li>
|
||
</ol>`);
|
||
|
||
html += makeCard('home','Домашка',null,`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>$9x^2 - 16 = 0$</li>
|
||
<li>$5x^2 + 10x = 0$</li>
|
||
<li>$x^2 + 4 = 0$</li>
|
||
<li>Длина прямоугольника на 3 см больше ширины, а площадь равна 54 см². Найдите стороны.</li>
|
||
</ol>`);
|
||
|
||
html += secNav(null,'p8');
|
||
|
||
box.innerHTML = html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
|
||
|
||
/* ===== INIT INTERACTIVE 1 ===== */
|
||
(function initConstructor(){
|
||
const aE = document.getElementById('p7c-a'), bE = document.getElementById('p7c-b'), cE = document.getElementById('p7c-c');
|
||
const eq = document.getElementById('p7c-eq'), tp = document.getElementById('p7c-type'), rt = document.getElementById('p7c-roots');
|
||
let done = false;
|
||
function termA(a){
|
||
if(a === 0) return '';
|
||
if(a === 1) return 'x^2';
|
||
if(a === -1) return '-x^2';
|
||
return a + 'x^2';
|
||
}
|
||
function termB(b){
|
||
if(b === 0) return '';
|
||
const s = b > 0 ? ' + ' : ' - ';
|
||
const v = Math.abs(b);
|
||
return s + (v === 1 ? '' : v) + 'x';
|
||
}
|
||
function termC(c){
|
||
if(c === 0) return '';
|
||
const s = c > 0 ? ' + ' : ' - ';
|
||
return s + Math.abs(c);
|
||
}
|
||
function refresh(){
|
||
const a = +aE.value, b = +bE.value, c = +cE.value;
|
||
document.getElementById('p7c-a-val').textContent = a;
|
||
document.getElementById('p7c-b-val').textContent = b;
|
||
document.getElementById('p7c-c-val').textContent = c;
|
||
if(a === 0){ eq.innerHTML = '$' + (termB(b) || '0') + termC(c) + ' = 0$ <span style="color:var(--bad);font-size:.85rem">не квадратное!</span>'; tp.textContent = 'Не квадратное (a=0)'; rt.textContent = ''; renderMath(eq); return; }
|
||
let s = termA(a) + termB(b) + termC(c) + ' = 0';
|
||
eq.innerHTML = '$' + s + '$';
|
||
let label = '';
|
||
if(b === 0 && c === 0) label = 'Неполное: $ax^2=0$ · корень $x=0$';
|
||
else if(b === 0) label = 'Неполное: $ax^2+c=0$';
|
||
else if(c === 0) label = 'Неполное: $ax^2+bx=0$ · корни $x_1=0,\\ x_2=' + fmt(-b/a) + '$';
|
||
else label = 'Полное квадратное · решаем через дискриминант';
|
||
tp.innerHTML = label;
|
||
let rs = '';
|
||
if(b === 0 && c === 0) rs = '$x=0$';
|
||
else if(c === 0) rs = '$x_1=0,\\ x_2=' + fmt(-b/a) + '$';
|
||
else if(b === 0){
|
||
const v = -c/a;
|
||
if(v > 0){ const r = Math.sqrt(v); rs = '$x = \\pm' + fmt(r) + '$'; }
|
||
else if(v === 0) rs = '$x=0$';
|
||
else rs = 'корней нет';
|
||
} else {
|
||
const D = b*b - 4*a*c;
|
||
if(D > 0){ const r1 = (-b - Math.sqrt(D))/(2*a), r2 = (-b + Math.sqrt(D))/(2*a); rs = '$x_1=' + fmt(r1) + ',\\ x_2=' + fmt(r2) + '$'; }
|
||
else if(D === 0) rs = '$x=' + fmt(-b/(2*a)) + '$';
|
||
else rs = 'корней нет';
|
||
}
|
||
rt.innerHTML = rs;
|
||
renderMath(eq); renderMath(tp); renderMath(rt);
|
||
if(!done){ done = true; setTimeout(()=>{ achievement('p7_constr'); bumpProgress('p7', 12); }, 300); }
|
||
}
|
||
aE.addEventListener('input', refresh); bE.addEventListener('input', refresh); cE.addEventListener('input', refresh);
|
||
refresh();
|
||
})();
|
||
|
||
/* ===== INIT INTERACTIVE 2 ===== */
|
||
(function initSort(){
|
||
const items = [
|
||
{ id:1, txt:'$2x^2 + 3x - 5 = 0$', cat:'full' },
|
||
{ id:2, txt:'$x^2 - 16 = 0$', cat:'incomplete' },
|
||
{ id:3, txt:'$3x^2 + 6x = 0$', cat:'incomplete' },
|
||
{ id:4, txt:'$x + 5 = 0$', cat:'notquad' },
|
||
{ id:5, txt:'$5x^2 - 2x + 1 = 0$', cat:'full' },
|
||
{ id:6, txt:'$7x^2 = 0$', cat:'incomplete' },
|
||
{ id:7, txt:'$x^3 - x = 0$', cat:'notquad' },
|
||
{ id:8, txt:'$x^2 + x + 1 = 0$', cat:'full' },
|
||
];
|
||
const pool = document.getElementById('p7s-pool');
|
||
const cats = ['full','incomplete','notquad'];
|
||
const labels = { full:'Полное', incomplete:'Неполное', notquad:'Не квадр.' };
|
||
let placed = {};
|
||
function makeChip(it, where){
|
||
const wrap = document.createElement('div');
|
||
wrap.className = 'chip-wrap';
|
||
wrap.style.cssText = 'display:inline-flex;align-items:center;gap:4px;background:var(--sec-acc-soft);border-radius:8px;padding:3px 6px;margin:2px';
|
||
const sp = document.createElement('span');
|
||
sp.className = 'chip';
|
||
sp.style.cssText = 'background:transparent;padding:2px 4px';
|
||
sp.innerHTML = it.txt;
|
||
wrap.appendChild(sp);
|
||
if(where === 'pool'){
|
||
cats.forEach(cat=>{
|
||
const b = document.createElement('button');
|
||
b.className = 'btn small';
|
||
b.textContent = labels[cat];
|
||
b.style.cssText = 'padding:3px 7px;font-size:.7rem';
|
||
b.addEventListener('click', ()=>{ placed[it.id] = cat; renderAll(); });
|
||
wrap.appendChild(b);
|
||
});
|
||
} else {
|
||
const b = document.createElement('button');
|
||
b.className = 'btn small';
|
||
b.textContent = '×';
|
||
b.style.cssText = 'padding:2px 7px';
|
||
b.addEventListener('click', ()=>{ delete placed[it.id]; renderAll(); });
|
||
wrap.appendChild(b);
|
||
}
|
||
return wrap;
|
||
}
|
||
function render(){
|
||
pool.innerHTML = '';
|
||
items.forEach(it=>{
|
||
if(placed[it.id]) return;
|
||
pool.appendChild(makeChip(it, 'pool'));
|
||
});
|
||
cats.forEach(cat=>{
|
||
const box = document.querySelector('.drop-items[data-cat="' + cat + '"]');
|
||
box.innerHTML = '';
|
||
items.forEach(it=>{
|
||
if(placed[it.id] !== cat) return;
|
||
box.appendChild(makeChip(it, 'placed'));
|
||
});
|
||
});
|
||
if(window.renderMathInElement) renderMath(document.getElementById('p7s-pool').parentElement);
|
||
}
|
||
function renderAll(){ render(); }
|
||
document.getElementById('p7s-check').addEventListener('click', ()=>{
|
||
const total = items.length;
|
||
const placedCount = Object.keys(placed).length;
|
||
if(placedCount < total){ feedback(document.getElementById('p7s-fb'), false, '⚠ Разложите ВСЕ уравнения по ящикам.'); document.getElementById('p7s-fb').style.display='block'; return; }
|
||
let ok = 0; items.forEach(it=>{ if(placed[it.id] === it.cat) ok++; });
|
||
const fb = document.getElementById('p7s-fb');
|
||
fb.style.display = 'block';
|
||
if(ok === total){ feedback(fb, true, '✓ Идеально! Все ' + total + ' верно.'); achievement('p7_sort'); bumpProgress('p7', 14); confetti(); }
|
||
else feedback(fb, false, 'Верно ' + ok + ' из ' + total + '. Попробуйте перепроверить.');
|
||
});
|
||
document.getElementById('p7s-reset').addEventListener('click', ()=>{ placed = {}; document.getElementById('p7s-fb').style.display='none'; renderAll(); });
|
||
renderAll();
|
||
})();
|
||
|
||
/* ===== INIT INTERACTIVE 3 ===== */
|
||
(function initPipeline(){
|
||
const stages = {
|
||
bc0: [
|
||
'<b>Дано:</b> $2x^2 - 6x = 0$',
|
||
'<b>Шаг 1:</b> Вынесем $x$ за скобки: $x(2x - 6) = 0$',
|
||
'<b>Шаг 2:</b> Произведение равно нулю $\\Leftrightarrow$ один из множителей равен нулю.',
|
||
'<b>Шаг 3:</b> $x = 0$ или $2x - 6 = 0$',
|
||
'<b>Шаг 4:</b> $x_1 = 0,\\ x_2 = 3$',
|
||
'<b>Ответ:</b> $\\{0;\\ 3\\}$',
|
||
],
|
||
ac0: [
|
||
'<b>Дано:</b> $3x^2 - 27 = 0$',
|
||
'<b>Шаг 1:</b> Перенесём $-27$ вправо: $3x^2 = 27$',
|
||
'<b>Шаг 2:</b> Разделим на $3$: $x^2 = 9$',
|
||
'<b>Шаг 3:</b> Возьмём квадратный корень: $x = \\pm\\sqrt{9}$',
|
||
'<b>Шаг 4:</b> $x = \\pm 3$',
|
||
'<b>Ответ:</b> $\\{-3;\\ 3\\}$',
|
||
],
|
||
};
|
||
let mode = 'bc0', idx = 0;
|
||
const stage = document.getElementById('p7p-stage');
|
||
let solved = false;
|
||
function show(){
|
||
const arr = stages[mode];
|
||
stage.innerHTML = arr.slice(0, idx + 1).map(s => '<p style="margin:6px 0">' + s + '</p>').join('');
|
||
renderMath(stage);
|
||
if(idx >= arr.length - 1 && !solved){ solved = true; achievement('p7_pipeline'); bumpProgress('p7', 12); }
|
||
}
|
||
document.querySelectorAll('.p7p-tab').forEach(t=>{
|
||
t.addEventListener('click', ()=>{ document.querySelectorAll('.p7p-tab').forEach(x=>x.classList.remove('active')); t.classList.add('active'); mode = t.dataset.tp; idx = 0; show(); });
|
||
});
|
||
document.getElementById('p7p-next').addEventListener('click', ()=>{ if(idx < stages[mode].length - 1) idx++; show(); });
|
||
document.getElementById('p7p-reset').addEventListener('click', ()=>{ idx = 0; show(); });
|
||
show();
|
||
})();
|
||
|
||
/* ===== INIT INTERACTIVE 4 ===== */
|
||
(function initBook(){
|
||
document.getElementById('p7b-check').addEventListener('click', ()=>{
|
||
const v = +document.getElementById('p7b-inp').value;
|
||
const fb = document.getElementById('p7b-fb');
|
||
fb.style.display = 'block';
|
||
if(Math.abs(v - 11) < 1e-9){ feedback(fb, true, '✓ Верно! Ширина = 11 см, длина = 15 см. $11 \\cdot 15 = 165$.'); renderMath(fb); achievement('p7_book'); bumpProgress('p7', 14); confetti(); }
|
||
else feedback(fb, false, 'Не то. $x^2+4x-165=0$, корни $-15$ и $11$. Ширина не может быть отрицательной.');
|
||
});
|
||
})();
|
||
|
||
/* ===== INIT INTERACTIVE 5 ===== */
|
||
(function initTrain(){
|
||
function gen(){
|
||
const t = Math.floor(Math.random()*3);
|
||
if(t === 0){
|
||
const a = 1 + Math.floor(Math.random()*4);
|
||
const r2 = 1 + Math.floor(Math.random()*8);
|
||
return { eq: a + 'x^2 - ' + (a*r2) + 'x = 0', ans: [0, r2] };
|
||
}
|
||
if(t === 1){
|
||
const a = 1 + Math.floor(Math.random()*3);
|
||
const r = 1 + Math.floor(Math.random()*7);
|
||
return { eq: a + 'x^2 - ' + (a*r*r) + ' = 0', ans: [-r, r] };
|
||
}
|
||
const a = 1 + Math.floor(Math.random()*3);
|
||
const c = 1 + Math.floor(Math.random()*15);
|
||
return { eq: a + 'x^2 + ' + c + ' = 0', ans: null };
|
||
}
|
||
let cur = null, i = 1, score = 0, t0 = 0, timer = null;
|
||
function newOne(){
|
||
cur = gen();
|
||
document.getElementById('p7t-task').innerHTML = '$' + cur.eq + ' = 0$'; renderMath(document.getElementById('p7t-task'));
|
||
document.getElementById('p7t-i').textContent = i;
|
||
document.getElementById('p7t-inp').value = '';
|
||
document.getElementById('p7t-fb').style.display = 'none';
|
||
}
|
||
function parse(s){
|
||
s = s.trim().toLowerCase();
|
||
if(/нет|none/.test(s)) return null;
|
||
return s.replace(/,/g,';').split(/[;\s]+/).filter(Boolean).map(Number).sort((a,b)=>a-b);
|
||
}
|
||
function check(){
|
||
const u = parse(document.getElementById('p7t-inp').value);
|
||
const fb = document.getElementById('p7t-fb');
|
||
fb.style.display = 'block';
|
||
let ok = false;
|
||
if(cur.ans === null){ ok = u === null; }
|
||
else if(u !== null){ const a = [...cur.ans].sort((a,b)=>a-b); ok = a.length === u.length && a.every((x,k)=>x === u[k]); }
|
||
if(ok){ score++; feedback(fb, true, '✓'); } else feedback(fb, false, 'Правильно: ' + (cur.ans === null ? 'нет' : cur.ans.join('; ')));
|
||
document.getElementById('p7t-score').textContent = score;
|
||
if(i >= 10){
|
||
setTimeout(()=>{ feedback(fb, score >= 7, 'Итог: ' + score + '/10 за ' + (((Date.now() - t0)/1000)|0) + ' c'); if(score >= 7){ achievement('p7_train'); bumpProgress('p7', 16); confetti(); } clearInterval(timer); }, 500);
|
||
} else { i++; setTimeout(newOne, 700); }
|
||
}
|
||
document.getElementById('p7t-start').addEventListener('click', ()=>{ i = 1; score = 0; document.getElementById('p7t-score').textContent = 0; t0 = Date.now(); if(timer) clearInterval(timer); timer = setInterval(()=>{ document.getElementById('p7t-time').textContent = ((Date.now() - t0)/1000)|0; }, 200); newOne(); });
|
||
document.getElementById('p7t-go').addEventListener('click', check);
|
||
document.getElementById('p7t-inp').addEventListener('keyup', e=>{ if(e.key === 'Enter') check(); });
|
||
document.getElementById('p7t-skip').addEventListener('click', ()=>{ if(i < 10){ i++; newOne(); } });
|
||
})();
|
||
|
||
/* ===== INIT INTERACTIVE 6 ===== */
|
||
(function initRoots(){
|
||
let i = 1, score = 0, cur = null;
|
||
function gen(){
|
||
const a = (Math.random() < 0.5 ? 1 : -1) * (1 + Math.floor(Math.random()*5));
|
||
const c = (Math.random() < 0.5 ? 1 : -1) * (1 + Math.floor(Math.random()*16));
|
||
const v = -c/a;
|
||
return { a, c, ok: v > 0, eq: (a === 1 ? '' : (a === -1 ? '-' : a)) + 'x^2 ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)) + ' = 0' };
|
||
}
|
||
function newOne(){
|
||
cur = gen();
|
||
document.getElementById('p7r-i').textContent = i;
|
||
document.getElementById('p7r-task').innerHTML = '$' + cur.eq + '$'; renderMath(document.getElementById('p7r-task'));
|
||
document.getElementById('p7r-fb').style.display = 'none';
|
||
}
|
||
function answer(yes){
|
||
const fb = document.getElementById('p7r-fb');
|
||
fb.style.display = 'block';
|
||
const ok = (cur.ok === yes);
|
||
if(ok){ score++; feedback(fb, true, '✓ Точно. $x^2 = ' + fmt(-cur.c/cur.a) + '$'); }
|
||
else feedback(fb, false, 'Нет. $x^2 = ' + fmt(-cur.c/cur.a) + '$ — ' + (cur.ok ? 'корни есть' : 'корней нет'));
|
||
renderMath(fb);
|
||
document.getElementById('p7r-score').textContent = score;
|
||
if(i >= 8){ setTimeout(()=>{ feedback(fb, score >= 6, 'Итог: ' + score + '/8'); if(score >= 6){ achievement('p7_roots'); bumpProgress('p7', 14); confetti(); } }, 600); }
|
||
else { i++; setTimeout(newOne, 800); }
|
||
}
|
||
document.getElementById('p7r-start').addEventListener('click', ()=>{ i = 1; score = 0; document.getElementById('p7r-score').textContent = 0; newOne(); });
|
||
document.getElementById('p7r-yes').addEventListener('click', ()=>answer(true));
|
||
document.getElementById('p7r-no').addEventListener('click', ()=>answer(false));
|
||
})();
|
||
}
|
||
</script>
|
||
<script>
|
||
/* ============================================================
|
||
§ 8 — ФОРМУЛЫ КОРНЕЙ. ДИСКРИМИНАНТ
|
||
============================================================ */
|
||
function buildP8(){
|
||
const box = document.getElementById('p8-body');
|
||
let html = '';
|
||
|
||
html += makeCard('repeat','Повторение из § 7',null,`
|
||
<ul style="margin-left:18px;line-height:1.7">
|
||
<li>Квадратное уравнение: $ax^2+bx+c=0,\\ a \\neq 0$.</li>
|
||
<li>Неполные уравнения решали без дискриминанта — через вынесение или прямой корень.</li>
|
||
<li>Свойство квадратного корня: $\\sqrt{D}$ существует только при $D \\geq 0$.</li>
|
||
</ul>`);
|
||
|
||
html += makeCard('theory','Универсальная формула','8.1',`
|
||
<p>Для уравнения $ax^2 + bx + c = 0$, $a \\neq 0$, выделим полный квадрат:</p>
|
||
<div style="background:var(--sec-acc-soft);border-radius:10px;padding:12px;margin:8px 0;text-align:center">$$a\\left(x + \\dfrac{b}{2a}\\right)^2 = \\dfrac{b^2 - 4ac}{4a}$$</div>
|
||
<p>Выражение $\\boxed{D = b^2 - 4ac}$ называется <b>дискриминантом</b>. От его знака зависит, есть ли корни.</p>`);
|
||
|
||
html += makeCard('rule','Главные формулы','8.2',`
|
||
<div style="background:var(--card-soft);border:1.5px solid var(--sec-acc);border-radius:10px;padding:12px;margin:6px 0;text-align:center;font-size:1.1rem">$$D = b^2 - 4ac \\qquad x_{1,2} = \\dfrac{-b \\pm \\sqrt{D}}{2a}$$</div>
|
||
<table class="tbl" style="width:100%;border-collapse:collapse;margin-top:8px">
|
||
<thead><tr style="background:var(--sec-acc-soft)"><th style="padding:8px;text-align:left">Знак $D$</th><th style="padding:8px;text-align:left">Сколько корней</th><th style="padding:8px;text-align:left">Формула</th></tr></thead>
|
||
<tbody>
|
||
<tr><td style="padding:8px;border-bottom:1px solid var(--border)">$D > 0$</td><td style="padding:8px;border-bottom:1px solid var(--border)">Два различных</td><td style="padding:8px;border-bottom:1px solid var(--border)">$x_{1,2} = \\dfrac{-b \\pm \\sqrt{D}}{2a}$</td></tr>
|
||
<tr><td style="padding:8px;border-bottom:1px solid var(--border)">$D = 0$</td><td style="padding:8px;border-bottom:1px solid var(--border)">Один (кратный)</td><td style="padding:8px;border-bottom:1px solid var(--border)">$x = \\dfrac{-b}{2a}$</td></tr>
|
||
<tr><td style="padding:8px">$D < 0$</td><td style="padding:8px">Корней нет</td><td style="padding:8px">—</td></tr>
|
||
</tbody>
|
||
</table>`);
|
||
|
||
html += makeCard('algo','Алгоритм решения','8.3',`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>Запишите уравнение в виде $ax^2+bx+c=0$, $a \\neq 0$.</li>
|
||
<li>Выпишите коэффициенты $a$, $b$, $c$ со знаками.</li>
|
||
<li>Вычислите $D = b^2 - 4ac$.</li>
|
||
<li>Сравните $D$ с нулём — определите число корней.</li>
|
||
<li>Если $D \\geq 0$, по формуле найдите $x_1$, $x_2$.</li>
|
||
</ol>`);
|
||
|
||
html += makeCard('example','Пример решения','8.4',`
|
||
<p><b>Решим:</b> $2x^2 - 5x + 2 = 0$. Здесь $a=2$, $b=-5$, $c=2$.</p>
|
||
<p>$D = (-5)^2 - 4 \\cdot 2 \\cdot 2 = 25 - 16 = 9$.</p>
|
||
<p>$\\sqrt{D} = 3$. $x_{1,2} = \\dfrac{5 \\pm 3}{4}$, поэтому $x_1 = \\dfrac{1}{2},\\ x_2 = 2$.</p>
|
||
<p><b>Проверка:</b> $2 \\cdot 4 - 10 + 2 = 0$. ✓</p>`);
|
||
|
||
/* INTERACTIVE 1: калькулятор дискриминанта */
|
||
html += widget('Калькулятор дискриминанта','INTERACT 1','Введите $a$, $b$, $c$ — мгновенно увидите $D$ и корни. Идёт пошаговое вычисление.',`
|
||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
|
||
<label>$a$ = <input type="number" id="p8d-a" value="1" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
|
||
<label>$b$ = <input type="number" id="p8d-b" value="-5" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
|
||
<label>$c$ = <input type="number" id="p8d-c" value="6" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
|
||
</div>
|
||
<div id="p8d-out" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;line-height:1.8"></div>`);
|
||
|
||
/* INTERACTIVE 2: парабола */
|
||
html += widget('Парабола: $y = ax^2+bx+c$','INTERACT 2','Двигайте слайдеры — смотрите, как меняется график и сколько раз он пересекает ось OX.',`
|
||
<div class="sliders">
|
||
<label>$a$ = <b id="p8g-a-val">1</b><input type="range" min="-3" max="3" step="0.1" value="1" id="p8g-a"></label>
|
||
<label>$b$ = <b id="p8g-b-val">0</b><input type="range" min="-6" max="6" step="0.2" value="0" id="p8g-b"></label>
|
||
<label>$c$ = <b id="p8g-c-val">-4</b><input type="range" min="-8" max="8" step="0.2" value="-4" id="p8g-c"></label>
|
||
</div>
|
||
<svg id="p8g-svg" viewBox="-10 -10 220 160" style="width:100%;max-width:480px;display:block;margin:10px auto;background:#fafafa;border:1px solid var(--border);border-radius:8px"></svg>
|
||
<div id="p8g-info" style="text-align:center;font-weight:600;color:var(--sec-acc-d)"></div>`);
|
||
|
||
/* INTERACTIVE 3: 3 случая */
|
||
html += widget('Три случая дискриминанта','INTERACT 3','Кликните по карточке — увидите пример и график для каждого случая.',`
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;margin-bottom:12px">
|
||
<div class="case-card" data-case="pos"><h5>$D > 0$</h5><div>Два корня</div></div>
|
||
<div class="case-card" data-case="zero"><h5>$D = 0$</h5><div>Один корень</div></div>
|
||
<div class="case-card" data-case="neg"><h5>$D < 0$</h5><div>Корней нет</div></div>
|
||
</div>
|
||
<div id="p8c-detail" style="padding:14px;background:var(--card-soft);border-radius:10px;min-height:140px;display:flex;gap:14px;flex-wrap:wrap;align-items:center"></div>`);
|
||
|
||
/* INTERACTIVE 4: тренажёр D */
|
||
html += widget('Тренажёр: «Сколько корней?»','INTERACT 4','По данному уравнению вычислите $D$ устно и ответьте: сколько корней?',`
|
||
<div class="score-display"><span>Задача <b id="p8t-i">1</b> / 10</span><span>Очки: <b id="p8t-score">0</b></span></div>
|
||
<div id="p8t-task" style="font-size:1.3rem;text-align:center;padding:16px;background:var(--sec-acc-soft);border-radius:10px;margin-bottom:10px"></div>
|
||
<div id="p8t-d-hint" style="text-align:center;color:var(--muted);margin-bottom:8px;font-size:.85rem"></div>
|
||
<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap">
|
||
<button class="btn" data-n="2" id="p8t-2">Два</button>
|
||
<button class="btn" data-n="1" id="p8t-1">Один</button>
|
||
<button class="btn" data-n="0" id="p8t-0">Корней нет</button>
|
||
</div>
|
||
<div class="feedback" id="p8t-fb" style="display:none;margin-top:10px"></div>
|
||
<button class="btn primary" id="p8t-start" style="margin-top:10px">Начать</button>`);
|
||
|
||
/* INTERACTIVE 5: пошаговый */
|
||
html += widget('Пошаговый решатель','INTERACT 5','Введите $a$, $b$, $c$ — система разложит решение по шагам.',`
|
||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
|
||
<label>$a$ = <input type="number" id="p8s-a" value="1" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
|
||
<label>$b$ = <input type="number" id="p8s-b" value="-7" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
|
||
<label>$c$ = <input type="number" id="p8s-c" value="12" style="width:70px;padding:6px;border:1.5px solid var(--border);border-radius:6px"></label>
|
||
<button class="btn primary" id="p8s-go">Решить пошагово</button>
|
||
</div>
|
||
<div id="p8s-stage" style="padding:14px;background:var(--card-soft);border-radius:10px;min-height:100px"></div>`);
|
||
|
||
/* INTERACTIVE 6: угадай знак D по графику */
|
||
html += widget('«Угадай знак D» — только по графику','INTERACT 6','По параболе определите знак дискриминанта.',`
|
||
<div class="score-display"><span>Раунд <b id="p8r-i">1</b> / 8</span><span>Правильно: <b id="p8r-score">0</b></span></div>
|
||
<svg id="p8r-svg" viewBox="-10 -10 220 160" style="width:100%;max-width:380px;display:block;margin:10px auto;background:#fafafa;border:1px solid var(--border);border-radius:8px"></svg>
|
||
<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap">
|
||
<button class="btn" data-d="pos" id="p8r-pos">$D > 0$</button>
|
||
<button class="btn" data-d="zero" id="p8r-zero">$D = 0$</button>
|
||
<button class="btn" data-d="neg" id="p8r-neg">$D < 0$</button>
|
||
</div>
|
||
<div class="feedback" id="p8r-fb" style="display:none;margin-top:10px"></div>
|
||
<button class="btn primary" id="p8r-start" style="margin-top:10px">Начать</button>`);
|
||
|
||
/* Устно/класс/дом */
|
||
html += makeCard('oral','Устные вопросы',null,`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>Что такое дискриминант? Какова его формула?</li>
|
||
<li>При каком знаке $D$ уравнение имеет два корня? Один? Ни одного?</li>
|
||
<li>Как изменится $D$, если уравнение умножить на $-1$?</li>
|
||
<li>Найдите $D$ для $x^2 + 2x + 1 = 0$.</li>
|
||
</ol>`);
|
||
|
||
html += makeCard('class','Класс — решите в тетради',null,`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>$x^2 - 7x + 12 = 0$</li>
|
||
<li>$2x^2 + 3x - 2 = 0$</li>
|
||
<li>$x^2 - 6x + 9 = 0$</li>
|
||
<li>$3x^2 + x + 1 = 0$</li>
|
||
<li>$5x^2 - 4x - 1 = 0$</li>
|
||
</ol>`);
|
||
|
||
html += makeCard('home','Домашка',null,`
|
||
<ol style="margin-left:18px;line-height:1.8">
|
||
<li>$x^2 + 5x + 6 = 0$</li>
|
||
<li>$2x^2 - 7x + 3 = 0$</li>
|
||
<li>$4x^2 - 4x + 1 = 0$</li>
|
||
<li>$x^2 + x + 2 = 0$</li>
|
||
<li>При каких $m$ уравнение $x^2 - 4x + m = 0$ имеет один корень?</li>
|
||
</ol>`);
|
||
|
||
html += secNav('p7','p9');
|
||
box.innerHTML = html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0);
|
||
|
||
/* INIT INTERACTIVE 1 */
|
||
(function initDisc(){
|
||
const aE = document.getElementById('p8d-a'), bE = document.getElementById('p8d-b'), cE = document.getElementById('p8d-c');
|
||
const out = document.getElementById('p8d-out');
|
||
let done = false;
|
||
function refresh(){
|
||
const a = +aE.value, b = +bE.value, c = +cE.value;
|
||
if(!isFinite(a) || a === 0){ out.innerHTML = 'Введите $a \\neq 0$ — иначе уравнение не квадратное.'; renderMath(out); return; }
|
||
const D = b*b - 4*a*c;
|
||
let s = '<div><b>Уравнение:</b> $' + (a === 1 ? '' : (a === -1 ? '-' : a)) + 'x^2 ' + (b >= 0 ? '+' + b : b) + 'x ' + (c >= 0 ? '+' + c : c) + ' = 0$</div>';
|
||
s += '<div><b>Шаг 1.</b> $D = b^2 - 4ac = (' + b + ')^2 - 4 \\cdot (' + a + ') \\cdot (' + c + ') = ' + (b*b) + ' - ' + (4*a*c) + ' = ' + D + '$</div>';
|
||
if(D > 0){ const r1 = (-b - Math.sqrt(D))/(2*a), r2 = (-b + Math.sqrt(D))/(2*a); s += '<div><b>Шаг 2.</b> $D > 0 \\Rightarrow$ два корня:</div><div>$x_{1,2} = \\dfrac{-(' + b + ') \\pm \\sqrt{' + D + '}}{2 \\cdot ' + a + '}$</div><div><b>Ответ:</b> $x_1 = ' + fmt(r1) + ',\\ x_2 = ' + fmt(r2) + '$</div>'; }
|
||
else if(D === 0){ s += '<div><b>Шаг 2.</b> $D = 0 \\Rightarrow$ один корень: $x = ' + fmt(-b/(2*a)) + '$</div>'; }
|
||
else s += '<div><b>Шаг 2.</b> $D < 0 \\Rightarrow$ корней нет.</div>';
|
||
out.innerHTML = s; renderMath(out);
|
||
if(!done){ done = true; setTimeout(()=>{ achievement('p8_disc'); bumpProgress('p8', 12); }, 300); }
|
||
}
|
||
[aE,bE,cE].forEach(e => e.addEventListener('input', refresh));
|
||
refresh();
|
||
})();
|
||
|
||
/* INIT INTERACTIVE 2 */
|
||
(function initParabola(){
|
||
const aE = document.getElementById('p8g-a'), bE = document.getElementById('p8g-b'), cE = document.getElementById('p8g-c');
|
||
const svg = document.getElementById('p8g-svg'), info = document.getElementById('p8g-info');
|
||
let done = false;
|
||
const W = 200, H = 140, x0 = W/2, y0 = H/2, sx = 14, sy = 14;
|
||
function refresh(){
|
||
const a = +aE.value, b = +bE.value, c = +cE.value;
|
||
document.getElementById('p8g-a-val').textContent = a.toFixed(1);
|
||
document.getElementById('p8g-b-val').textContent = b.toFixed(1);
|
||
document.getElementById('p8g-c-val').textContent = c.toFixed(1);
|
||
let path = '';
|
||
for(let i = 0; i <= 200; i++){
|
||
const x = -7 + i * 14 / 200;
|
||
const y = a*x*x + b*x + c;
|
||
const cx = x0 + x*sx, cy = y0 - y*sy;
|
||
path += (i === 0 ? 'M' : 'L') + cx.toFixed(2) + ',' + cy.toFixed(2) + ' ';
|
||
}
|
||
let svgC = '<line x1="0" y1="' + y0 + '" x2="' + W + '" y2="' + y0 + '" stroke="#999" stroke-width="0.5"/>';
|
||
svgC += '<line x1="' + x0 + '" y1="0" x2="' + x0 + '" y2="' + H + '" stroke="#999" stroke-width="0.5"/>';
|
||
svgC += '<path d="' + path + '" fill="none" stroke="var(--sec-acc)" stroke-width="1.8"/>';
|
||
if(a !== 0){
|
||
const D = b*b - 4*a*c;
|
||
if(D >= 0){
|
||
const r1 = (-b - Math.sqrt(D))/(2*a), r2 = (-b + Math.sqrt(D))/(2*a);
|
||
[r1, r2].forEach(r=>{ svgC += '<circle cx="' + (x0 + r*sx).toFixed(2) + '" cy="' + y0 + '" r="3" fill="#e91e63"/>'; });
|
||
info.innerHTML = 'D = ' + D.toFixed(2) + ' · ' + (D > 0 ? 'два корня: ' + fmt(r1) + ', ' + fmt(r2) : 'один корень: ' + fmt(r1));
|
||
} else info.innerHTML = 'D = ' + D.toFixed(2) + ' · корней нет (парабола не пересекает OX)';
|
||
}
|
||
svg.innerHTML = svgC;
|
||
if(!done){ done = true; setTimeout(()=>{ achievement('p8_parab'); bumpProgress('p8', 12); }, 400); }
|
||
}
|
||
[aE,bE,cE].forEach(e => e.addEventListener('input', refresh));
|
||
refresh();
|
||
})();
|
||
|
||
/* INIT INTERACTIVE 3 */
|
||
(function initCases(){
|
||
const data = {
|
||
pos: { eq: 'x^2 - 5x + 6 = 0', D: 1, roots: 'x_1 = 2,\\ x_2 = 3', svg: parab(1, -5, 6) },
|
||
zero:{ eq: 'x^2 - 4x + 4 = 0', D: 0, roots: 'x = 2', svg: parab(1, -4, 4) },
|
||
neg: { eq: 'x^2 + x + 1 = 0', D:-3, roots: 'корней нет', svg: parab(1, 1, 1) },
|
||
};
|
||
function parab(a, b, c){
|
||
const W = 180, H = 130, x0 = W/2, y0 = H/2, sx = 11, sy = 11;
|
||
let path = '';
|
||
for(let i = 0; i <= 200; i++){
|
||
const x = -8 + i * 16 / 200;
|
||
const y = a*x*x + b*x + c;
|
||
const cx = x0 + x*sx, cy = y0 - y*sy;
|
||
if(cy >= -20 && cy <= H + 20) path += (path ? 'L' : 'M') + cx.toFixed(2) + ',' + cy.toFixed(2) + ' ';
|
||
}
|
||
let s = '<svg viewBox="0 0 ' + W + ' ' + H + '" style="width:180px;height:130px;background:#fff;border:1px solid #ddd;border-radius:6px">';
|
||
s += '<line x1="0" y1="' + y0 + '" x2="' + W + '" y2="' + y0 + '" stroke="#999" stroke-width="0.5"/>';
|
||
s += '<line x1="' + x0 + '" y1="0" x2="' + x0 + '" y2="' + H + '" stroke="#999" stroke-width="0.5"/>';
|
||
s += '<path d="' + path + '" fill="none" stroke="#e91e63" stroke-width="1.5"/></svg>';
|
||
return s;
|
||
}
|
||
const detail = document.getElementById('p8c-detail');
|
||
let seen = new Set();
|
||
document.querySelectorAll('.case-card').forEach(c=>{
|
||
c.addEventListener('click', ()=>{
|
||
document.querySelectorAll('.case-card').forEach(x=>x.classList.remove('active'));
|
||
c.classList.add('active');
|
||
const d = data[c.dataset.case];
|
||
detail.innerHTML = '<div style="flex:1;min-width:180px"><div><b>Пример:</b> $' + d.eq + '$</div><div><b>$D$ =</b> ' + d.D + '</div><div><b>Корни:</b> $' + d.roots + '$</div></div><div>' + d.svg + '</div>';
|
||
renderMath(detail);
|
||
seen.add(c.dataset.case);
|
||
if(seen.size === 3){ achievement('p8_cases'); bumpProgress('p8', 12); }
|
||
});
|
||
});
|
||
document.querySelector('.case-card').click();
|
||
})();
|
||
|
||
/* INIT INTERACTIVE 4 */
|
||
(function initTrain(){
|
||
let cur = null, i = 1, score = 0;
|
||
function gen(){
|
||
const t = Math.floor(Math.random()*3);
|
||
if(t === 0){
|
||
const r1 = -3 + Math.floor(Math.random()*7), r2 = -3 + Math.floor(Math.random()*7);
|
||
if(r1 === r2) return gen();
|
||
return { a:1, b:-(r1+r2), c:r1*r2, n:2 };
|
||
}
|
||
if(t === 1){
|
||
const r = -4 + Math.floor(Math.random()*9);
|
||
return { a:1, b:-2*r, c:r*r, n:1 };
|
||
}
|
||
const b = -3 + Math.floor(Math.random()*7), c = 3 + Math.floor(Math.random()*8);
|
||
return { a:1, b, c, n:0 };
|
||
}
|
||
function newOne(){
|
||
cur = gen();
|
||
const a = cur.a, b = cur.b, c = cur.c;
|
||
const txt = 'x^2 ' + (b >= 0 ? '+ ' + b : '- ' + Math.abs(b)) + 'x ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)) + ' = 0';
|
||
document.getElementById('p8t-task').innerHTML = '$' + txt + '$';
|
||
document.getElementById('p8t-i').textContent = i;
|
||
document.getElementById('p8t-d-hint').textContent = 'Подскажу: $D = b^2 - 4ac$';
|
||
renderMath(document.getElementById('p8t-task'));
|
||
document.getElementById('p8t-fb').style.display = 'none';
|
||
}
|
||
function answer(n){
|
||
const D = cur.b*cur.b - 4*cur.a*cur.c;
|
||
const fb = document.getElementById('p8t-fb');
|
||
fb.style.display = 'block';
|
||
if(n === cur.n){ score++; feedback(fb, true, '✓ Верно! D = ' + D); }
|
||
else feedback(fb, false, 'Нет. D = ' + D + ' → ' + (cur.n === 2 ? '2 корня' : cur.n === 1 ? '1 корень' : 'корней нет'));
|
||
document.getElementById('p8t-score').textContent = score;
|
||
if(i >= 10){ setTimeout(()=>{ feedback(fb, score >= 7, 'Итог: ' + score + '/10'); if(score >= 7){ achievement('p8_disc_train'); bumpProgress('p8', 16); confetti(); } }, 600); }
|
||
else { i++; setTimeout(newOne, 800); }
|
||
}
|
||
document.getElementById('p8t-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p8t-score').textContent = 0; newOne(); });
|
||
document.getElementById('p8t-2').addEventListener('click', ()=>answer(2));
|
||
document.getElementById('p8t-1').addEventListener('click', ()=>answer(1));
|
||
document.getElementById('p8t-0').addEventListener('click', ()=>answer(0));
|
||
})();
|
||
|
||
/* INIT INTERACTIVE 5 */
|
||
(function initSteps(){
|
||
document.getElementById('p8s-go').addEventListener('click', ()=>{
|
||
const a = +document.getElementById('p8s-a').value;
|
||
const b = +document.getElementById('p8s-b').value;
|
||
const c = +document.getElementById('p8s-c').value;
|
||
const stage = document.getElementById('p8s-stage');
|
||
if(!a){ stage.innerHTML = '<p>$a$ не может быть нулём.</p>'; return; }
|
||
const D = b*b - 4*a*c;
|
||
let html = '<p><b>Шаг 1:</b> $a = ' + a + ',\\ b = ' + b + ',\\ c = ' + c + '$</p>';
|
||
html += '<p><b>Шаг 2:</b> $D = b^2 - 4ac = ' + b + '^2 - 4 \\cdot ' + a + ' \\cdot ' + c + ' = ' + (b*b) + ' - ' + (4*a*c) + ' = ' + D + '$</p>';
|
||
html += '<p><b>Шаг 3:</b> ' + (D > 0 ? '$D > 0$ → два корня' : D === 0 ? '$D = 0$ → один корень' : '$D < 0$ → корней нет') + '</p>';
|
||
if(D >= 0){
|
||
html += '<p><b>Шаг 4:</b> $\\sqrt{D} = ' + fmt(Math.sqrt(D)) + '$</p>';
|
||
if(D > 0){ const r1 = (-b - Math.sqrt(D))/(2*a), r2 = (-b + Math.sqrt(D))/(2*a); html += '<p><b>Шаг 5:</b> $x_1 = \\dfrac{' + (-b) + ' - ' + fmt(Math.sqrt(D)) + '}{' + (2*a) + '} = ' + fmt(r1) + ',\\ x_2 = ' + fmt(r2) + '$</p>'; }
|
||
else html += '<p><b>Шаг 5:</b> $x = \\dfrac{' + (-b) + '}{' + (2*a) + '} = ' + fmt(-b/(2*a)) + '$</p>';
|
||
}
|
||
stage.innerHTML = html; renderMath(stage);
|
||
achievement('p8_steps'); bumpProgress('p8', 12);
|
||
});
|
||
})();
|
||
|
||
/* INIT INTERACTIVE 6 */
|
||
(function initGraph(){
|
||
let cur = null, i = 1, score = 0;
|
||
function gen(){
|
||
const t = Math.floor(Math.random()*3);
|
||
const a = Math.random() < 0.5 ? 1 : -1;
|
||
if(t === 0){
|
||
const r1 = -3 + Math.floor(Math.random()*7), r2 = -3 + Math.floor(Math.random()*7);
|
||
if(r1 === r2) return gen();
|
||
return { a, b:-a*(r1+r2), c:a*r1*r2, kind:'pos' };
|
||
}
|
||
if(t === 1){
|
||
const r = -3 + Math.floor(Math.random()*7);
|
||
return { a, b:-2*a*r, c:a*r*r, kind:'zero' };
|
||
}
|
||
const v = 1 + Math.floor(Math.random()*4);
|
||
return { a:1, b:0, c:v, kind:'neg' };
|
||
}
|
||
function draw(){
|
||
const W = 200, H = 140, x0 = W/2, y0 = H/2, sx = 14, sy = 14;
|
||
let path = '';
|
||
for(let k = 0; k <= 200; k++){
|
||
const x = -7 + k * 14 / 200;
|
||
const y = cur.a*x*x + cur.b*x + cur.c;
|
||
const cx = x0 + x*sx, cy = y0 - y*sy;
|
||
if(cy >= -40 && cy <= H + 40) path += (path ? 'L' : 'M') + cx.toFixed(2) + ',' + cy.toFixed(2) + ' ';
|
||
}
|
||
let s = '<line x1="0" y1="' + y0 + '" x2="' + W + '" y2="' + y0 + '" stroke="#999" stroke-width="0.5"/>';
|
||
s += '<line x1="' + x0 + '" y1="0" x2="' + x0 + '" y2="' + H + '" stroke="#999" stroke-width="0.5"/>';
|
||
s += '<path d="' + path + '" fill="none" stroke="#e91e63" stroke-width="1.6"/>';
|
||
document.getElementById('p8r-svg').innerHTML = s;
|
||
}
|
||
function newOne(){
|
||
cur = gen();
|
||
document.getElementById('p8r-i').textContent = i;
|
||
document.getElementById('p8r-fb').style.display = 'none';
|
||
draw();
|
||
}
|
||
function answer(k){
|
||
const fb = document.getElementById('p8r-fb');
|
||
fb.style.display = 'block';
|
||
if(k === cur.kind){ score++; feedback(fb, true, '✓'); }
|
||
else feedback(fb, false, 'Нет. Правильно: ' + (cur.kind === 'pos' ? 'D > 0' : cur.kind === 'zero' ? 'D = 0' : 'D < 0'));
|
||
document.getElementById('p8r-score').textContent = score;
|
||
if(i >= 8){ setTimeout(()=>{ feedback(fb, score >= 6, 'Итог: ' + score + '/8'); if(score >= 6){ achievement('p8_graph'); bumpProgress('p8', 14); confetti(); } }, 600); }
|
||
else { i++; setTimeout(newOne, 800); }
|
||
}
|
||
document.getElementById('p8r-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p8r-score').textContent = 0; newOne(); });
|
||
document.getElementById('p8r-pos').addEventListener('click', ()=>answer('pos'));
|
||
document.getElementById('p8r-zero').addEventListener('click', ()=>answer('zero'));
|
||
document.getElementById('p8r-neg').addEventListener('click', ()=>answer('neg'));
|
||
})();
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|