feat(trainer): тема «Окружность» + режим «читать условие с чертежа»

Окружность (новая геом-тема g-circle, 9 кл, π ≈ 3,14 → ответ — конечная
десятичная дробь, ученик вводит её): 4 генератора — длина окружности по радиусу
(2πr), по диаметру (πd), площадь круга (πr²), длина дуги ((n/360)·2πr, n=45·k,
require r·k чётно → дробь конечная). Новые типы фигур: circle (радиус/диаметр/
заливка) и circle-arc (два радиуса под центральным углом + выделенная дуга).

Режим «читать значения с чертежа»: у всех 19 геом-генераторов добавлено
figurePrompt (краткое условие); переключатель «Текст / На чертеже» (#tr-figmode)
на странице, выбор сохраняется в localStorage. В режиме чертежа числа берутся с
фигуры, текст минимальный. Движок прокидывает figurePrompt; showStatement
выбирает полный текст или промпт; renderFigureToggle показан только для задач с
чертежом; для текстовых/алгебраических задач режим скрыт, проверка ответа от
режима не зависит. На чертеж n-угольника выведено число сторон (n = …).

Верификация: headless-смоук 6968 проверок / 1140 рендеров; ответы окружности
конечные и принимаются движком (1600 экземпляров, округление до 2 знаков ok);
inline-скрипт парсится; адверсариал-ревью — circle clean, toggle без high/medium
(2 low устранены: скрытие тумблера при неудаче генерации + подпись n сторон).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-26 12:49:15 +03:00
parent ff9900bdcc
commit 1dcde8790a
4 changed files with 175 additions and 5 deletions
+84 -1
View File
@@ -41,7 +41,8 @@
{ key: 'g-pyth', label: 'Пифагор', subject: 'geometry', grade: 8, order: 13 },
{ key: 'g-area', label: 'Площади', subject: 'geometry', grade: 8, order: 14 },
{ key: 'g-poly', label: 'Многоугольники', subject: 'geometry', grade: 8, order: 15 },
{ key: 'g-sim', label: 'Подобие', subject: 'geometry', grade: 8, order: 16 }
{ key: 'g-sim', label: 'Подобие', subject: 'geometry', grade: 8, order: 16 },
{ key: 'g-circle', label: 'Окружность', subject: 'geometry', grade: 9, order: 17 }
];
var GENERATORS = [
@@ -501,6 +502,7 @@
id: 'ang-triangle', topic: 'g-angles', order: 1, subject: 'geometry', grade: 7, kind: 'compute',
title: 'Третий угол треугольника',
figure: { type: 'triangle-angles', angA: 'a', angB: 'b' },
figurePrompt: 'Найдите неизвестный угол треугольника (в градусах).',
pick: { a: [20, 80], b: [20, 80] }, derive: { val: '180 - a - b' }, require: 'val >= 15 && val <= 150',
lhs: 'x', rhs: '180 - {a} - {b}', display: 'В треугольнике два угла равны {a}° и {b}°. Найдите третий угол (в градусах).',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -515,6 +517,7 @@
id: 'ang-adjacent', topic: 'g-angles', order: 2, subject: 'geometry', grade: 7, kind: 'compute',
title: 'Смежный угол',
figure: { type: 'adjacent-angles', ang: 'a' },
figurePrompt: 'Найдите неизвестный угол (в градусах).',
pick: { a: [25, 155] }, derive: { val: '180 - a' },
lhs: 'x', rhs: '180 - {a}', display: 'Один из смежных углов равен {a}°. Найдите другой смежный с ним угол.',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -529,6 +532,7 @@
id: 'ang-exterior', topic: 'g-angles', order: 3, subject: 'geometry', grade: 7, kind: 'compute',
title: 'Внешний угол треугольника',
figure: { type: 'triangle-angles', angA: 'a', angB: 'b', ext: true },
figurePrompt: 'Найдите внешний угол треугольника (в градусах).',
pick: { a: [20, 80], b: [20, 80] }, derive: { val: 'a + b' }, require: 'val <= 160',
lhs: 'x', rhs: '{a} + {b}', display: 'Внешний угол треугольника равен сумме двух не смежных с ним внутренних углов. Эти углы равны {a}° и {b}°. Найдите внешний угол.',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -545,6 +549,7 @@
id: 'pyth-hyp', topic: 'g-pyth', order: 1, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Гипотенуза (Пифагор)',
figure: { type: 'right-triangle', a: 'a', b: 'b', c: 'c', unknown: 'c' },
figurePrompt: 'Найдите гипотенузу прямоугольного треугольника (отмечена «?»).',
pick: { m: [2, 5], n: [1, 4] }, constraint: 'm > n',
derive: { a: 'm*m - n*n', b: '2*m*n', c: 'm*m + n*n' },
lhs: 'x', rhs: 'sqrt({a}^2 + {b}^2)', display: 'Катеты прямоугольного треугольника равны {a} и {b}. Найдите гипотенузу.',
@@ -560,6 +565,7 @@
id: 'pyth-leg', topic: 'g-pyth', order: 2, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Катет (Пифагор)',
figure: { type: 'right-triangle', a: 'a', b: 'b', c: 'c', unknown: 'b' },
figurePrompt: 'Найдите неизвестный катет (отмечен «?»).',
pick: { m: [2, 5], n: [1, 4] }, constraint: 'm > n',
derive: { a: 'm*m - n*n', b: '2*m*n', c: 'm*m + n*n' },
lhs: 'x', rhs: 'sqrt({c}^2 - {a}^2)', display: 'Гипотенуза прямоугольного треугольника {c}, один катет {a}. Найдите второй катет.',
@@ -577,6 +583,7 @@
id: 'area-rect', topic: 'g-area', order: 1, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Площадь прямоугольника',
figure: { type: 'rectangle', w: 'a', h: 'b' },
figurePrompt: 'Найдите площадь прямоугольника.',
pick: { a: [2, 16], b: [2, 16] }, derive: { val: 'a*b' },
lhs: 'x', rhs: '{a}*{b}', display: 'Стороны прямоугольника {a} и {b}. Найдите его площадь.',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -591,6 +598,7 @@
id: 'area-triangle', topic: 'g-area', order: 2, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Площадь треугольника',
figure: { type: 'triangle-base-height', base: 'a', height: 'h' },
figurePrompt: 'Найдите площадь треугольника.',
pick: { a: [2, 16], h: [2, 16] }, require: 'mod(a*h, 2) == 0',
derive: { val: 'a*h/2' },
lhs: 'x', rhs: '{a}*{h}/2', display: 'Основание треугольника {a}, высота к нему {h}. Найдите площадь.',
@@ -606,6 +614,7 @@
id: 'area-square', topic: 'g-area', order: 3, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Площадь квадрата',
figure: { type: 'square', a: 'a' },
figurePrompt: 'Найдите площадь квадрата.',
pick: { a: [2, 20] }, derive: { val: 'a*a' },
lhs: 'x', rhs: '{a}^2', display: 'Сторона квадрата {a}. Найдите его площадь.',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -733,6 +742,7 @@
id: 'area-trapezoid', topic: 'g-area', order: 4, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Площадь трапеции',
figure: { type: 'trapezoid', bottom: 'a', top: 'b', height: 'h' },
figurePrompt: 'Найдите площадь трапеции.',
pick: { a: [2, 14], b: [2, 14], h: [2, 12] }, require: 'mod((a + b)*h, 2) == 0',
derive: { val: '(a + b)*h/2' },
lhs: 'x', rhs: '({a} + {b})*{h}/2', display: 'Основания трапеции {a} и {b}, высота {h}. Найдите площадь.',
@@ -748,6 +758,7 @@
id: 'area-parallelogram', topic: 'g-area', order: 5, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Площадь параллелограмма',
figure: { type: 'parallelogram', base: 'a', height: 'h' },
figurePrompt: 'Найдите площадь параллелограмма.',
pick: { a: [2, 16], h: [2, 14] }, derive: { val: 'a*h' },
lhs: 'x', rhs: '{a}*{h}', display: 'Сторона параллелограмма {a}, высота к ней {h}. Найдите площадь.',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -762,6 +773,7 @@
id: 'area-rhombus', topic: 'g-area', order: 6, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Площадь ромба',
figure: { type: 'rhombus', d1: 'd1', d2: 'd2' },
figurePrompt: 'Найдите площадь ромба.',
pick: { d1: [2, 16], d2: [2, 16] }, require: 'mod(d1*d2, 2) == 0',
derive: { val: 'd1*d2/2' },
lhs: 'x', rhs: '{d1}*{d2}/2', display: 'Диагонали ромба {d1} и {d2}. Найдите площадь.',
@@ -779,6 +791,7 @@
id: 'poly-angles-sum', topic: 'g-poly', order: 1, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Сумма углов многоугольника',
figure: { type: 'regular-polygon', n: 'n' },
figurePrompt: 'Найдите сумму углов многоугольника на чертеже (в градусах).',
pick: { n: [3, 12] }, derive: { val: '180*(n - 2)' },
lhs: 'x', rhs: '180*({n} - 2)', display: 'Найдите сумму углов выпуклого {n}-угольника (в градусах).',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -793,6 +806,7 @@
id: 'poly-regular-angle', topic: 'g-poly', order: 2, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Угол правильного многоугольника',
figure: { type: 'regular-polygon', n: 'n', markAngle: true },
figurePrompt: 'Найдите угол правильного многоугольника на чертеже (в градусах).',
pick: { n: [3, 20] }, require: 'mod(180*(n - 2), n) == 0',
derive: { val: '180*(n - 2)/n' },
lhs: 'x', rhs: '180*({n} - 2)/{n}', display: 'Найдите величину угла правильного {n}-угольника (в градусах).',
@@ -810,6 +824,7 @@
id: 'sim-side', topic: 'g-sim', order: 1, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Сторона по коэффициенту',
figure: { type: 'two-similar', side: 'a', k: 'k', mode: 'side' },
figurePrompt: 'Найдите сходственную сторону подобного треугольника (отмечена «?»).',
pick: { a: [2, 15], k: [2, 5] }, derive: { val: 'a*k' },
lhs: 'x', rhs: '{a}*{k}', display: 'Треугольники подобны с коэффициентом {k}. Сторона первого равна {a}. Найдите сходственную сторону второго.',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -824,6 +839,7 @@
id: 'sim-perimeter', topic: 'g-sim', order: 2, subject: 'geometry', grade: 8, kind: 'compute',
title: 'Периметр подобной фигуры',
figure: { type: 'two-similar', perim: 'p', k: 'k', mode: 'perimeter' },
figurePrompt: 'Найдите периметр подобной фигуры (отмечена «?»).',
pick: { p: [5, 30], k: [2, 5] }, derive: { val: 'p*k' },
lhs: 'x', rhs: '{p}*{k}', display: 'Фигуры подобны с коэффициентом {k}. Периметр первой равен {p}. Найдите периметр второй.',
answerVar: 'x', answer: 'val', integerAnswer: true,
@@ -991,6 +1007,71 @@
{ note: 'Перемножаем модули; знак минус — если множители разных знаков, плюс — если одинаковых:', tex: 'x = {a}*{b}' },
{ note: 'Получаем:', tex: 'x = {ans}' }
]
},
/* ═══ Тема: Окружность (геометрия, 9 класс) ═══
Считаем с π ≈ 3,14 (как в учебниках) → ответ — КОНЕЧНАЯ десятичная дробь,
ученик вводит её (SimExpr принимает «31.4»). Чертёж показывает радиус/диаметр/угол. */
/* длина окружности по радиусу: C = 2πr */
{
id: 'circ-length', topic: 'g-circle', order: 1, subject: 'geometry', grade: 9, kind: 'compute',
title: 'Длина окружности',
figure: { type: 'circle', r: 'r', show: 'radius' },
figurePrompt: 'Найдите длину окружности (π ≈ 3,14).',
pick: { r: [1, 20] }, derive: { val: '2*3.14*r' },
lhs: 'x', rhs: '2*3.14*{r}', display: 'Радиус окружности равен {r}. Найдите длину окружности (π ≈ 3,14).',
answerVar: 'x', answer: 'val',
solution: [
{ note: 'Длина окружности вычисляется по формуле C = 2πr. Подставляем r = {r} и π ≈ 3,14:', tex: 'x = 2*3.14*{r}' },
{ note: 'Считаем:', tex: 'x = {ans}' }
]
},
/* длина окружности по диаметру: C = πd */
{
id: 'circ-diam', topic: 'g-circle', order: 2, subject: 'geometry', grade: 9, kind: 'compute',
title: 'Длина по диаметру',
figure: { type: 'circle', d: 'd', show: 'diameter' },
figurePrompt: 'Найдите длину окружности (π ≈ 3,14).',
pick: { d: [2, 30] }, derive: { val: '3.14*d' },
lhs: 'x', rhs: '3.14*{d}', display: 'Диаметр окружности равен {d}. Найдите длину окружности (π ≈ 3,14).',
answerVar: 'x', answer: 'val',
solution: [
{ note: 'Длину окружности можно найти через диаметр: C = πd. Подставляем d = {d} и π ≈ 3,14:', tex: 'x = 3.14*{d}' },
{ note: 'Считаем:', tex: 'x = {ans}' }
]
},
/* площадь круга: S = πr² */
{
id: 'circ-area', topic: 'g-circle', order: 3, subject: 'geometry', grade: 9, kind: 'compute',
title: 'Площадь круга',
figure: { type: 'circle', r: 'r', show: 'area' },
figurePrompt: 'Найдите площадь круга (π ≈ 3,14).',
pick: { r: [1, 15] }, derive: { val: '3.14*r^2' },
lhs: 'x', rhs: '3.14*{r}^2', display: 'Радиус круга равен {r}. Найдите его площадь (π ≈ 3,14).',
answerVar: 'x', answer: 'val',
solution: [
{ note: 'Площадь круга вычисляется по формуле S = πr². Подставляем r = {r} и π ≈ 3,14:', tex: 'x = 3.14*{r}^2' },
{ note: 'Считаем:', tex: 'x = {ans}' }
]
},
/* длина дуги: L = (n/360)·2πr; n = 45·k, требуем конечную дробь (r·k чётно) */
{
id: 'circ-arc', topic: 'g-circle', order: 4, subject: 'geometry', grade: 9, kind: 'compute',
title: 'Длина дуги',
figure: { type: 'circle-arc', r: 'r', angle: 'n' },
figurePrompt: 'Найдите длину дуги (π ≈ 3,14).',
pick: { r: [3, 12], k: [1, 7] }, require: 'mod(r*k, 2) == 0',
derive: { n: '45*k', val: '45*k/360*2*3.14*r' },
lhs: 'x', rhs: '{n}/360*2*3.14*{r}', display: 'Дуга окружности радиуса {r} опирается на центральный угол {n}°. Найдите длину дуги (π ≈ 3,14).',
answerVar: 'x', answer: 'val',
solution: [
{ note: 'Длина дуги — это часть длины окружности: L = (n/360)·2πr. Здесь n = {n}°, r = {r}, π ≈ 3,14:', tex: 'x = {n}/360*2*3.14*{r}' },
{ note: 'Считаем:', tex: 'x = {ans}' }
]
}
];
@@ -1031,6 +1112,8 @@
'area-parallelogram': 2, 'area-trapezoid': 3, 'area-rhombus': 2,
// Геометрия — Многоугольники / Подобие
'poly-angles-sum': 1, 'poly-regular-angle': 2, 'sim-side': 1, 'sim-perimeter': 2,
// Геометрия — Окружность
'circ-length': 1, 'circ-diam': 1, 'circ-area': 2, 'circ-arc': 3,
// НОД/НОК / Дроби / Десятичные / Отрицательные
'gcd-pair': 1, 'lcm-pair': 2,
'frac-of-number': 1, 'frac-add-same': 2,