feat(trainer): НОД/НОК с нормальными числами; универсальная шапка; НОК теперь появляется

НОД/НОК (числа больше + без степеней):
- движок: фича factorize ({name, of}) кладёт в шаги решения СТРОКУ разложения на простые множители без степеней (36 -> «2*2*3*3»); helper primeFactorString
- генераторы: a=g·m, b=g·n (g,m,n из 2..9) -> нормальные числа (14, 35, 16, 112…), общий множитель гарантирован; решение показывает разложение обоих + НОД/НОК = произведение множителей
- пример: 16 = 2·2·2·2, НОК = 2·2·2·2·7 = 112

НОК теперь появляется (раньше показывался только НОД):
- причина: smart-подбор брал первый неосвоенный навык ГЛОБАЛЬНО -> из НОД прыгал на lin-basic, НОК не доходил
- фикс: умная тренировка теперь адаптируется В ПРЕДЕЛАХ выбранной темы (pickNext scope = skillsOf(curTopic)) -> в теме «НОД и НОК» ведёт по обоим навыкам; тему выбирает ученик в рейле

Шапка: пилюля стала универсальной и динамической (updateSubjectPill: «Алгебра · 5–9 класс» / «Геометрия · 7–8 класс» по текущему предмету), вместо статичной «Алгебра · 7–8 класс».

Смоук движка 1154/1154, страница 42/42; эмодзи 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-25 17:57:30 +03:00
parent 2a50ff740a
commit fb16821b0a
3 changed files with 53 additions and 26 deletions
+15 -22
View File
@@ -847,20 +847,17 @@
{
id: 'gcd-pair', topic: 'gcd-lcm', order: 1, subject: 'algebra', grade: 5, kind: 'compute',
title: 'НОД двух чисел',
pick: { ip: [0, 3], iq: [0, 3], ir: [0, 3] },
constraint: 'ip != iq && ip != ir && iq != ir',
derive: {
p: '(ip==0)?2:((ip==1)?3:((ip==2)?5:7))',
q: '(iq==0)?2:((iq==1)?3:((iq==2)?5:7))',
r: '(ir==0)?2:((ir==1)?3:((ir==2)?5:7))',
a: 'p*q', b: 'p*r', val: 'gcd(a, b)'
},
pick: { g: [2, 9], m: [2, 8], n: [2, 8] }, constraint: 'm != n',
derive: { a: 'g*m', b: 'g*n', val: 'gcd(a, b)' },
require: 'a <= 90 && b <= 90',
factorize: [{ name: 'aFac', of: 'a' }, { name: 'bFac', of: 'b' }, { name: 'dFac', of: 'gcd(a, b)' }],
lhs: 'x', rhs: 'gcd({a}, {b})', display: 'Найдите наибольший общий делитель (НОД) чисел {a} и {b}.',
answerVar: 'x', answer: 'val', integerAnswer: true,
solution: [
{ note: 'Разложим {a} на простые множители:', tex: '{a} = {p} * {q}' },
{ note: 'Разложим {b} на простые множители:', tex: '{b} = {p} * {r}' },
{ note: 'Общий простой множитель у обоих чисел — {p}. Значит, НОД равен {p}:', tex: 'x = {p}' }
{ note: 'Разложим {a} на простые множители:', tex: '{a} = {aFac}' },
{ note: 'Разложим {b} на простые множители:', tex: '{b} = {bFac}' },
{ note: 'НОД — произведение ОБЩИХ множителей (повторяющиеся берём в наименьшем количестве):', tex: 'x = {dFac}' },
{ note: 'Перемножаем:', tex: 'x = {ans}' }
]
},
@@ -868,20 +865,16 @@
{
id: 'lcm-pair', topic: 'gcd-lcm', order: 2, subject: 'algebra', grade: 6, kind: 'compute',
title: 'НОК двух чисел',
pick: { ip: [0, 3], iq: [0, 3], ir: [0, 3] },
constraint: 'ip != iq && ip != ir && iq != ir',
derive: {
p: '(ip==0)?2:((ip==1)?3:((ip==2)?5:7))',
q: '(iq==0)?2:((iq==1)?3:((iq==2)?5:7))',
r: '(ir==0)?2:((ir==1)?3:((ir==2)?5:7))',
a: 'p*q', b: 'p*r', val: 'lcm(a, b)'
},
pick: { g: [2, 9], m: [2, 8], n: [2, 8] }, constraint: 'm != n',
derive: { a: 'g*m', b: 'g*n', val: 'lcm(a, b)' },
require: 'a <= 60 && b <= 60 && lcm(a, b) <= 240',
factorize: [{ name: 'aFac', of: 'a' }, { name: 'bFac', of: 'b' }, { name: 'kFac', of: 'lcm(a, b)' }],
lhs: 'x', rhs: 'lcm({a}, {b})', display: 'Найдите наименьшее общее кратное (НОК) чисел {a} и {b}.',
answerVar: 'x', answer: 'val', integerAnswer: true,
solution: [
{ note: 'Разложим {a} на простые множители:', tex: '{a} = {p} * {q}' },
{ note: 'Разложим {b} на простые множители:', tex: '{b} = {p} * {r}' },
{ note: 'НОК — произведение всех множителей, общий ({p}) берём один раз:', tex: 'x = {p} * {q} * {r}' },
{ note: 'Разложим {a} на простые множители:', tex: '{a} = {aFac}' },
{ note: 'Разложим {b} на простые множители:', tex: '{b} = {bFac}' },
{ note: 'НОК — произведение ВСЕХ множителей (общие берём в наибольшем количестве):', tex: 'x = {kFac}' },
{ note: 'Перемножаем:', tex: 'x = {ans}' }
]
},