From 90d0c41fd0fab577c22034cabe77bb0fc380997d Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Wed, 27 May 2026 14:46:03 +0300 Subject: [PATCH] =?UTF-8?q?feat(algebra-8=20ch2):=20Wave=202=20=E2=80=94?= =?UTF-8?q?=20=C2=A79=20(=D0=92=D0=B8=D0=B5=D1=82=D0=B0)=20+=20=C2=A710=20?= =?UTF-8?q?(=D0=A0=D0=B0=D0=B7=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit § 9 «Теорема Виета»: - Теория, обратная теорема, общий случай (a≠1), знаки корней - INTERACT 1: Тренажёр устного подбора (10 уравнений) - INTERACT 2: Конструктор «корни → уравнение» - INTERACT 3: Знаки корней (8 раундов: оба+, оба-, разные, нет) - INTERACT 4: Быстрая проверка корней через Виета - INTERACT 5: Виета для непривед. (сумма −b/a, произведение c/a) § 10 «Квадратный трёхчлен. Разложение»: - Теория, алгоритм, формула ax²+bx+c = a(x−x₁)(x−x₂) - INTERACT 1: Конструктор разложения (a, x1, x2 → трёхчлен) - INTERACT 2: Пошаговый разлагатель (D, корни, разложение) - INTERACT 3: Тренажёр (8 трёхчленов → корни) - INTERACT 4: Сокращение дробей (5 задач, выбор из 4 вариантов) - INTERACT 5: Разложимо или нет (8 трёхчленов по D) ACH_LABELS добавлены для p9_* и p10_*. Сайдбары для §9 и §10 заполнены формулами. --- frontend/textbooks/algebra_8_ch2.html | 565 +++++++++++++++++++++++++- 1 file changed, 561 insertions(+), 4 deletions(-) diff --git a/frontend/textbooks/algebra_8_ch2.html b/frontend/textbooks/algebra_8_ch2.html index b981aaa..7825be0 100644 --- a/frontend/textbooks/algebra_8_ch2.html +++ b/frontend/textbooks/algebra_8_ch2.html @@ -381,6 +381,16 @@ const ACH_LABELS = { p8_disc_train: 'Тренажёр дискриминанта', p8_steps: 'Пошаговое решение', p8_graph: 'Знак D по графику', + p9_vieta: 'Подбор по Виета', + p9_constr: 'Корни → уравнение', + p9_signs: 'Знаки корней', + p9_check: 'Проверка по Виета', + p9_nonpriv: 'Виета для a≠1', + p10_constr: 'Разложение на множители', + p10_steps: 'Шаговое разложение', + p10_train: 'Тренажёр разложения', + p10_fraction: 'Сокращение дробей', + p10_sort: 'Разложимо или нет', }; function loadProgress(){ @@ -505,8 +515,19 @@ const SIDEBARS = { ['$D = 0$','один корень: $x = \\dfrac{-b}{2a}$'], ['$D < 0$','корней нет'], ]}, - p9: { title:'§ 9 — скоро', rows:[['Теорема Виета','будет в Wave 2']]}, - p10:{ title:'§ 10 — скоро', rows:[['Разложение','будет в Wave 2']]}, + p9: { title:'Шпаргалка § 9', rows:[ + ['Виета','$x_1+x_2=-p,\\ x_1 x_2 = q$ для $x^2+px+q=0$'], + ['Общий','$x_1+x_2 = -b/a,\\ x_1 x_2 = c/a$'], + ['$q > 0$','корни одного знака'], + ['$q < 0$','корни разных знаков'], + ['Обратная','если $x_1+x_2=-p$ и $x_1 x_2=q$ — это корни'], + ]}, + p10:{ title:'Шпаргалка § 10', rows:[ + ['Разложение','$ax^2+bx+c = a(x-x_1)(x-x_2)$'], + ['Условие','$D \\geq 0$ (иначе нельзя)'], + ['Корни','через дискриминант или Виета'], + ['Сокращение','через разложение числителя и знаменателя'], + ]}, p11:{ title:'§ 11 — скоро', rows:[['Текстовые задачи','будет в Wave 3']]}, p12:{ title:'§ 12 — скоро', rows:[['Сводящиеся к квадратным','будет в Wave 3']]}, final2:{ title:'Финал', rows:[['Итоги главы','будет в Wave 4']]}, @@ -657,8 +678,544 @@ function init(){ document.addEventListener('DOMContentLoaded', init); /* STUBS for paragraphs not yet implemented */ -function buildP9stub(){ document.getElementById('p9-body').innerHTML = `

§ 9 — Теорема Виета

Этот параграф будет реализован в следующей волне обновлений.

Wave 2: § 9 + § 10

${secNav('p8','p10')}`; } -function buildP10stub(){ document.getElementById('p10-body').innerHTML = `

§ 10 — Квадратный трёхчлен. Разложение на множители

Скоро в Wave 2.

${secNav('p9','p11')}`; } +function buildP9stub(){ buildP9(); } +function buildP9(){ + const box = document.getElementById('p9-body'); + let html = ''; + + html += makeCard('repeat','Повторение',null,` + `); + + html += makeCard('theory','Теорема Виета','9.1',` +

Пусть $x_1$ и $x_2$ — корни приведённого уравнения $x^2 + px + q = 0$. Тогда:

+
$$x_1 + x_2 = -p,\\qquad x_1 \\cdot x_2 = q$$
+

Обратная теорема. Если для чисел $x_1, x_2$ выполнено $x_1+x_2=-p$ и $x_1 x_2=q$, то они — корни $x^2+px+q=0$.

`); + + html += makeCard('rule','Общий случай (a ≠ 1)','9.2',` +

Для уравнения $ax^2 + bx + c = 0$:

+
$$x_1 + x_2 = -\\dfrac{b}{a},\\qquad x_1 \\cdot x_2 = \\dfrac{c}{a}$$
+

Анализ знаков (если корни вещественные):

+ `); + + html += makeCard('example','Пример',null,` +

Подбор: $x^2 - 7x + 12 = 0$. Ищем $x_1, x_2$: сумма $7$, произведение $12$. Это $3$ и $4$. Ответ: $\\{3;\\ 4\\}$.

+

Составление: найти уравнение с корнями $-2$ и $5$. Сумма $= 3$, произведение $= -10$. Уравнение: $x^2 - 3x - 10 = 0$.

`); + + /* ===== INTERACTIVE 1: Подбор корней ===== */ + html += widget('Тренажёр Виета: устный подбор','INTERACT 1','Дано приведённое уравнение. Подберите корни в уме и введите через точку с запятой.',` +
Задача 1 / 10Очки: 0
+
+
+ + + +
+ + `); + + /* ===== INTERACTIVE 2: Составить уравнение ===== */ + html += widget('Конструктор: корни → уравнение','INTERACT 2','Выберите корни — система соберёт приведённое уравнение по Виета.',` +
+ + +
+
`); + + /* ===== INTERACTIVE 3: Знаки корней ===== */ + html += widget('Знаки корней по Виета','INTERACT 3','По уравнению определите знаки корней (если они существуют).',` +
Раунд 1 / 8Правильно: 0
+
+
+ + + + +
+ + `); + + /* ===== INTERACTIVE 4: Проверка корней по Виета ===== */ + html += widget('Быстрая проверка корней','INTERACT 4','Подставьте найденные корни — проверьте через Виета мгновенно.',` +
+ +
+
+ + +
+
`); + + /* ===== INTERACTIVE 5: Виета для непривед. ===== */ + html += widget('Виета для $a \\neq 1$','INTERACT 5','Уравнение не приведённое. Введите сумму и произведение корней.',` +
+
+ + + + +
+ `); + + html += makeCard('oral','Устные вопросы',null,` +
    +
  1. Сформулируйте теорему Виета для приведённого уравнения.
  2. +
  3. Что говорит обратная теорема?
  4. +
  5. Корни уравнения $x^2 - 9x + 20 = 0$ — целые? Найдите устно.
  6. +
  7. Какого знака произведение корней уравнения $x^2 + 3x - 10 = 0$?
  8. +
`); + + html += makeCard('class','Класс — решите по Виета',null,` +
    +
  1. $x^2 - 11x + 28 = 0$
  2. +
  3. $x^2 + x - 12 = 0$
  4. +
  5. $x^2 + 10x + 21 = 0$
  6. +
  7. Составьте приведённое уравнение с корнями $-4$ и $7$.
  8. +
`); + + html += makeCard('home','Домашка',null,` +
    +
  1. $x^2 - 8x + 15 = 0$
  2. +
  3. $x^2 + 2x - 35 = 0$
  4. +
  5. Составьте уравнение с корнями $\\dfrac{1}{2}$ и $-3$.
  6. +
  7. Найдите $p$, если корни $x^2 + px - 6 = 0$ — это $2$ и $-3$.
  8. +
`); + + html += secNav('p8','p10'); + box.innerHTML = html; + if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0); + + /* INIT 1 — Тренажёр Виета */ + (function(){ + let cur = null, i = 1, score = 0; + function gen(){ + const r1 = -7 + Math.floor(Math.random()*15); + const r2 = -7 + Math.floor(Math.random()*15); + if(r1 === r2) return gen(); + const p = -(r1 + r2), q = r1*r2; + return { r1, r2, p, q }; + } + function show(){ + cur = gen(); + document.getElementById('p9v-i').textContent = i; + const t = 'x^2 ' + (cur.p >= 0 ? '+ ' + cur.p : '- ' + Math.abs(cur.p)) + 'x ' + (cur.q >= 0 ? '+ ' + cur.q : '- ' + Math.abs(cur.q)) + ' = 0'; + document.getElementById('p9v-task').innerHTML = '$' + t + '$'; renderMath(document.getElementById('p9v-task')); + document.getElementById('p9v-inp').value = ''; + document.getElementById('p9v-fb').style.display = 'none'; + } + function check(){ + const fb = document.getElementById('p9v-fb'); + fb.style.display = 'block'; + const u = document.getElementById('p9v-inp').value.replace(/,/g,';').split(/[;\s]+/).filter(Boolean).map(Number).sort((a,b)=>a-b); + const a = [cur.r1, cur.r2].sort((a,b)=>a-b); + const ok = u.length === 2 && u[0] === a[0] && u[1] === a[1]; + if(ok){ score++; feedback(fb, true, '✓ Верно: ' + a.join(' и ')); } + else feedback(fb, false, 'Не то. Правильно: ' + a.join(' и ')); + document.getElementById('p9v-score').textContent = score; + if(i >= 10){ setTimeout(()=>{ feedback(fb, score >= 7, 'Итог: ' + score + '/10'); if(score >= 7){ achievement('p9_vieta'); bumpProgress('p9', 16); confetti(); } }, 600); } + else { i++; setTimeout(show, 800); } + } + document.getElementById('p9v-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p9v-score').textContent = 0; show(); }); + document.getElementById('p9v-go').addEventListener('click', check); + document.getElementById('p9v-inp').addEventListener('keyup', e=>{ if(e.key === 'Enter') check(); }); + document.getElementById('p9v-skip').addEventListener('click', ()=>{ if(i < 10){ i++; show(); } }); + })(); + + /* INIT 2 — Конструктор уравнения */ + (function(){ + const r1E = document.getElementById('p9c-r1'), r2E = document.getElementById('p9c-r2'); + const out = document.getElementById('p9c-out'); + let done = false; + function refresh(){ + const r1 = +r1E.value, r2 = +r2E.value; + const p = -(r1 + r2), q = r1 * r2; + let s = '
Сумма: $x_1 + x_2 = ' + r1 + ' + (' + r2 + ') = ' + (r1+r2) + ' \\Rightarrow -p = ' + (r1+r2) + ' \\Rightarrow p = ' + p + '$
'; + s += '
Произведение: $x_1 \\cdot x_2 = ' + r1 + ' \\cdot (' + r2 + ') = ' + q + ' \\Rightarrow q = ' + q + '$
'; + s += '
Уравнение: $x^2 ' + (p >= 0 ? '+ ' + p : '- ' + Math.abs(p)) + 'x ' + (q >= 0 ? '+ ' + q : '- ' + Math.abs(q)) + ' = 0$
'; + out.innerHTML = s; renderMath(out); + if(!done){ done = true; setTimeout(()=>{ achievement('p9_constr'); bumpProgress('p9', 14); }, 300); } + } + r1E.addEventListener('input', refresh); r2E.addEventListener('input', refresh); + refresh(); + })(); + + /* INIT 3 — Знаки корней */ + (function(){ + let cur = null, i = 1, score = 0; + function gen(){ + const t = Math.floor(Math.random()*4); + if(t === 0){ + const r1 = 1 + Math.floor(Math.random()*5), r2 = 1 + Math.floor(Math.random()*5); + return { p: -(r1+r2), q: r1*r2, kind: 'pp' }; + } + if(t === 1){ + const r1 = -1 - Math.floor(Math.random()*5), r2 = -1 - Math.floor(Math.random()*5); + return { p: -(r1+r2), q: r1*r2, kind: 'nn' }; + } + if(t === 2){ + const r1 = 1 + Math.floor(Math.random()*5), r2 = -1 - Math.floor(Math.random()*5); + return { p: -(r1+r2), q: r1*r2, kind: 'pn' }; + } + const p = -5 + Math.floor(Math.random()*11), q = 4 + Math.floor(Math.random()*8); + const D = p*p - 4*q; + if(D >= 0) return gen(); + return { p, q, kind:'none' }; + } + function show(){ + cur = gen(); + document.getElementById('p9z-i').textContent = i; + const t = 'x^2 ' + (cur.p >= 0 ? '+ ' + cur.p : '- ' + Math.abs(cur.p)) + 'x ' + (cur.q >= 0 ? '+ ' + cur.q : '- ' + Math.abs(cur.q)) + ' = 0'; + document.getElementById('p9z-task').innerHTML = '$' + t + '$'; renderMath(document.getElementById('p9z-task')); + document.getElementById('p9z-fb').style.display = 'none'; + } + function ans(k){ + const fb = document.getElementById('p9z-fb'); + fb.style.display = 'block'; + if(k === cur.kind){ score++; feedback(fb, true, '✓ Верно'); } + else feedback(fb, false, 'Не то. Правильно: ' + ({pp:'оба «+»',nn:'оба «−»',pn:'разных знаков',none:'корней нет'})[cur.kind]); + document.getElementById('p9z-score').textContent = score; + if(i >= 8){ setTimeout(()=>{ feedback(fb, score >= 6, 'Итог: ' + score + '/8'); if(score >= 6){ achievement('p9_signs'); bumpProgress('p9', 14); confetti(); } }, 600); } + else { i++; setTimeout(show, 800); } + } + document.getElementById('p9z-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p9z-score').textContent = 0; show(); }); + document.querySelectorAll('[data-z]').forEach(b => b.addEventListener('click', ()=>ans(b.dataset.z))); + })(); + + /* INIT 4 — Проверка корней */ + (function(){ + document.getElementById('p9p-check').addEventListener('click', ()=>{ + const p = +document.getElementById('p9p-p').value, q = +document.getElementById('p9p-q').value; + const r1 = +document.getElementById('p9p-r1').value, r2 = +document.getElementById('p9p-r2').value; + const sum = r1 + r2, prod = r1 * r2; + const out = document.getElementById('p9p-out'); + const okS = sum === -p, okP = prod === q; + let html = '
$x_1 + x_2 = ' + sum + '$ vs $-p = ' + (-p) + '$ — ' + (okS ? '' : '') + '
'; + html += '
$x_1 \\cdot x_2 = ' + prod + '$ vs $q = ' + q + '$ — ' + (okP ? '' : '') + '
'; + if(okS && okP){ html += '
Корни верные!
'; achievement('p9_check'); bumpProgress('p9', 12); } + else html += '
Корни ошибочны.
'; + out.style.background = (okS && okP) ? 'var(--ok-bg)' : 'var(--fail-bg)'; + out.innerHTML = html; renderMath(out); + }); + })(); + + /* INIT 5 — Виета для непривед. */ + (function(){ + let cur = null; + function gen(){ + const a = 2 + Math.floor(Math.random()*3); + const r1 = -3 + Math.floor(Math.random()*7), r2 = -3 + Math.floor(Math.random()*7); + if(r1 === r2) return gen(); + const b = -a*(r1+r2), c = a*r1*r2; + return { a, b, c, sum:-b/a, prod:c/a }; + } + function show(){ + cur = gen(); + document.getElementById('p9n-task').innerHTML = '$' + cur.a + 'x^2 ' + (cur.b >= 0 ? '+ ' + cur.b : '- ' + Math.abs(cur.b)) + 'x ' + (cur.c >= 0 ? '+ ' + cur.c : '- ' + Math.abs(cur.c)) + ' = 0$'; + renderMath(document.getElementById('p9n-task')); + document.getElementById('p9n-s').value = ''; + document.getElementById('p9n-p').value = ''; + document.getElementById('p9n-fb').style.display = 'none'; + } + function parse(s){ s = s.trim().replace(/,/g,'.'); if(s.includes('/')){ const [a,b] = s.split('/').map(Number); return a/b; } return +s; } + document.getElementById('p9n-go').addEventListener('click', ()=>{ + const us = parse(document.getElementById('p9n-s').value), up = parse(document.getElementById('p9n-p').value); + const fb = document.getElementById('p9n-fb'); fb.style.display = 'block'; + const okS = Math.abs(us - cur.sum) < 1e-6, okP = Math.abs(up - cur.prod) < 1e-6; + if(okS && okP){ feedback(fb, true, '✓ Верно! $\\dfrac{-b}{a}=' + fmt(cur.sum) + ',\\ \\dfrac{c}{a}=' + fmt(cur.prod) + '$'); renderMath(fb); achievement('p9_nonpriv'); bumpProgress('p9', 14); } + else feedback(fb, false, 'Правильно: сумма = ' + fmt(cur.sum) + ', произведение = ' + fmt(cur.prod)); + }); + document.getElementById('p9n-next').addEventListener('click', show); + show(); + })(); +} +function buildP10stub(){ buildP10(); } +function buildP10(){ + const box = document.getElementById('p10-body'); + let html = ''; + + html += makeCard('repeat','Повторение',null,` + `); + + html += makeCard('theory','Что такое квадратный трёхчлен','10.1',` +

Квадратный трёхчлен — это многочлен $ax^2 + bx + c$, где $a \\neq 0$. Числа $x_1, x_2$, при которых он равен нулю, называются корнями трёхчлена.

+

Если $D \\geq 0$, трёхчлен раскладывается:

+
$$ax^2 + bx + c = a(x - x_1)(x - x_2)$$
+

Если $D < 0$ — на множители первой степени с действительными коэффициентами не раскладывается.

`); + + html += makeCard('algo','Алгоритм разложения',null,` +
    +
  1. Найти $D$ и корни $x_1, x_2$.
  2. +
  3. Если $D \\geq 0$, записать $a(x - x_1)(x - x_2)$.
  4. +
  5. Раскрыть скобки и проверить.
  6. +
`); + + html += makeCard('example','Примеры',null,` +

1) $x^2 - 5x + 6 = (x-2)(x-3)$.

+

2) $2x^2 - 7x + 3$: $D = 49 - 24 = 25$, $x_1 = 3$, $x_2 = 0{,}5$. Разложение: $2(x-3)(x-0{,}5) = (x-3)(2x-1)$.

+

3) $x^2 + 1$: $D = -4 < 0$ → не раскладывается.

+

4) Сокращение: $\\dfrac{x^2 - 9}{x^2 - 5x + 6} = \\dfrac{(x-3)(x+3)}{(x-3)(x-2)} = \\dfrac{x+3}{x-2}$.

`); + + /* INT 1 — Конструктор разложения */ + html += widget('Конструктор разложения','INTERACT 1','Введите $a$, $x_1$, $x_2$ — получите трёхчлен и его разложение.',` +
+ + + +
+
`); + + /* INT 2 — Шаговый разлагатель */ + html += widget('Пошаговый разлагатель','INTERACT 2','Введите $a$, $b$, $c$ — система разложит трёхчлен по шагам.',` +
+ + + + +
+
`); + + /* INT 3 — Тренажёр разложения */ + html += widget('Тренажёр разложения','INTERACT 3','Введите разложение в формате $(x-?)(x-?)$ — корни через точку с запятой, со знаками.',` +
Задача 1 / 8Очки: 0
+
+
+ + +
+ + `); + + /* INT 4 — Сокращение дробей */ + html += widget('Сокращение дробей','INTERACT 4','Дробь содержит квадратные трёхчлены. Разложите устно и введите сокращённую форму.',` +
Задача 1 / 5Очки: 0
+
+
+ + `); + + /* INT 5 — Drag: разложимо или нет */ + html += widget('Разложимо или нет?','INTERACT 5','По знаку дискриминанта разнесите трёхчлены: раскладываются на множители или нет.',` +
+
+
Раскладывается ($D \\geq 0$)
+
Не раскладывается ($D < 0$)
+
+
+ `); + + html += makeCard('oral','Устно',null,` +
    +
  1. При каком условии трёхчлен раскладывается?
  2. +
  3. Запишите разложение $x^2 - 4x + 3$.
  4. +
  5. Разложим ли $x^2 + 9$?
  6. +
`); + + html += makeCard('class','Класс — разложите',null,` +
    +
  1. $x^2 - 8x + 15$
  2. +
  3. $2x^2 + 5x - 3$
  4. +
  5. $x^2 + 6x + 9$
  6. +
  7. Сократите: $\\dfrac{x^2 - 4}{x^2 + x - 6}$.
  8. +
`); + + html += makeCard('home','Домашка',null,` +
    +
  1. $x^2 - 9x + 20$
  2. +
  3. $3x^2 - 8x + 4$
  4. +
  5. $x^2 + 4x + 7$ — раскладывается ли?
  6. +
  7. Сократите: $\\dfrac{x^2 - 25}{x^2 - 7x + 10}$.
  8. +
`); + + html += secNav('p9','p11'); + box.innerHTML = html; + if(window.renderMathInElement) setTimeout(()=>renderMath(box), 0); + + /* INIT 1 */ + (function(){ + const aE = document.getElementById('p10c-a'), x1E = document.getElementById('p10c-x1'), x2E = document.getElementById('p10c-x2'); + const out = document.getElementById('p10c-out'); + let done = false; + function refresh(){ + const a = +aE.value, x1 = +x1E.value, x2 = +x2E.value; + if(!a){ out.innerHTML = 'Введите $a \\neq 0$'; renderMath(out); return; } + const b = -a*(x1+x2), c = a*x1*x2; + const eq = (a === 1 ? '' : (a === -1 ? '-' : a)) + 'x^2 ' + (b >= 0 ? '+ ' + b : '- ' + Math.abs(b)) + 'x ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)); + const fact = (a === 1 ? '' : (a === -1 ? '-' : a)) + '(x ' + (x1 >= 0 ? '- ' + x1 : '+ ' + Math.abs(x1)) + ')(x ' + (x2 >= 0 ? '- ' + x2 : '+ ' + Math.abs(x2)) + ')'; + out.innerHTML = '
Трёхчлен: $' + eq + '$
Разложение: $' + fact + '$
'; + renderMath(out); + if(!done){ done = true; setTimeout(()=>{ achievement('p10_constr'); bumpProgress('p10', 14); }, 300); } + } + [aE,x1E,x2E].forEach(e => e.addEventListener('input', refresh)); + refresh(); + })(); + + /* INIT 2 */ + (function(){ + document.getElementById('p10s-go').addEventListener('click', ()=>{ + const a = +document.getElementById('p10s-a').value; + const b = +document.getElementById('p10s-b').value; + const c = +document.getElementById('p10s-c').value; + const stage = document.getElementById('p10s-stage'); + if(!a){ stage.innerHTML = '

$a$ не может быть нулём.

'; return; } + const D = b*b - 4*a*c; + let html = '

Шаг 1: $D = ' + (b*b) + ' - ' + (4*a*c) + ' = ' + D + '$

'; + if(D < 0){ html += '

Шаг 2: $D < 0$ → трёхчлен не раскладывается на множители с действительными коэффициентами.

'; } + else { + const x1 = (-b - Math.sqrt(D))/(2*a), x2 = (-b + Math.sqrt(D))/(2*a); + html += '

Шаг 2: $x_1 = ' + fmt(x1) + ',\\ x_2 = ' + fmt(x2) + '$

'; + html += '

Шаг 3: $' + a + 'x^2 ' + (b >= 0 ? '+ ' + b : '- ' + Math.abs(b)) + 'x ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)) + ' = ' + (a === 1 ? '' : a) + '(x ' + (x1 >= 0 ? '- ' + fmt(x1) : '+ ' + fmt(-x1)) + ')(x ' + (x2 >= 0 ? '- ' + fmt(x2) : '+ ' + fmt(-x2)) + ')$

'; + } + stage.innerHTML = html; renderMath(stage); + achievement('p10_steps'); bumpProgress('p10', 14); + }); + })(); + + /* INIT 3 */ + (function(){ + let cur = null, i = 1, score = 0; + function gen(){ + const r1 = -5 + Math.floor(Math.random()*11), r2 = -5 + Math.floor(Math.random()*11); + if(r1 === r2 || r1 === 0 && r2 === 0) return gen(); + const b = -(r1+r2), c = r1*r2; + return { r1, r2, eq: 'x^2 ' + (b >= 0 ? '+ ' + b : '- ' + Math.abs(b)) + 'x ' + (c >= 0 ? '+ ' + c : '- ' + Math.abs(c)) }; + } + function show(){ + cur = gen(); + document.getElementById('p10t-i').textContent = i; + document.getElementById('p10t-task').innerHTML = '$' + cur.eq + '$'; + renderMath(document.getElementById('p10t-task')); + document.getElementById('p10t-inp').value = ''; + document.getElementById('p10t-fb').style.display = 'none'; + } + function check(){ + const fb = document.getElementById('p10t-fb'); + fb.style.display = 'block'; + const u = document.getElementById('p10t-inp').value.replace(/,/g,';').split(/[;\s]+/).filter(Boolean).map(Number).sort((a,b)=>a-b); + const a = [cur.r1, cur.r2].sort((a,b)=>a-b); + const ok = u.length === 2 && u[0] === a[0] && u[1] === a[1]; + if(ok){ score++; feedback(fb, true, '✓ $(x ' + (cur.r1 >= 0 ? '- ' + cur.r1 : '+ ' + Math.abs(cur.r1)) + ')(x ' + (cur.r2 >= 0 ? '- ' + cur.r2 : '+ ' + Math.abs(cur.r2)) + ')$'); renderMath(fb); } + else feedback(fb, false, 'Правильно: ' + a.join(' и ')); + document.getElementById('p10t-score').textContent = score; + if(i >= 8){ setTimeout(()=>{ feedback(fb, score >= 6, 'Итог: ' + score + '/8'); if(score >= 6){ achievement('p10_train'); bumpProgress('p10', 16); confetti(); } }, 600); } + else { i++; setTimeout(show, 800); } + } + document.getElementById('p10t-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p10t-score').textContent = 0; show(); }); + document.getElementById('p10t-go').addEventListener('click', check); + document.getElementById('p10t-inp').addEventListener('keyup', e=>{ if(e.key === 'Enter') check(); }); + })(); + + /* INIT 4 — Сокращение */ + (function(){ + const tasks = [ + { n:'x^2 - 9', d:'x^2 - 5x + 6', ans:'\\dfrac{x+3}{x-2}', opts:['\\dfrac{x+3}{x-2}','\\dfrac{x-3}{x+2}','\\dfrac{x+3}{x+2}','\\dfrac{1}{x-2}'] }, + { n:'x^2 - 4', d:'x^2 + x - 6', ans:'\\dfrac{x-2}{x+3}', opts:['\\dfrac{x+2}{x+3}','\\dfrac{x-2}{x+3}','\\dfrac{x-2}{x-3}','\\dfrac{x+2}{x-3}'] }, + { n:'x^2 - 25', d:'x^2 - 7x + 10', ans:'\\dfrac{x+5}{x-2}', opts:['\\dfrac{x+5}{x-2}','\\dfrac{x-5}{x-2}','\\dfrac{x-5}{x+2}','\\dfrac{x+5}{x+2}'] }, + { n:'x^2 - 5x + 6', d:'x^2 - 4', ans:'\\dfrac{x-3}{x+2}', opts:['\\dfrac{x-3}{x+2}','\\dfrac{x+3}{x+2}','\\dfrac{x-3}{x-2}','\\dfrac{x+2}{x-3}'] }, + { n:'x^2 - 1', d:'x^2 + 3x - 4', ans:'\\dfrac{x+1}{x+4}', opts:['\\dfrac{x+1}{x+4}','\\dfrac{x-1}{x+4}','\\dfrac{x-1}{x-4}','\\dfrac{x+1}{x-4}'] }, + ]; + let cur = null, i = 1, score = 0, shuffled = []; + function show(){ + cur = shuffled[i-1]; + document.getElementById('p10f-i').textContent = i; + document.getElementById('p10f-task').innerHTML = '$\\dfrac{' + cur.n + '}{' + cur.d + '} = \\ ?$'; + renderMath(document.getElementById('p10f-task')); + const opts = document.getElementById('p10f-opts'); + opts.innerHTML = ''; + [...cur.opts].sort(()=>Math.random()-0.5).forEach(o=>{ + const b = document.createElement('button'); + b.className = 'btn'; + b.innerHTML = '$' + o + '$'; + b.style.cssText = 'text-align:left;padding:10px 14px'; + b.addEventListener('click', ()=>{ + const fb = document.getElementById('p10f-fb'); fb.style.display = 'block'; + if(o === cur.ans){ score++; b.classList.add('ok'); feedback(fb, true, '✓'); } + else { b.classList.add('fail'); feedback(fb, false, 'Правильно: $' + cur.ans + '$'); renderMath(fb); } + document.getElementById('p10f-score').textContent = score; + if(i >= tasks.length){ setTimeout(()=>{ feedback(fb, score >= 4, 'Итог: ' + score + '/' + tasks.length); if(score >= 4){ achievement('p10_fraction'); bumpProgress('p10', 14); confetti(); } }, 600); } + else { i++; setTimeout(show, 900); } + }); + opts.appendChild(b); + }); + renderMath(opts); + document.getElementById('p10f-fb').style.display = 'none'; + } + document.getElementById('p10f-start').addEventListener('click', ()=>{ i=1; score=0; document.getElementById('p10f-score').textContent = 0; shuffled = [...tasks].sort(()=>Math.random()-0.5); show(); }); + })(); + + /* INIT 5 — Drag */ + (function(){ + const items = [ + { id:1, txt:'$x^2 - 5x + 6$', cat:'yes' }, + { id:2, txt:'$x^2 + 1$', cat:'no' }, + { id:3, txt:'$2x^2 + 5x - 3$', cat:'yes' }, + { id:4, txt:'$x^2 - 2x + 5$', cat:'no' }, + { id:5, txt:'$x^2 - 9$', cat:'yes' }, + { id:6, txt:'$3x^2 + x + 1$', cat:'no' }, + { id:7, txt:'$x^2 + 6x + 9$', cat:'yes' }, + { id:8, txt:'$x^2 + 4$', cat:'no' }, + ]; + const cats = ['yes','no']; + const labels = { yes:'Раскл.', no:'Не раскл.' }; + let placed = {}; + function makeChip(it, where){ + const wrap = document.createElement('div'); + 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.innerHTML = it.txt; sp.style.cssText = 'padding:2px 4px'; + 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:.72rem'; + b.addEventListener('click', ()=>{ placed[it.id] = cat; render(); }); + 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]; render(); }); + wrap.appendChild(b); + } + return wrap; + } + function render(){ + const pool = document.getElementById('p10z-pool'); + pool.innerHTML = ''; + items.forEach(it=>{ if(!placed[it.id]) pool.appendChild(makeChip(it, 'pool')); }); + cats.forEach(cat=>{ + const box = document.querySelector('#p10-body .drop-items[data-cat="' + cat + '"]'); + if(!box) return; + box.innerHTML = ''; + items.forEach(it=>{ if(placed[it.id] === cat) box.appendChild(makeChip(it, 'placed')); }); + }); + if(window.renderMathInElement) renderMath(pool.parentElement); + } + document.getElementById('p10z-check').addEventListener('click', ()=>{ + const fb = document.getElementById('p10z-fb'); + fb.style.display = 'block'; + const placedCount = Object.keys(placed).length; + if(placedCount < items.length){ feedback(fb, false, '⚠ Разложите все ' + items.length + ' трёхчленов.'); return; } + let ok = 0; items.forEach(it=>{ if(placed[it.id] === it.cat) ok++; }); + if(ok === items.length){ feedback(fb, true, '✓ Все ' + items.length + ' верно!'); achievement('p10_sort'); bumpProgress('p10', 14); confetti(); } + else feedback(fb, false, 'Верно ' + ok + ' из ' + items.length); + }); + document.getElementById('p10z-reset').addEventListener('click', ()=>{ placed = {}; document.getElementById('p10z-fb').style.display='none'; render(); }); + render(); + })(); +} function buildP11stub(){ document.getElementById('p11-body').innerHTML = `

§ 11 — Текстовые задачи

Скоро в Wave 3.

${secNav('p10','p12')}`; } function buildP12stub(){ document.getElementById('p12-body').innerHTML = `

§ 12 — Сводящиеся к квадратным

Скоро в Wave 3.

${secNav('p11','final2')}`; } function buildFinal2stub(){ document.getElementById('final2-body').innerHTML = `

Финал главы

Итоговая самооценка, практика, увлекательная математика и финальный босс — в Wave 4.

${secNav('p12',null)}`; }