7 Commits

Author SHA1 Message Date
Maxim Dolgolyov 143ae23216 fix(ctmath): срезать провенанс-префикс [ЦТ YYYY · XN] из текста заданий
48 заданий год-пачек (ЦТ 2017/2021) при оцифровке получили в начале text_html
тег вида «[ЦТ 2017 · A1]» — мусор для ученика в тренажёре. cleanup_ctmath_bank.js
теперь срезает ведущий тег [ЦТ|ЦЭ|РТ|ДРТ YYYY …] (узкий паттерн, не трогает
матскобки внутри $…$, не обнуляет пустой результат). Идемпотентно.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:37:29 +03:00
Maxim Dolgolyov dbfcfa41ec fix(ctmath): расширить выпадающий список вариантов под длинные подписи
Селект «Вариант» использовал .mk-input (узкий, под число) → подпись
«РТ-2024/25 · этап I» обрезалась. Задал width:auto/min-width:14rem/max-width:100%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:33:40 +03:00
Maxim Dolgolyov 9a13a19e63 feat(ctmath): человекочитаемые подписи вариантов-пробников
Вместо «Вариант 101/102/103» (технические номера) показываем источник:
«РТ-2024/25 · этап I/II/III». examVariantLabel() в exam-prep.js — единый
источник подписи: listVariants (пикер/dropdown) + variant_label в ответе
mock/:id (строка прохождения и результата). Номера в БД остаются 101+
(нужны для фильтра-диапазона [101;1999] и провенанса). math9 — fallback
«Вариант N» (не затронут). Новые варианты (104+) — дописывать в VARIANT_LABEL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:31:45 +03:00
Maxim Dolgolyov 68817cc612 fix(ctmath): чистка банка — год-пачки убраны из пикера пробников
- exam-prep.js: MOCK_VARIANT_RANGE — для ctmath показываем как пробники
  только чистые 30-задачные варианты [101;1999]; год-пачки (variant=год
  2011-2024 и 0, до 114 задач) остаются пулом для тренажёра по темам,
  но скрыты из пикера/mock-start/просмотра вариантов. math9 (1..80) не затронут
  (диапазон только для ctmath).
- mock.js: пикер «По варианту» — выпадающий список реальных вариантов
  (через listVariants) вместо number-input 1..N; раньше для ctmath он
  предлагал 1..18 и не доходил до 101 → пробник по варианту не запускался.
- cleanup_ctmath_bank.js: идемпотентный скрипт — ретайр битого id=1419
  (mc с противоречивым ответом → long), variants_count → 3 (чистых вариантов).
- seed_*: variants_count считается по диапазону [101;1999] (консистентно с роутом).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 22:22:32 +03:00
Maxim Dolgolyov 6cd0a81d88 feat(ctmath): пробник РТ-2024/25 Этап III Вариант 1 (variant=103)
Завершающий пробник РТ-2024/25 (полный охват: тела вращения, сфера,
производная, сечения, параметрически сложные задачи). По 1 варианту на Этап.
1 чертёж из PDF (три окружности, А2). KaTeX-рендер 30/30, self-сверка ответов.
РТ-2024/25 оцифрован целиком: Этапы I/II/III = variants 101/102/103.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 22:01:38 +03:00
Maxim Dolgolyov 2af560b7c4 feat(ctmath): пробник РТ-2024/25 Этап II Вариант 1 (variant=102)
Чистый 30-задачный пробник Этапа II (другой набор тем, чем Этап I:
обратные тригфункции, логарифмы, производная, стереометрия). По 1 варианту
на Этап (правило «без повторов»). 3 чертежа из PDF (параллельные прямые,
панель из 5 графиков для y=|x|, график функции). KaTeX-рендер 30/30, self-сверка.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 21:34:53 +03:00
Maxim Dolgolyov 98894e31ad feat(ctmath): эталонный пробник РТ-2024/25 Этап I Вариант 1 (variant=101)
Первый чистый 30-задачный вариант-пробник для exam-prep ctmath (А1–А10 + В1–В20),
в отличие от год-пачек (variant=год). Идемпотентный seed (dry-run/--apply),
3 чертежа вырезаны из PDF (хорда/график/L-поле). Проверено: KaTeX-рендер 30/30,
self-сверка ответов через checkAnswerServer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 21:08:19 +03:00
13 changed files with 1123 additions and 10 deletions
+103
View File
@@ -0,0 +1,103 @@
'use strict';
/* ───────────────────────────────────────────────────────────────────────────
cleanup_ctmath_bank.js — точечная чистка банка exam-prep ctmath.
Что делает (идемпотентно):
1. id=1248 (вычисление 5^lg2·2^lg5): дефектная задача (варианты «а» и «д»
одинаковы, верного ответа нет) — уже переведена в 'long'; чистим
литеральное answer="null" → NULL.
2. id=1419 (var 2024, «укажите номера пар»): битый mc — сохранённый ответ «а»
(«3 и 4») противоречит решению («4 и 5»), причём «4 и 5» вообще нет среди
вариантов; единственная подходящая пара — №4, ни один mc-вариант не верен.
Ретайрим в 'long' (self-check): убирается из авто-проверки тренажёра/пробника
(там берутся только mc/open), но текст и разбор сохраняются.
3. variants_count трека ctmath → число «чистых» вариантов-пробников (variant≥101),
чтобы шапка («N вариантов») соответствовала пикеру (год-пачки скрыты роутом).
Год-пачки (variant=год) НЕ удаляются — они остаются пулом задач для тренажёра
по темам (он отбирает по subtopic). «Указательные» opts (["1","1"]…) НЕ трогаем —
они рабочие (ученик выбирает номер).
Запуск: node backend/scripts/cleanup_ctmath_bank.js [--apply]
─────────────────────────────────────────────────────────────────────────── */
const { DatabaseSync } = require('node:sqlite');
const path = require('path');
const APPLY = process.argv.includes('--apply');
const EXAM = 'ctmath';
// Чистые варианты-пробники: 3-значные [101;1999]; год-пачки — 4-значные годы
// (≥2011) и 0 — исключены. Совпадает с MOCK_VARIANT_RANGE.ctmath в routes/exam-prep.js.
const MOCK_LO = 101, MOCK_HI = 1999;
const db = new DatabaseSync(path.join(__dirname, '..', 'data', 'learnspace.db'));
const get = (sql, ...a) => db.prepare(sql).get(...a);
console.log(`\n=== cleanup_ctmath_bank (${APPLY ? 'APPLY' : 'DRY-RUN'}) ===\n`);
const actions = [];
// 1. id=1248 answer="null" → NULL
const t1248 = get(`SELECT id, task_type, answer FROM exam_tasks WHERE id=1248 AND exam_key=?`, EXAM);
if (t1248 && t1248.answer === 'null') {
actions.push({ desc: `id=1248: answer "null" → NULL (тип ${t1248.task_type})`,
run: () => db.prepare(`UPDATE exam_tasks SET answer=NULL WHERE id=1248`).run() });
} else {
console.log(`• id=1248: пропуск (answer=${t1248 ? JSON.stringify(t1248.answer) : 'нет строки'})`);
}
// 2. id=1419 битый mc → long, answer/opts NULL
const t1419 = get(`SELECT id, task_type FROM exam_tasks WHERE id=1419 AND exam_key=?`, EXAM);
if (t1419 && t1419.task_type === 'mc') {
actions.push({ desc: `id=1419: битый mc → 'long' (answer/opts → NULL, текст и разбор сохраняются)`,
run: () => db.prepare(`UPDATE exam_tasks SET task_type='long', answer=NULL, opts_json=NULL WHERE id=1419`).run() });
} else {
console.log(`• id=1419: пропуск (тип ${t1419 ? t1419.task_type : 'нет строки'})`);
}
// 2b. Срезать провенанс-префикс [ЦТ YYYY · XN] из начала текста задания
// (в чистых вариантах 101+ его нет; для консистентности убираем из год-пачек).
// Паттерн узкий: [ + ЦТ|ЦЭ|РТ|ДРТ + год + … + ]; математические скобки внутри $…$ не задеваются.
const reTag = /^\s*\[(?:ЦТ|ЦЭ|РТ|ДРТ)\s+\d{4}[^\]]*\]\s*/;
const prefixed = db.prepare(`SELECT id, text_html FROM exam_tasks WHERE exam_key=? AND TRIM(text_html) LIKE '[%'`).all(EXAM)
.filter(r => reTag.test(r.text_html))
.map(r => ({ id: r.id, clean: r.text_html.replace(reTag, '') }))
.filter(p => p.clean.trim().length > 0); // не обнуляем задачу
if (prefixed.length) {
actions.push({ desc: `срезать провенанс-префикс [ЦТ … ] у ${prefixed.length} заданий`,
run: () => { const upd = db.prepare(`UPDATE exam_tasks SET text_html=? WHERE id=?`); for (const p of prefixed) upd.run(p.clean, p.id); } });
} else {
console.log('• провенанс-префиксы: пропуск (не найдено)');
}
// 3. variants_count = число чистых вариантов (≥101)
const cleanCnt = get(`SELECT COUNT(DISTINCT variant) c FROM exam_tasks WHERE exam_key=? AND variant BETWEEN ? AND ?`, EXAM, MOCK_LO, MOCK_HI).c;
const curCnt = get(`SELECT variants_count vc FROM exam_tracks WHERE exam_key=?`, EXAM).vc;
if (curCnt !== cleanCnt) {
actions.push({ desc: `exam_tracks.variants_count: ${curCnt}${cleanCnt} (чистых вариантов [${MOCK_LO};${MOCK_HI}])`,
run: () => db.prepare(`UPDATE exam_tracks SET variants_count=? WHERE exam_key=?`).run(cleanCnt, EXAM) });
} else {
console.log(`• variants_count: пропуск (уже ${curCnt})`);
}
console.log(`\nК применению (${actions.length}):`);
actions.forEach(a => console.log(' - ' + a.desc));
if (!actions.length) { console.log('\nНечего менять — всё уже в нужном состоянии.\n'); db.close(); process.exit(0); }
if (!APPLY) {
console.log('\nDRY-RUN: ничего не записано. Для записи: node backend/scripts/cleanup_ctmath_bank.js --apply\n');
db.close(); process.exit(0);
}
db.exec('BEGIN');
try {
for (const a of actions) a.run();
db.exec('COMMIT');
console.log(`\n✓ Применено изменений: ${actions.length}.\n`);
} catch (e) {
db.exec('ROLLBACK');
console.error('\n✗ Ошибка, откат:', e.message);
process.exitCode = 1;
}
db.close();
+384
View File
@@ -0,0 +1,384 @@
'use strict';
/* ───────────────────────────────────────────────────────────────────────────
seed_ctmath_rt2425_e1v1.js
Эталонный «чистый» вариант-пробник для трека exam-prep `ctmath`.
Источник: РТ–2024/2025, Этап I, Вариант 1 (РИКЗ, «Тематическое
консультирование по математике»). 30 заданий: А1–А10 (часть A) +
В1–В20 (часть B). Перенабрано вручную в KaTeX по PDF
(F:\!Рабочие\ЦТ\Математика\Математика\РТ\2024-2025\МАТ РТ-1 24_25 В1.pdf).
Чем отличается от уже залитых 723 задач: те сгруппированы по `variant`=ГОД
(2024 → 114 задач в одной «пачке») и НЕ образуют чистого 30-задачного
варианта, поэтому таймер-пробник на них собирается криво. Здесь
variant=101 — ровно 30 заданий (task_idx 1..30) → корректный пробник
на 180 мин (mock source='variant').
Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx). Повторный
запуск обновляет строки, не плодит дубли.
Запуск:
node backend/scripts/seed_ctmath_rt2425_e1v1.js # DRY-RUN (по умолчанию)
node backend/scripts/seed_ctmath_rt2425_e1v1.js --apply # запись в БД
⚠️ Массовую запись в БД запускает ПОЛЬЗОВАТЕЛЬ вручную (авто-режим
Claude Code блокирует продакшн-записи). Скрипт безопасен: без --apply
ничего не пишет, только печатает сводку и самопроверку.
─────────────────────────────────────────────────────────────────────────── */
const { DatabaseSync } = require('node:sqlite');
const path = require('path');
const APPLY = process.argv.includes('--apply');
const EXAM = 'ctmath';
const VARIANT = 101; // чистый 30-задачный вариант (не год)
const PROV = 'РТ–2024/2025, Этап I, Вариант 1';
const R = String.raw;
// figure helper — белый фон у самого PNG, поэтому смотрится на любой теме
const FIG = (name, alt) =>
`<img src="/img/ct/math/rt2425_e1v1/${name}" alt="${alt}" ` +
`style="max-width:300px;width:100%;height:auto;display:block;margin:10px auto;` +
`background:#fff;border-radius:8px;padding:6px;">`;
/* opts: метки кириллица а–д (как в существующих 723 строках ctmath;
checkAnswerServer имеет ветку /^[а-д]$/). РТ-варианты 1..5 → а..д. */
const L = ['а', 'б', 'в', 'г', 'д'];
const mc = (...html) => html.map((h, i) => [L[i], h]);
/* ── 30 заданий ─────────────────────────────────────────────────────────── */
const TASKS = [
// ── Часть A: А1–А10 ──────────────────────────────────────────────────────
{ idx: 1, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1,
text: R`Результатом округления числа $1{,}3678$ до тысячных является число:`,
opts: mc('$0{,}368$', '$1{,}367$', '$1{,}368$', '$1{,}370$', '$1{,}363$'),
answer: 'в',
sol: R`Округляем до третьего знака после запятой: $1{,}3678\approx 1{,}368$.`,
ref: 'Герасимов «Математика, 6 кл.», гл. 1, § 2' },
{ idx: 2, type: 'mc', topic: 'planimetry', subtopic: 'plan-circle', diff: 1,
text: R`Среди отрезков $FP$, $OA$, $NK$, $MA$, $TE$ укажите отрезок, который является хордой окружности, изображённой на рисунке. (Точка $O$ — центр окружности.)`,
opts: mc('$FP$', '$OA$', '$NK$', '$MA$', '$TE$'),
answer: 'г',
sol: R`Хорда — это отрезок, соединяющий две точки окружности. Обе точки $M$ и $A$ лежат на окружности, поэтому хордой является отрезок $MA$.`,
ref: 'Казаков «Геометрия, 7 кл.», гл. 1, § 4',
fig: FIG('a2.png', 'Окружность с центром O и точками E, K, P, F, N, A, T, M') },
{ idx: 3, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 2,
text: R`Укажите номер функции, график которой параллелен графику функции $y=4x+1$.`,
opts: mc('$y=4x-1$', '$y=-4x+1$', '$y=-4x-1$', '$y=x+4$', '$y=-x-4$'),
answer: 'а',
sol: R`Графики линейных функций параллельны, если их угловые коэффициенты равны, а свободные члены различны. У $y=4x+1$ коэффициент $k=4$; из предложенных только $y=4x-1$ имеет $k=4$ и $b=-1\ne 1$.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 3, § 20' },
{ idx: 4, type: 'mc', topic: 'expressions', subtopic: 'expr-polynomials', diff: 2,
text: R`Найдите значения данных выражений при $x=-1{,}1$. Укажите номер того выражения, значение которого является наибольшим.`,
opts: mc('$2x$', '$1-x$', '$|x|$', '$x+1$', '$x^2$'),
answer: 'б',
sol: R`Подставим $x=-1{,}1$: $\ 1)\ 2x=-2{,}2;\quad 2)\ 1-x=2{,}1;\quad 3)\ |x|=1{,}1;\quad 4)\ x+1=-0{,}1;\quad 5)\ x^2=1{,}21.$ Наибольшее значение $2{,}1$у выражения $1-x$.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 4' },
{ idx: 5, type: 'mc', topic: 'equations', subtopic: 'eq-linear', diff: 1,
text: R`Определите, при каком из значений $x$, равных $6;\ 0;\ 1{,}8;\ 4{,}2;\ -1$, верно двойное неравенство $3\le x+1<7$.`,
opts: mc('$6$', '$0$', '$1{,}8$', '$4{,}2$', '$-1$'),
answer: 'г',
sol: R`Неравенство $3\le x+1<7$ равносильно $2\le x<6$. Из данных чисел этому промежутку принадлежит только $x=4{,}2$.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 3, § 18' },
{ idx: 6, type: 'open', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2,
text: R`Укажите номера верных равенств.<br>1) $2^{5/7}:2^{4/7}=2^{1/7}$;<br>2) $2^{1/3}=\dfrac{1}{8}$;<br>3) $2^{1/3}\cdot 2^{2}=2^{2/3}$;<br>4) $\left(2^{1/3}\right)^{2}=2^{1/9}$;<br>5) $2^{1/3}\cdot 5^{1/3}=10^{1/3}$.<br><i>Ответ запишите цифрами в порядке возрастания, без пробелов.</i>`,
answer: '15', ansShow: '1, 5',
sol: R`$1)\ 2^{5/7}:2^{4/7}=2^{5/7-4/7}=2^{1/7}$ — верно. $\ 2)$ неверно. $\ 3)\ 2^{1/3}\cdot 2^{2}=2^{1/3+2}=2^{7/3}\ne 2^{2/3}$ — неверно. $\ 4)\ \left(2^{1/3}\right)^{2}=2^{2/3}\ne 2^{1/9}$ — неверно. $\ 5)\ 2^{1/3}\cdot 5^{1/3}=(2\cdot5)^{1/3}=10^{1/3}$ — верно.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 1, § 1' },
{ idx: 7, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2,
text: R`В состав чайного сбора входят мята и липа в отношении $2:3$ соответственно. Сколько граммов липы входит в $975$ г такого сбора?`,
opts: mc('$390$ г', '$325$ г', '$875$ г', '$545$ г', '$585$ г'),
answer: 'д',
sol: R`Пусть на одну часть приходится $k$ г: мята — $2k$, липа — $3k$. Тогда $2k+3k=975$, $5k=975$, $k=195$. Липа: $3k=585$ г.`,
ref: 'Герасимов «Математика, 6 кл.», гл. 2, § 5' },
{ idx: 8, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2,
text: R`Результат упрощения выражения $\sqrt{(x-3)^{2}}$ при $-1{,}6<x<-1$ имеет вид:`,
opts: mc('$x-6$', '$-x+3$', '$x+3$', '$-x-3$', '$x-3$'),
answer: 'б',
sol: R`По свойству $\sqrt{a^{2}}=|a|$ имеем $\sqrt{(x-3)^{2}}=|x-3|$. При $-1{,}6<x<-1$ выражение $x-3<0$, поэтому $|x-3|=-(x-3)=-x+3$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 3' },
{ idx: 9, type: 'mc', topic: 'stereometry', subtopic: 'ster-basics', diff: 2,
text: R`Прямая $a$ перпендикулярна плоскости $\alpha$ и пересекает её в точке $A$. Точка $B$ находится на расстоянии $2$ от прямой $a$ и на расстоянии $\sqrt{21}$ от плоскости $\alpha$. Найдите расстояние от точки $B$ до точки $A$.`,
opts: mc('$5$', '$\sqrt{17}$', '$2\sqrt{21}$', '$\sqrt{23}$', '$6$'),
answer: 'а',
sol: R`Опустим перпендикуляры: $BK=2$ — на прямую $a$, $BM=\sqrt{21}$ — на плоскость $\alpha$; тогда $AM=BK=2$. В прямоугольном треугольнике $BMA$ по теореме Пифагора $BA^{2}=BM^{2}+AM^{2}=(\sqrt{21})^{2}+2^{2}=25$, значит $BA=5$.`,
ref: 'Латотин «Геометрия, 10 кл.», разд. 3, § 8' },
{ idx: 10, type: 'open', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2,
text: R`Укажите номера выражений, которые имеют смысл.<br>1) $-\sqrt[4]{\sqrt{51}-8}$;<br>2) $\sqrt[3]{-8}$;<br>3) $\sqrt[4]{8^{-1}}$;<br>4) $\sqrt[4]{-8}$;<br>5) $-\sqrt[5]{8^{-1}}$.<br><i>Ответ запишите цифрами в порядке возрастания, без пробелов.</i>`,
answer: '235', ansShow: '2, 3, 5',
sol: R`$1)$ не имеет смысла: $\sqrt{51}-8<0$, а корень чётной степени из отрицательного числа не существует. $\ 2)\ \sqrt[3]{-8}$ — корень нечётной степени, смысл есть. $\ 3)\ \sqrt[4]{8^{-1}}$$8^{-1}=\tfrac18>0$, смысл есть. $\ 4)\ \sqrt[4]{-8}$ — смысла нет. $\ 5)\ -\sqrt[5]{8^{-1}}$ — смысл есть.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 2, § 13' },
// ── Часть B: В1–В20 ──────────────────────────────────────────────────────
{ idx: 11, type: 'open', topic: 'stereometry', subtopic: 'ster-basics', diff: 3,
text: R`Дана правильная четырёхугольная пирамида $SABCD$. Точки $M$ и $N$ — середины боковых рёбер $SA$ и $SC$ соответственно. Выберите верные утверждения.<br>1) прямая $MN$ пересекает прямую $SD$;<br>2) прямая $MN$ пересекает плоскость $SBD$;<br>3) прямая $MN$ лежит в плоскости $SDC$;<br>4) прямая $MN$ параллельна прямой $AB$;<br>5) прямая $MN$ параллельна плоскости $ADC$;<br>6) прямые $MN$ и $CD$ являются скрещивающимися.<br><i>Ответ запишите цифрами в порядке возрастания, без пробелов.</i>`,
answer: '256', ansShow: '2, 5, 6',
sol: R`$1)$ неверно: $MN$ и $SD$ скрещиваются. $\ 2)$ верно: $M$ и $N$ по разные стороны от плоскости $SBD$. $\ 3)$ неверно: $MN$ пересекает $SDC$ в точке $N$. $\ 4)$ неверно: $MN$ и $AB$ скрещиваются. $\ 5)$ верно: $MN$ — средняя линия треугольника $SAC$, значит $MN\parallel AC$, $AC\subset ADC$. $\ 6)$ верно: $MN$ и $CD$ скрещиваются.`,
ref: 'Латотин «Геометрия, 10 кл.», разд. 13' },
{ idx: 12, type: 'long', topic: 'planimetry', subtopic: 'plan-circle', diff: 3,
text: R`Для начала каждого из предложений А–В подберите его окончание 1–7 так, чтобы получилось верное утверждение.<br><b>Начало:</b><br>А) Уравнение окружности с центром в начале координат и радиусом $\sqrt{11}$ имеет вид …<br>Б) Уравнение окружности с центром в начале координат, проходящей через точку $M(-2;5)$, имеет вид …<br>В) Уравнение прямой, проходящей через точки $M(-2;5)$ и $A(2;-5)$, имеет вид …<br><b>Окончание:</b><br>1) $5y-2x=0$;&emsp;2) $x^{2}-y^{2}=29$;&emsp;3) $x^{2}+y^{2}=29$;&emsp;4) $x+y=11$;<br>5) $2y+5x=0$;&emsp;6) $x^{2}+y^{2}=11$;&emsp;7) $x^{2}-y^{2}=11$.<br><i>Ответ запишите сочетанием букв и цифр, например: А1Б1В4.</i>`,
answer: 'А6Б3В5', ansShow: 'А6Б3В5',
sol: R`А) Центр $(0;0)$, радиус $\sqrt{11}$: $x^{2}+y^{2}=11$ — окончание 6. Б) Центр $(0;0)$, проходит через $M(-2;5)$: $R^{2}=(-2)^{2}+5^{2}=29$, то есть $x^{2}+y^{2}=29$ — окончание 3. В) Прямая через $M(-2;5)$ и $A(2;-5)$: подходит $2y+5x=0$ (обе точки ему удовлетворяют) — окончание 5.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 12' },
{ idx: 13, type: 'open', topic: 'numbers', subtopic: 'num-divisibility', diff: 1,
text: R`Фломастеры, которых всего было $445$ штук, упаковывали в коробки по $16$ штук в каждую. Сколько получилось полных коробок, если $13$ фломастеров остались неупакованными?`,
answer: '27',
sol: R`Пусть $x$ — число полных коробок. По смыслу деления с остатком $445=16x+13$, откуда $16x=432$, $x=27$.`,
ref: 'Герасимов «Математика, 5 кл.», ч. 1, гл. 1, § 11' },
{ idx: 14, type: 'open', topic: 'functions', subtopic: 'fn-graphs', diff: 2,
text: R`Найдите значение выражения $4p$, где $p$ — произведение координат вершины параболы, заданной уравнением $y=-2x^{2}-6x+3$.`,
answer: '-45',
sol: R`Абсцисса вершины $x_0=-\dfrac{b}{2a}=-\dfrac{-6}{2\cdot(-2)}=-\dfrac32$. Ордината $y_0=-2\left(-\dfrac32\right)^{2}-6\left(-\dfrac32\right)+3=-\dfrac92+9+3=\dfrac{15}{2}$. Тогда $p=x_0y_0=-\dfrac32\cdot\dfrac{15}{2}=-\dfrac{45}{4}$ и $4p=-45$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 3, § 13' },
{ idx: 15, type: 'open', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2,
text: R`В треугольнике $ABC$ точки $M$ и $N$ — середины сторон $AB$ и $AC$ соответственно, $\angle ABC=95^\circ$, $\angle ANM=36^\circ$. Найдите градусную меру угла $BAC$.`,
answer: '49',
sol: R`$MN$ — средняя линия треугольника $ABC$, поэтому $MN\parallel BC$, и $\angle ACB=\angle ANM=36^\circ$ (соответственные углы). По сумме углов треугольника $\angle BAC=180^\circ-95^\circ-36^\circ=49^\circ$.`,
ref: 'Казаков «Геометрия, 7 кл.», гл. 3, § 17' },
{ idx: 16, type: 'open', topic: 'trigonometry', subtopic: 'trig-identities', diff: 3,
text: R`Найдите значение выражения $6\sqrt3\,\sin 600^\circ-\sqrt2\,\cos 225^\circ$.`,
answer: '-8',
sol: R`$\sin600^\circ=\sin240^\circ=\sin(270^\circ-30^\circ)=-\cos30^\circ=-\dfrac{\sqrt3}{2}$; $\cos225^\circ=\cos(180^\circ+45^\circ)=-\cos45^\circ=-\dfrac{\sqrt2}{2}$. Тогда $6\sqrt3\cdot\left(-\dfrac{\sqrt3}{2}\right)-\sqrt2\cdot\left(-\dfrac{\sqrt2}{2}\right)=-9+1=-8$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 2; § 9' },
{ idx: 17, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 3,
text: R`Найдите произведение наибольшего целого решения на количество всех целых решений неравенства $\left(x+\log_{0{,}5}64\right)^{2}(x-3)(x+13)\le 0$.`,
answer: '108',
sol: R`Так как $\log_{0{,}5}64=-6$, неравенство принимает вид $(x-6)^{2}(x-3)(x+13)\le 0$. Методом интервалов решение: $[-13;3]\cup\{6\}$. Наибольшее целое решение $6$; всего целых решений $18$ (17 на отрезке $[-13;3]$ и $x=6$). Произведение: $6\cdot18=108$.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 13' },
{ idx: 18, type: 'open', topic: 'equations', subtopic: 'eq-linear', diff: 2,
text: R`Найдите сумму всех целых решений системы неравенств $\begin{cases}(x-2)^{2}+23>(x+3)^{2}-2,\\[2pt] 1{,}6x\ge 0{,}9x-6{,}3.\end{cases}$`,
answer: '-44',
sol: R`Первое неравенство: $x^{2}-4x+4+23>x^{2}+6x+9-2$, то есть $-10x>-20$, $x<2$. Второе: $0{,}7x\ge-6{,}3$, $x\ge-9$. Решение системы — полуинтервал $[-9;2)$. Сумма всех целых из него равна $-44$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 6' },
{ idx: 19, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 3,
text: R`Функция $y=f(x)$ нечётна и определена на отрезке $[-8;8]$. Её график для $x\le 0$ изображён на рисунке. Найдите значение выражения $3n$, где $n$ — количество всех целых значений аргумента, при которых функция принимает неположительные значения.`,
answer: '30',
sol: R`График нечётной функции симметричен относительно начала координат. Функция неположительна ($f(x)\le0$) на промежутках $[-8;-6]$ и $(0;6)$, а также в точках $x=-6,\ 0,\ 6$. Целых значений с $f(x)<0$ — семь, плюс три нуля, итого $n=10$, значит $3n=30$.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 2, § 8',
fig: FIG('b9.png', 'График нечётной функции для x ≤ 0 на отрезке [-8;0]') },
{ idx: 20, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 2,
text: R`Найдите площадь ромба $ABCD$, если его периметр равен $72$, а величина угла $BAD$ равна $30^\circ$.`,
answer: '162',
sol: R`Сторона ромба $a=\dfrac{72}{4}=18$. Площадь $S=a^{2}\sin\alpha=18^{2}\cdot\sin30^\circ=324\cdot\dfrac12=162$.`,
ref: 'Казаков «Геометрия, 8 кл.», гл. 2, § 15' },
{ idx: 21, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 3,
text: R`Найдите значение выражения $25m$, где $m$ — сумма корней уравнения $\left(\dfrac37\right)^{5x^{2}-5x+2}-\left(\dfrac73\right)^{1-3x}=0$.`,
answer: '40',
sol: R`Так как $\left(\dfrac73\right)^{1-3x}=\left(\dfrac37\right)^{3x-1}$, получаем $5x^{2}-5x+2=3x-1$, то есть $5x^{2}-8x+3=0$. Дискриминант положителен, корни существуют. По теореме Виета сумма корней $m=\dfrac{8}{5}=1{,}6$, поэтому $25m=40$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 2, § 5' },
{ idx: 22, type: 'open', topic: 'equations', subtopic: 'eq-linear', diff: 2,
text: R`Поле разбили на два участка $A$ и $B$ одинаковой площади, как показано на рисунке (размеры указаны в метрах). Найдите (в метрах) периметр участка $B$.`,
answer: '390',
sol: R`Обозначим горизонтальный размер участка $B$ через $x$ м. Из равенства площадей: $140\cdot40+70\cdot(170-x)=70x$, откуда $14x=1750$, $x=125$. Значит, участок $B$ — прямоугольник $70\times125$, его периметр $2(70+125)=390$ м.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 3, § 16',
fig: FIG('b12.png', 'L-образный участок: A и B, размеры 170, 70, 210, 40 м') },
{ idx: 23, type: 'open', topic: 'stereometry', subtopic: 'ster-rotation', diff: 3,
text: R`Осевым сечением цилиндра является квадрат, длина диагонали которого равна $4\sqrt6$. Найдите значение выражения $\dfrac{\sqrt3\,V}{\pi}$, где $V$ — объём цилиндра.`,
answer: '144',
sol: R`Сторона квадрата $\dfrac{4\sqrt6}{\sqrt2}=4\sqrt3$, значит высота цилиндра и диаметр основания равны $4\sqrt3$, радиус $R=2\sqrt3$. Объём $V=\pi R^{2}h=\pi(2\sqrt3)^{2}\cdot4\sqrt3=48\pi\sqrt3$. Тогда $\dfrac{\sqrt3\,V}{\pi}=48\cdot3=144$.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 1, § 2' },
{ idx: 24, type: 'open', topic: 'equations', subtopic: 'eq-irrational', diff: 3,
text: R`Найдите произведение корней (корень, если он единственный) уравнения $\sqrt{x+7}-\sqrt{x^{2}-6x-91}=0$.`,
answer: '-98',
sol: R`Так как $x^{2}-6x-91=(x+7)(x-13)$, уравнение приводится к $\sqrt{x+7}=\sqrt{(x+7)(x-13)}$. После возведения в квадрат $(x+7)(x-14)=0$. Проверка показывает, что оба числа $-7$ и $14$ — корни. Их произведение $-7\cdot14=-98$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 2, § 17' },
{ idx: 25, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 4,
text: R`Найдите (в градусах) сумму наименьшего положительного и наибольшего отрицательного корней уравнения $\sin 2x\cos 17x-\cos 2x\sin 17x=\sin\dfrac{3\pi}{2}$.`,
answer: '-12',
sol: R`Левая часть по формуле синуса разности равна $\sin(2x-17x)=\sin(-15x)$, а $\sin\dfrac{3\pi}{2}=-1$. Значит $\sin(-15x)=-1$, то есть $\sin15x=1$, $15x=90^\circ+360^\circ n$, $x=6^\circ+24^\circ n$. Наименьший положительный корень $6^\circ$, наибольший отрицательный $-18^\circ$; их сумма $-12^\circ$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 8; § 10' },
{ idx: 26, type: 'open', topic: 'equations', subtopic: 'eq-quadratic', diff: 3,
text: R`Найдите сумму всех целых решений совокупности неравенств $\left[\begin{array}{l}x^{2}-x-6\le0,\\ x^{2}-4x-5>0\end{array}\right.$ на промежутке $[-10;7]$.`,
answer: '-36',
sol: R`$1)\ x^{2}-x-6\le0$: решение $[-2;3]$. $\ 2)\ x^{2}-4x-5>0$: решение $(-\infty;-1)\cup(5;+\infty)$. Объединение решений совокупности: $(-\infty;3]\cup(5;+\infty)$. Пересечение с $[-10;7]$ даёт $[-10;3]\cup(5;7]$. Сумма целых: $-49+13=-36$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 3, § 16' },
{ idx: 27, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 4,
text: R`В правильной четырёхугольной пирамиде $QABCD$ длина бокового ребра равна $17$, длина диагонали основания $ABCD$ равна $16$. Через середины рёбер $AB$ и $AD$ и точку $Q$ проведена секущая плоскость. Найдите значение выражения $S^{2}$, где $S$ — площадь сечения пирамиды этой плоскостью.`,
answer: '3856',
sol: R`Пусть $K$, $M$ — середины рёбер $AB$, $AD$; сечение — равнобедренный треугольник $KQM$. $KM$ — средняя линия треугольника $ABD$, $KM=\dfrac12 BD=8$. Высота пирамиды $QO=\sqrt{QA^{2}-OA^{2}}=\sqrt{17^{2}-8^{2}}=15$. Высота $QN$ треугольника $KQM$: $QN=\sqrt{QO^{2}+ON^{2}}=\sqrt{15^{2}+4^{2}}=\sqrt{241}$. Площадь $S=\dfrac12\cdot KM\cdot QN=4\sqrt{241}$, откуда $S^{2}=16\cdot241=3856$.`,
ref: 'Латотин «Геометрия, 10 кл.», разд. 1, § 3' },
{ idx: 28, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 4,
text: R`При делении некоторого натурального двузначного числа на произведение его цифр неполное частное равно $3$, а остаток равен $10$. Если цифры этого числа поменять местами, то полученное число будет меньше данного на $36$. Найдите исходное число.`,
answer: '73',
sol: R`Пусть $x$ — цифра десятков, $y$ — цифра единиц; число равно $10x+y$. Условия дают систему $\begin{cases}10x+y=3xy+10,\\ 10x+y=(10y+x)+36.\end{cases}$ Из второго уравнения $x-y=4$. Подставив $x=y+4$, получаем $3y^{2}+y-30=0$, откуда $y=3$, $x=7$. Искомое число — $73$.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 11' },
{ idx: 29, type: 'open', topic: 'functions', subtopic: 'fn-derivative', diff: 4,
text: R`Составьте уравнение касательной к графику функции $f(x)=32x^{3}-24x-5$ в точке с абсциссой $x_0=\dfrac14$. В ответ запишите произведение координат точки пересечения этой касательной с прямой $y=-16x-10$.`,
answer: '-84',
sol: R`$f'(x)=96x^{2}-24$, $f'\!\left(\dfrac14\right)=-18=k$; $f\!\left(\dfrac14\right)=-10{,}5$. Касательная $y=-18x-6$. Пересечение с $y=-16x-10$: $-18x-6=-16x-10$, $x=2$, $y=-42$. Произведение координат $2\cdot(-42)=-84$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 3, § 20' },
{ idx: 30, type: 'open', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 5,
text: R`Из точки $E$ — середины стороны $BC$ равностороннего треугольника $ABC$ — проведён перпендикуляр $EP$ к плоскости треугольника, причём $EP=\dfrac12 BC$. На отрезке $PC$ взята точка $M$ так, что $PM:MC=2:3$. Найдите значение выражения $176\sin^{2}\alpha$, где $\alpha$ — угол между прямой $AM$ и плоскостью $ABC$.`,
answer: '18',
sol: R`Пусть сторона равна $a$, тогда $EP=\dfrac a2$. Проекция $M$ на плоскость — точка $K$ на $EC$, $\angle MAK=\alpha$. Из подобия $\triangle MKC\sim\triangle PEC$: $MK=\dfrac{3a}{10}$, $CK=\dfrac{3a}{10}$. По теореме косинусов в $\triangle AKC$: $AK^{2}=a^{2}+\left(\dfrac{3a}{10}\right)^{2}-2a\cdot\dfrac{3a}{10}\cos60^\circ=\dfrac{79a^{2}}{100}$. Тогда $AM^{2}=MK^{2}+AK^{2}=\dfrac{88a^{2}}{100}$, $\sin\alpha=\dfrac{MK}{AM}=\dfrac{3}{2\sqrt{22}}$, и $176\sin^{2}\alpha=176\cdot\dfrac{9}{88}=18$.`,
ref: 'Латотин «Геометрия, 10 кл.», разд. 3, § 9' },
];
/* ── Сборка solution_html ────────────────────────────────────────────────── */
function ansShowOf(t) {
if (t.ansShow != null) return t.ansShow;
if (t.type === 'mc') return `${t.answer})`;
return `$${t.answer}$`; // числовой/комбинация цифр — в KaTeX
}
function buildSolution(t) {
const ans = ansShowOf(t);
let html = `${t.sol}<div class="sol-ans">Ответ: ${ans}</div>`;
if (t.ref) html += `<div class="sol-ref" style="margin-top:6px;font-size:.85em;opacity:.7">Учебник: ${t.ref}</div>`;
return html;
}
/* ── Самопроверка (повтор логики checkAnswerServer из exam-prep.js) ────────── */
const EPS = 1e-6;
function srvToNumber(s) {
if (s == null) return NaN;
let t = String(s).trim().replace(/\$/g, '').replace(/\s+/g, '').replace(',', '.');
const f = t.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(-?\d+(?:\.\d+)?)$/);
if (f) { const n = Number(f[1]), d = Number(f[2]); return d === 0 ? NaN : n / d; }
const n = Number(t); return Number.isFinite(n) ? n : NaN;
}
function checkAnswerServer(userInput, canonical) {
if (userInput == null || canonical == null) return false;
const c = String(canonical).trim();
if (/^[а-д]$/.test(c)) return String(userInput).trim().toLowerCase() === c.toLowerCase();
if (/^[^;]+;[^;]+$/.test(c)) return false; // (пар нет в этом варианте)
const cn = srvToNumber(c), un = srvToNumber(userInput);
if (Number.isNaN(cn) || Number.isNaN(un)) return false;
return Math.abs(cn - un) < EPS;
}
/* ── Валидация набора ──────────────────────────────────────────────────────── */
const problems = [];
if (TASKS.length !== 30) problems.push(`Ожидалось 30 заданий, получено ${TASKS.length}`);
const seen = new Set();
for (const t of TASKS) {
if (seen.has(t.idx)) problems.push(`Дубль task_idx=${t.idx}`); seen.add(t.idx);
if (t.idx < 1 || t.idx > 30) problems.push(`task_idx вне 1..30: ${t.idx}`);
if (!['mc', 'open', 'long'].includes(t.type)) problems.push(`#${t.idx}: тип ${t.type}`);
if (t.type === 'mc') {
if (!Array.isArray(t.opts) || t.opts.length !== 5) problems.push(`#${t.idx}: mc должен иметь 5 вариантов`);
if (!t.opts.some(o => o[0] === t.answer)) problems.push(`#${t.idx}: answer "${t.answer}" не среди меток`);
}
if (!t.text || !t.sol) problems.push(`#${t.idx}: пустой text/sol`);
// self-check автопроверки (long не автопроверяется)
if (t.type !== 'long' && !checkAnswerServer(t.answer, t.answer))
problems.push(`#${t.idx}: answer "${t.answer}" не проходит self-check (Unicode-минус? пробел?)`);
// запрет Unicode-минуса в answer (нужен ASCII '-')
if (//.test(String(t.answer))) problems.push(`#${t.idx}: Unicode-минус в answer`);
}
/* ── Экспорт для тестов/тиража (без запуска main при require) ──────────────── */
module.exports = { TASKS, buildSolution, ansShowOf, checkAnswerServer, EXAM, VARIANT, PROV };
if (require.main !== module) return;
/* ── Открытие БД ───────────────────────────────────────────────────────────── */
const DB = path.join(__dirname, '..', 'data', 'learnspace.db');
const db = new DatabaseSync(DB);
// Защита: трек должен существовать
const track = db.prepare(`SELECT exam_key, variants_count FROM exam_tracks WHERE exam_key=?`).get(EXAM);
if (!track) { console.error(`✗ Трек '${EXAM}' не найден в exam_tracks. Прерывание.`); process.exit(1); }
/* ── DRY-RUN сводка ────────────────────────────────────────────────────────── */
console.log(`\n=== seed_ctmath_rt2425_e1v1 (${PROV}) variant=${VARIANT} ===`);
console.log(`Режим: ${APPLY ? 'APPLY (запись)' : 'DRY-RUN (только проверка)'}\n`);
const byType = TASKS.reduce((a, t) => (a[t.type] = (a[t.type] || 0) + 1, a), {});
console.log('Типы:', JSON.stringify(byType), '| фигур:', TASKS.filter(t => t.fig).length, '\n');
console.log('idx | type | subtopic | d | answer | fig');
console.log('----+------+-----------------------+---+-----------+----');
for (const t of TASKS) {
console.log(
`${String(t.idx).padStart(3)} | ${t.type.padEnd(4)} | ${String(t.subtopic).padEnd(21)} | ${t.diff} | ${String(t.answer).padEnd(9)} | ${t.fig ? '✓' : ''}`
);
}
if (problems.length) {
console.error(`\n✗ ПРОБЛЕМЫ (${problems.length}):`);
problems.forEach(p => console.error(' - ' + p));
console.error('\nЗапись отменена из-за ошибок валидации.');
db.close();
process.exit(1);
}
console.log('\n✓ Валидация и self-check ответов пройдены (30/30).');
/* ── APPLY: upsert ─────────────────────────────────────────────────────────── */
if (!APPLY) {
console.log('\nDRY-RUN: ничего не записано. Для записи: node backend/scripts/seed_ctmath_rt2425_e1v1.js --apply\n');
db.close();
process.exit(0);
}
const upsert = db.prepare(`
INSERT INTO exam_tasks
(exam_key, variant, task_idx, task_type, text_html, figure_html,
opts_json, answer, solution_html, topic, subtopic, difficulty)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(exam_key, variant, task_idx) DO UPDATE SET
task_type = excluded.task_type,
text_html = excluded.text_html,
figure_html = excluded.figure_html,
opts_json = excluded.opts_json,
answer = excluded.answer,
solution_html = excluded.solution_html,
topic = excluded.topic,
subtopic = excluded.subtopic,
difficulty = excluded.difficulty
`);
let n = 0;
db.exec('BEGIN');
try {
for (const t of TASKS) {
upsert.run(
EXAM, VARIANT, t.idx, t.type,
t.text,
t.fig || null,
t.type === 'mc' ? JSON.stringify(t.opts) : null,
t.answer,
buildSolution(t),
t.topic, t.subtopic, t.diff
);
n++;
}
// variants_count = число «чистых» вариантов-пробников [101;1999]; год-пачки (годы≥2011, 0) скрыты роутом
const distinct = db.prepare(`SELECT COUNT(DISTINCT variant) c FROM exam_tasks WHERE exam_key=? AND variant BETWEEN 101 AND 1999`).get(EXAM).c;
db.prepare(`UPDATE exam_tracks SET variants_count=? WHERE exam_key=?`).run(distinct, EXAM);
db.exec('COMMIT');
console.log(`\n✓ Записано/обновлено ${n} заданий (variant=${VARIANT}).`);
console.log(`✓ exam_tracks.variants_count = ${distinct} (различных вариантов).`);
console.log(`\nПробник доступен: /exam-prep/ctmath → «Варианты» → «Вариант ${VARIANT}».\n`);
} catch (e) {
db.exec('ROLLBACK');
console.error('\n✗ Ошибка записи, откат транзакции:', e.message);
process.exitCode = 1;
}
db.close();
+298
View File
@@ -0,0 +1,298 @@
'use strict';
/* ───────────────────────────────────────────────────────────────────────────
seed_ctmath_rt2425_e2v1.js — РТ–2024/2025, Этап II, Вариант 1 → variant=102
Чистый 30-задачный пробник (А1–А10 + В1–В20). Этап II — другой набор тем, чем
Этап I (позже по программе: обратные тригфункции, логарифмы, производная,
стереометрия). Перенабрано вручную в KaTeX по PDF
(…\РТ\2024-2025\МАТ РТ-2 24_25 В1.pdf); чертежи вырезаны из PDF.
Правило тиража: 1 вариант на Этап (В1/В2 одного этапа — дубли, берём один).
Запуск: node backend/scripts/seed_ctmath_rt2425_e2v1.js [--apply]
Контракт формата/проверок — см. seed_ctmath_rt2425_e1v1.js.
─────────────────────────────────────────────────────────────────────────── */
const { DatabaseSync } = require('node:sqlite');
const path = require('path');
const APPLY = process.argv.includes('--apply');
const EXAM = 'ctmath';
const VARIANT = 102;
const PROV = 'РТ–2024/2025, Этап II, Вариант 1';
const FIGDIR = 'rt2425_e2v1';
const R = String.raw;
const FIG = (name, alt) =>
`<img src="/img/ct/math/${FIGDIR}/${name}" alt="${alt}" ` +
`style="max-width:300px;width:100%;height:auto;display:block;margin:10px auto;` +
`background:#fff;border-radius:8px;padding:6px;">`;
const L = ['а', 'б', 'в', 'г', 'д'];
const mc = (...html) => html.map((h, i) => [L[i], h]);
const TASKS = [
// ── Часть A ──────────────────────────────────────────────────────────────
{ idx: 1, type: 'mc', topic: 'numbers', subtopic: 'num-divisibility', diff: 1,
text: R`Юра и Ян собирали яблоки. Юра собрал яблок в $4$ раза больше, чем Ян. Какую часть всех собранных яблок собрал Ян?`,
opts: mc('$\dfrac45$', '$\dfrac15$', '$\dfrac13$', '$\dfrac14$', '$\dfrac34$'),
answer: 'б',
sol: R`Ян собрал в $4$ раза меньше Юры, поэтому всё количество яблок делится на $4+1=5$ равных частей, и Ян собрал одну из них, то есть $\dfrac15$.`,
ref: 'Герасимов «Математика, 5 кл.», ч. 2, гл. 3, § 1' },
{ idx: 2, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2,
text: R`Используя данные рисунка, определите, чему должна быть равна градусная мера угла $1$, чтобы прямые $a$ и $b$ были параллельны.`,
opts: mc('$68^\circ$', '$48^\circ$', '$46^\circ$', '$36^\circ$', '$44^\circ$'),
answer: 'д',
sol: R`Угол $2$, смежный с углом $136^\circ$, равен $44^\circ$. Прямые $a$ и $b$ параллельны, если соответственные углы $1$ и $2$ при секущей $c$ равны, поэтому $\angle 1=44^\circ$.`,
ref: 'Казаков «Геометрия, 7 кл.», гл. 3, § 15',
fig: FIG('a2.png', 'Прямые a и b, секущая c; угол 1 и угол 136°') },
{ idx: 3, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 1,
text: R`Укажите номер рисунка, на котором изображён график функции $y=|x|$.`,
opts: mc('$1$', '$2$', '$3$', '$4$', '$5$'),
answer: 'в',
sol: R`График функции $y=|x|$ — это «уголок» с вершиной в начале координат (ветви $y=x$ при $x\ge0$ и $y=-x$ при $x<0$). Ему соответствует рисунок $3$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 4, § 19',
fig: FIG('a3.png', 'Пять графиков-кандидатов 1–5; график 3 — «уголок» y=|x|') },
{ idx: 4, type: 'mc', topic: 'expressions', subtopic: 'expr-polynomials', diff: 1,
text: R`Среди значений переменной $x$, равных $16;\ -1;\ 1;\ -4;\ -15$, укажите то, при котором значение выражения $0{,}36-x^2$ равно $-15{,}64$.`,
opts: mc('$16$', '$-1$', '$1$', '$-4$', '$-15$'),
answer: 'г',
sol: R`Проверяем: при $x=-4$ имеем $0{,}36-(-4)^2=0{,}36-16=-15{,}64$. Остальные значения дают другой результат.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 4' },
{ idx: 5, type: 'mc', topic: 'equations', subtopic: 'eq-linear', diff: 2,
text: R`Укажите номер, под которым приведено множество всех решений системы неравенств $\begin{cases}x\le 6,\\ x<-4.\end{cases}$`,
opts: mc('$(-\infty;-4)$', '$(-\infty;6]$', '$(-4;6]$', '$(-\infty;6)$', '$(-\infty;-4)\cup(-4;6]$'),
answer: 'а',
sol: R`Решение первого неравенства — луч $(-\infty;6]$, второго — открытый луч $(-\infty;-4)$. Пересечением является $(-\infty;-4)$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 6' },
{ idx: 6, type: 'open', topic: 'numbers', subtopic: 'num-real', diff: 2,
text: R`Среди выражений $\log_{\sqrt2}4$; $\ -5^2$; $\ \cos\dfrac{5\pi}{6}$; $\ 7^{-1}$; $\ \sqrt[5]{(-2)^5}$ укажите те, значение которых является отрицательным числом.<br><i>Ответ запишите номерами в порядке возрастания, без пробелов.</i>`,
answer: '235', ansShow: '2, 3, 5',
sol: R`$1)\ \log_{\sqrt2}4=4>0$. $\ 2)\ -5^2=-25<0$. $\ 3)\ \cos\dfrac{5\pi}{6}=-\dfrac{\sqrt3}{2}<0$. $\ 4)\ 7^{-1}=\dfrac17>0$. $\ 5)\ \sqrt[5]{(-2)^5}=-2<0$. Отрицательны выражения 2, 3, 5.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 1, § 3' },
{ idx: 7, type: 'mc', topic: 'expressions', subtopic: 'expr-polynomials', diff: 2,
text: R`Результат разложения многочлена $(a-b)+2c(b-a)$ на множители имеет вид:`,
opts: mc('$(a-b)(1+2c)$', '$(a-b)(2c-1)$', '$(a-b)(1-2c)$', '$-2c(a-b)$', '$2c(a-b)$'),
answer: 'в',
sol: R`$(a-b)+2c(b-a)=(a-b)-2c(a-b)=(a-b)(1-2c)$.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 14' },
{ idx: 8, type: 'mc', topic: 'equations', subtopic: 'eq-linear', diff: 2,
text: R`Укажите номер неравенства, которое равносильно неравенству $x>5$.`,
opts: mc('$x^2>5x$', '$\dfrac{1}{x-5}<0$', '$(x-5)^2>0$', '$-2x<-10$', '$(0{,}5)^{x-5}>0$'),
answer: 'г',
sol: R`Решение $x>5$ — луч $(5;+\infty)$. Неравенство $-2x<-10$ равносильно $x>5$ — то же множество решений. (Остальные дают другие множества.)`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 13' },
{ idx: 9, type: 'mc', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 2,
text: R`У правильной четырёхугольной призмы площадь основания равна $28$ см$^2$. Какой должна быть высота (в сантиметрах) этой призмы, чтобы её объём был равен $98$ см$^3$?`,
opts: mc('$2$', '$4$', '$3{,}2$', '$4{,}5$', '$3{,}5$'),
answer: 'д',
sol: R`Объём призмы $V=S_{\text{осн}}\cdot h$. Тогда $98=28h$, откуда $h=3{,}5$ см.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 1, § 1' },
{ idx: 10, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 3,
text: R`На рисунке изображён график функции $y=f(x)$, определённой на промежутке $[-6;6]$. Укажите номера верных утверждений.<br>1) множеством значений функции является отрезок $[-3;4]$;<br>2) функция является нечётной;<br>3) график функции $y=f(x-1)$ проходит через точку $(0;2)$;<br>4) функция убывает на промежутках $[-1;0]$ и $[1;6]$;<br>5) $f(-5)+f(2)<0$.<br><i>Ответ запишите номерами в порядке возрастания, без пробелов.</i>`,
answer: '14', ansShow: '1, 4',
sol: R`$1)$ верно: $E(f)=[-3;4]$. $\ 2)$ неверно: график симметричен относительно оси ординат, функция чётная. $\ 3)$ неверно: точка $(0;2)$ не принадлежит графику $y=f(x-1)$. $\ 4)$ верно: на $[-1;0]$ и $[1;6]$ значения убывают. $\ 5)$ неверно: $-2<f(-5)<-1$ и $2<f(2)<3$, поэтому $f(-5)+f(2)>0$.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 2, § 69',
fig: FIG('a10.png', 'График чётной функции y=f(x) на [-6;6], с пиками y=4 и краями y=-3') },
// ── Часть B ──────────────────────────────────────────────────────────────
{ idx: 11, type: 'long', topic: 'trigonometry', subtopic: 'trig-identities', diff: 3,
text: R`Для начала каждого из предложений А–В подберите его окончание 1–6 так, чтобы получилось верное утверждение.<br><b>Начало:</b><br>А) Значение выражения $\arcsin 0-|-5|$ равно …<br>Б) Значение выражения $\dfrac1\pi\arccos\left(-\dfrac{\sqrt3}{2}\right)-\dfrac13$ равно …<br>В) Значение выражения $4\sqrt6\,\sin\left(2\arccos\dfrac{\sqrt2}{2}-\dfrac\pi4\right)$ равно …<br><b>Окончание:</b><br>1) $6\sqrt2$;&emsp;2) $-5$;&emsp;3) $\dfrac13$;&emsp;4) $-4$;&emsp;5) $4\sqrt3$;&emsp;6) $\dfrac12$.<br><i>Ответ запишите сочетанием букв и цифр, например: А1Б1В4.</i>`,
answer: 'А2Б6В5', ansShow: 'А2Б6В5',
sol: R`А) $\arcsin0-|-5|=0-5=-5$ — окончание 2. Б) $\dfrac1\pi\cdot\dfrac{5\pi}{6}-\dfrac13=\dfrac56-\dfrac13=\dfrac12$ — окончание 6. В) $4\sqrt6\,\sin\left(2\cdot\dfrac\pi4-\dfrac\pi4\right)=4\sqrt6\sin\dfrac\pi4=4\sqrt6\cdot\dfrac{\sqrt2}{2}=4\sqrt3$ — окончание 5.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 7' },
{ idx: 12, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 3,
text: R`$ABCDA_1B_1C_1D_1$ — куб. Длина пространственной ломаной $ABB_1C_1C$ равна $16\sqrt3$. Выберите верные утверждения.<br>1) длина диагонали грани $ABCD$ равна $4\sqrt3$;<br>2) площадь полной поверхности куба равна $192$;<br>3) длина диагонали куба равна $4\sqrt6$;<br>4) площадь треугольника $AC_1C$ равна $24\sqrt2$;<br>5) длина ребра куба равна $4\sqrt3$;<br>6) объём куба равен $192\sqrt3$.<br><i>Ответ запишите номерами в порядке возрастания, без пробелов.</i>`,
answer: '456', ansShow: '4, 5, 6',
sol: R`Ломаная $ABB_1C_1C$ состоит из четырёх рёбер: $16\sqrt3:4=4\sqrt3$ — ребро. $\ 1)$ диагональ грани $=4\sqrt3\cdot\sqrt2=4\sqrt6$ — неверно. $\ 2)\ S=6a^2=6\cdot48=288$ — неверно. $\ 3)$ диагональ куба $=a\sqrt3=4\sqrt3\cdot\sqrt3=12$ — неверно. $\ 4)\ S_{AC_1C}=\tfrac12\cdot4\sqrt6\cdot4\sqrt3=24\sqrt2$ — верно. $\ 5)$ ребро $=4\sqrt3$ — верно. $\ 6)\ V=a^3=(4\sqrt3)^3=192\sqrt3$ — верно.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 1, § 1' },
{ idx: 13, type: 'open', topic: 'trigonometry', subtopic: 'trig-identities', diff: 3,
text: R`Найдите значение выражения $15\sqrt{10}\,\operatorname{tg}\alpha$, если $\operatorname{ctg}\alpha=-\dfrac{\sqrt{10}}{8}$.`,
answer: '-120',
sol: R`Из тождества $\operatorname{tg}\alpha\cdot\operatorname{ctg}\alpha=1$: $\operatorname{tg}\alpha=\dfrac1{\operatorname{ctg}\alpha}=-\dfrac{8}{\sqrt{10}}=-\dfrac{4\sqrt{10}}{5}$. Тогда $15\sqrt{10}\cdot\left(-\dfrac{4\sqrt{10}}{5}\right)=15\cdot\left(-\dfrac{4\cdot10}{5}\right)=-120$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 4' },
{ idx: 14, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 2,
text: R`Диагонали ромба равны $4$ и $10$. Найдите значение выражения $\sqrt{29}\cdot P$, где $P$ — периметр ромба.`,
answer: '116',
sol: R`Диагонали ромба перпендикулярны и делятся точкой пересечения пополам. Сторона $a=\sqrt{2^2+5^2}=\sqrt{29}$. Периметр $P=4\sqrt{29}$, тогда $\sqrt{29}\cdot P=\sqrt{29}\cdot4\sqrt{29}=4\cdot29=116$.`,
ref: 'Казаков «Геометрия, 8 кл.», гл. 1, § 5' },
{ idx: 15, type: 'open', topic: 'numbers', subtopic: 'num-divisibility', diff: 3,
text: R`Пусть $A$ — наименьшее натуральное число, большее $50$, при делении которого на $9$ и на $12$ получается остаток $1$. Найдите остаток при делении числа $A$ на $13$. В ответ запишите сумму числа $A$ и полученного остатка.`,
answer: '81',
sol: R`$A-1$ делится и на $9$, и на $12$, то есть кратно $\text{НОК}(9;12)=36$. Наименьшее такое $A-1>49$ равно $72$, значит $A=73$. Остаток от деления $73$ на $13$ равен $8$. Сумма $73+8=81$.`,
ref: 'Герасимов «Математика, 5 кл.», ч. 1, гл. 1, § 1113' },
{ idx: 16, type: 'open', topic: 'word-sequences', subtopic: 'seq-progressions', diff: 3,
text: R`Найдите, при каком значении переменной $x$ значения выражений $x-18$; $\ x-3$; $\ x+17$ будут последовательными членами геометрической прогрессии.`,
answer: '63',
sol: R`По характеристическому свойству геометрической прогрессии $(x-3)^2=(x-18)(x+17)$. Раскрывая: $x^2-6x+9=x^2-x-306$, $-5x=-315$, $x=63$.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 4, § 17' },
{ idx: 17, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 4,
text: R`Пусть $(x_1;y_1)$ и $(x_2;y_2)$ — решения системы уравнений $\begin{cases}x^2+3y=27,\\ x-y=-9.\end{cases}$ Найдите значение выражения $x_1x_2-y_1y_2$.`,
answer: '-54',
sol: R`Из второго уравнения $y=x+9$. Тогда $x^2+3(x+9)=27$, $x^2+3x=0$, $x=0$ или $x=-3$. Решения: $(-3;6)$ и $(0;9)$. Значение $x_1x_2-y_1y_2=(-3)\cdot0-6\cdot9=-54$ (не зависит от выбора нумерации пар).`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 11' },
{ idx: 18, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 3,
text: R`Аппликация состоит из двух подобных треугольников $\mathrm{I}$ и $\mathrm{II}$. Площадь треугольника $\mathrm{I}$ равна $75$ см$^2$, а длины сторон треугольника $\mathrm{II}$ на $20\%$ больше длин соответствующих сторон треугольника $\mathrm{I}$. Найдите (в см$^2$) площадь всей аппликации.`,
answer: '183',
sol: R`Коэффициент подобия (II к I) равен $1{,}2=\dfrac65$. Отношение площадей подобных треугольников равно квадрату коэффициента: $S_{\mathrm{II}}=75\cdot\left(\dfrac65\right)^2=75\cdot\dfrac{36}{25}=108$ см$^2$. Площадь всей аппликации $75+108=183$ см$^2$.`,
ref: 'Казаков «Геометрия, 8 кл.», гл. 3, § 23' },
{ idx: 19, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 3,
text: R`Найдите значение выражения $2\log_{25}\left(\dfrac{a}{125}\right)-\log_5\dfrac{25}{b}$, если $\log_{25}(ab)=19$.`,
answer: '33',
sol: R`$2\log_{25}\left(\dfrac{a}{125}\right)=\log_5\dfrac{a}{125}$. Тогда выражение равно $\log_5\dfrac{a}{125}-\log_5\dfrac{25}{b}=\log_5\dfrac{ab}{5^5}=\log_5(ab)-5=2\log_{25}(ab)-5=2\cdot19-5=33$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 3, § 7' },
{ idx: 20, type: 'open', topic: 'planimetry', subtopic: 'plan-triangles', diff: 4,
text: R`В равнобедренном треугольнике $KMN$ проведена высота $MH$ к основанию $KN$. Точка $P$ — середина боковой стороны $MN$. Известно, что длина высоты $MH$ равна длине отрезка $HP$ и $KN=6\sqrt6$. Найдите значение выражения $S^2$, где $S$ — площадь треугольника $KMN$.`,
answer: '972',
sol: R`Высота $MH$ равнобедренного треугольника является и медианой, поэтому $HN=\tfrac12 KN=3\sqrt6$. В прямоугольном треугольнике $MHN$ отрезок $HP$ — медиана к гипотенузе $MN$, значит $HP=\tfrac12 MN$; по условию $MH=HP=\tfrac12 MN$, то есть катет $MH$ равен половине гипотенузы, и $\angle MNH=30^\circ$. Тогда $MH=HN\operatorname{tg}30^\circ=3\sqrt6\cdot\dfrac{\sqrt3}{3}=3\sqrt2$. Площадь $S=\tfrac12\cdot KN\cdot MH=\tfrac12\cdot6\sqrt6\cdot3\sqrt2=18\sqrt3$, откуда $S^2=972$.`,
ref: 'Казаков «Геометрия, 8 кл.», гл. 2, § 1516' },
{ idx: 21, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 3,
text: R`Найдите количество всех целых чисел из множества значений функции $y=\left(\dfrac13\right)^{-x}$ на отрезке $[3;4]$.`,
answer: '55',
sol: R`$y=\left(\dfrac13\right)^{-x}=3^x$ — возрастающая функция. При $3\le x\le4$ имеем $3^3\le 3^x\le 3^4$, то есть $E=[27;81]$. Целых чисел на отрезке $[27;81]$$81-27+1=55$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 2, § 4' },
{ idx: 22, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 3,
text: R`Первый турист ехал от базы со скоростью $40$ км/ч и успел на станцию за $3$ мин до отправления поезда. Второй турист, выехавший одновременно с первым от той же базы со скоростью $35$ км/ч, опоздал на этот же поезд на $3$ мин. На каком расстоянии (в километрах) от базы находится станция?`,
answer: '28',
sol: R`Пусть расстояние равно $x$ км. Разница во времени между туристами составляет $6$ мин $=\dfrac1{10}$ ч: $\dfrac{x}{35}-\dfrac{x}{40}=\dfrac1{10}$, $\dfrac{x}{280}=\dfrac1{10}$, $x=28$ км.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 3, § 16; гл. 4, § 25' },
{ idx: 23, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 4,
text: R`Найдите произведение наименьшего целого решения на количество всех целых решений неравенства $\log_{0{,}4}\left(\dfrac{x^2}{4}-3\right)\ge 0$.`,
answer: '-8',
sol: R`$0=\log_{0{,}4}1$, и так как $0<0{,}4<1$, неравенство равносильно системе $\dfrac{x^2}{4}-3\le1$ и $\dfrac{x^2}{4}-3>0$, то есть $x^2\le16$ и $x^2>12$. Решение: $[-4;-2\sqrt3)\cup(2\sqrt3;4]$. Целых решений два ($-4$ и $4$), наименьшее $-4$. Произведение $-4\cdot2=-8$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 3, § 10' },
{ idx: 24, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 4,
text: R`Найдите (в градусах) наименьший положительный корень уравнения $4\sin\dfrac{x}{7}\cos\dfrac{x}{7}=\sqrt3$.`,
answer: '210',
sol: R`По формуле синуса двойного аргумента $2\sin\dfrac{2x}{7}=\sqrt3$, $\sin\dfrac{2x}{7}=\dfrac{\sqrt3}{2}$. Тогда $\dfrac{2x}{7}=(-1)^k60^\circ+180^\circ k$, $x=(-1)^k210^\circ+630^\circ k$. Наименьший положительный корень — $210^\circ$ (при $k=0$).`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 8; § 11' },
{ idx: 25, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 4,
text: R`В правильной треугольной пирамиде ребро основания равно $2\sqrt2$, а угол между боковым ребром и плоскостью основания равен $30^\circ$. Найдите значение выражения $9\sqrt6\cdot V$, где $V$ — объём этой пирамиды.`,
answer: '24',
sol: R`Высота $SO$, $\angle SAO=30^\circ$. $AO=\tfrac23 AM$, где медиана $AM=\sqrt6$, значит $AO=\dfrac{2\sqrt6}{3}$. Тогда $SO=AO\operatorname{tg}30^\circ=\dfrac{2\sqrt6}{3}\cdot\dfrac{\sqrt3}{3}=\dfrac{2\sqrt2}{3}$. Объём $V=\dfrac13\cdot\dfrac{(2\sqrt2)^2\sqrt3}{4}\cdot\dfrac{2\sqrt2}{3}=\dfrac{4\sqrt6}{9}$. Тогда $9\sqrt6\cdot V=9\sqrt6\cdot\dfrac{4\sqrt6}{9}=4\cdot6=24$.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 2, § 3' },
{ idx: 26, type: 'open', topic: 'equations', subtopic: 'eq-irrational', diff: 4,
text: R`Найдите произведение корней (корень, если он единственный) уравнения $\sqrt[4]{x^2+6x-27}\cdot\sqrt[3]{x^2-6x-27}=0$.`,
answer: '-243',
sol: R`Произведение равно нулю, когда один из множителей равен нулю, а другой имеет смысл. $x^2+6x-27=0\Rightarrow x=-9,\ 3$ (оба удовлетворяют ОДЗ). $x^2-6x-27=0\Rightarrow x=-3,\ 9$, но при $x=-3$ подкоренное выражение $\sqrt[4]{\;}$ отрицательно — не подходит, остаётся $x=9$. Корни уравнения: $-9,\ 3,\ 9$; произведение $-9\cdot3\cdot9=-243$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 2, § 17' },
{ idx: 27, type: 'open', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 5,
text: R`$ABCA_1B_1C_1$ — прямая треугольная призма, все рёбра которой равны. Точки $K$ и $M$ — середины рёбер $A_1C_1$ и $B_1C_1$ соответственно. Точка $N$ лежит на ребре $AB$ так, что $AN:NB=1:5$. Найдите значение выражения $\dfrac{1}{\cos^2\varphi}$, где $\varphi$ — угол между прямыми $A_1N$ и $KM$.`,
answer: '37',
sol: R`Пусть ребро равно $a$, $AN=\dfrac a6$. Так как $KM\parallel AB$ (средняя линия), угол между $A_1N$ и $KM$ равен углу $\angle NA_1B_1$. В прямоугольном треугольнике $A_1AN$: $A_1N=\sqrt{a^2+\left(\dfrac a6\right)^2}=\dfrac{a\sqrt{37}}{6}$, $\sin\angle AA_1N=\dfrac{a/6}{A_1N}=\dfrac{\sqrt{37}}{37}$. Тогда $\cos\varphi=\sin\angle AA_1N=\dfrac{\sqrt{37}}{37}$, и $\dfrac{1}{\cos^2\varphi}=37$.`,
ref: 'Латотин «Геометрия, 10 кл.», разд. 2, § 4' },
{ idx: 28, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 4,
text: R`Найдите произведение наибольшего целого отрицательного и наименьшего целого положительного решений неравенства $5\cdot25^{\frac{5-x}{23}}-26\cdot25^{\frac{5-x}{46}}+5\ge 0$.`,
answer: '-504',
sol: R`Замена $t=25^{\frac{5-x}{46}}$ даёт $5t^2-26t+5\ge0$, откуда $t\le\dfrac15$ или $t\ge5$. Тогда $\dfrac{5-x}{23}\le-1$ или $\dfrac{5-x}{23}\ge1$, то есть $x\ge28$ или $x\le-18$. Решение: $(-\infty;-18]\cup[28;+\infty)$. Наибольшее целое отрицательное — $-18$, наименьшее целое положительное — $28$; произведение $-18\cdot28=-504$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 2, § 6' },
{ idx: 29, type: 'open', topic: 'functions', subtopic: 'fn-derivative', diff: 4,
text: R`Найдите точку максимума и максимум функции $f(x)=x^3-75x-24\sin\dfrac{7\pi}{6}$. В ответ запишите их сумму.`,
answer: '257',
sol: R`$24\sin\dfrac{7\pi}{6}=24\cdot\left(-\dfrac12\right)=-12$, поэтому $f(x)=x^3-75x+12$. $f'(x)=3x^2-75=0$ при $x=\pm5$. Точка максимума $x_{\max}=-5$, $f(-5)=-125+375+12=262$. Сумма $-5+262=257$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 3, § 20' },
{ idx: 30, type: 'open', topic: 'stereometry', subtopic: 'ster-rotation', diff: 5,
text: R`Плоскость, параллельная основанию конуса, делит его высоту в отношении $2:5$, считая от вершины. Площадь сечения конуса меньше площади основания на $270\pi$. Образующая конуса составляет с плоскостью основания угол $\operatorname{arctg}\dfrac57$. Найдите значение выражения $\dfrac{\sqrt6\,V}{\pi}$, где $V$ — объём конуса.`,
answer: '2940',
sol: R`Сечением является круг; по свойству площади относятся как квадраты расстояний от вершины: $\dfrac{S_{\text{осн}}-270\pi}{S_{\text{осн}}}=\left(\dfrac27\right)^2=\dfrac{4}{49}$, откуда $45 S_{\text{осн}}=49\cdot270\pi$, $S_{\text{осн}}=294\pi$. Тогда $R^2=294$, $R=7\sqrt6$. Высота $SO=R\operatorname{tg}\left(\operatorname{arctg}\dfrac57\right)=7\sqrt6\cdot\dfrac57=5\sqrt6$. Объём $V=\dfrac13 S_{\text{осн}}\cdot SO=\dfrac13\cdot294\pi\cdot5\sqrt6=490\pi\sqrt6$. Тогда $\dfrac{\sqrt6\,V}{\pi}=490\cdot6=2940$.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 2, § 4' },
];
/* ── машинерия (как в e1v1) ────────────────────────────────────────────────── */
function ansShowOf(t) { if (t.ansShow != null) return t.ansShow; if (t.type === 'mc') return `${t.answer})`; return `$${t.answer}$`; }
function buildSolution(t) {
let html = `${t.sol}<div class="sol-ans">Ответ: ${ansShowOf(t)}</div>`;
if (t.ref) html += `<div class="sol-ref" style="margin-top:6px;font-size:.85em;opacity:.7">Учебник: ${t.ref}</div>`;
return html;
}
const EPS = 1e-6;
function srvToNumber(s) {
if (s == null) return NaN;
let t = String(s).trim().replace(/\$/g, '').replace(/\s+/g, '').replace(',', '.');
const f = t.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(-?\d+(?:\.\d+)?)$/);
if (f) { const n = Number(f[1]), d = Number(f[2]); return d === 0 ? NaN : n / d; }
const n = Number(t); return Number.isFinite(n) ? n : NaN;
}
function checkAnswerServer(u, c0) {
if (u == null || c0 == null) return false;
const c = String(c0).trim();
if (/^[а-д]$/.test(c)) return String(u).trim().toLowerCase() === c.toLowerCase();
if (/^[^;]+;[^;]+$/.test(c)) return false;
const cn = srvToNumber(c), un = srvToNumber(u);
if (Number.isNaN(cn) || Number.isNaN(un)) return false;
return Math.abs(cn - un) < EPS;
}
const problems = [];
if (TASKS.length !== 30) problems.push(`Ожидалось 30, получено ${TASKS.length}`);
const seen = new Set();
for (const t of TASKS) {
if (seen.has(t.idx)) problems.push(`Дубль idx=${t.idx}`); seen.add(t.idx);
if (t.idx < 1 || t.idx > 30) problems.push(`idx вне 1..30: ${t.idx}`);
if (!['mc', 'open', 'long'].includes(t.type)) problems.push(`#${t.idx}: тип ${t.type}`);
if (t.type === 'mc') {
if (!Array.isArray(t.opts) || t.opts.length !== 5) problems.push(`#${t.idx}: mc!=5 опций`);
if (!t.opts.some(o => o[0] === t.answer)) problems.push(`#${t.idx}: answer "${t.answer}" не среди меток`);
}
if (!t.text || !t.sol) problems.push(`#${t.idx}: пустой text/sol`);
if (t.type !== 'long' && !checkAnswerServer(t.answer, t.answer)) problems.push(`#${t.idx}: self-check "${t.answer}"`);
if (//.test(String(t.answer))) problems.push(`#${t.idx}: Unicode-минус в answer`);
}
module.exports = { TASKS, buildSolution, ansShowOf, checkAnswerServer, EXAM, VARIANT, PROV };
if (require.main !== module) return;
const DB = path.join(__dirname, '..', 'data', 'learnspace.db');
const db = new DatabaseSync(DB);
if (!db.prepare(`SELECT exam_key FROM exam_tracks WHERE exam_key=?`).get(EXAM)) { console.error(`✗ Трек '${EXAM}' не найден.`); process.exit(1); }
console.log(`\n=== seed_ctmath_rt2425_e2v1 (${PROV}) variant=${VARIANT} ===`);
console.log(`Режим: ${APPLY ? 'APPLY' : 'DRY-RUN'}\n`);
console.log('Типы:', JSON.stringify(TASKS.reduce((a, t) => (a[t.type] = (a[t.type] || 0) + 1, a), {})), '| фигур:', TASKS.filter(t => t.fig).length, '\n');
console.log('idx | type | subtopic | d | answer | fig');
console.log('----+------+-----------------------+---+-----------+----');
for (const t of TASKS) console.log(`${String(t.idx).padStart(3)} | ${t.type.padEnd(4)} | ${String(t.subtopic).padEnd(21)} | ${t.diff} | ${String(t.answer).padEnd(9)} | ${t.fig ? '✓' : ''}`);
if (problems.length) { console.error(`\n✗ ПРОБЛЕМЫ (${problems.length}):`); problems.forEach(p => console.error(' - ' + p)); db.close(); process.exit(1); }
console.log('\n✓ Валидация и self-check ответов пройдены (30/30).');
if (!APPLY) { console.log('\nDRY-RUN: ничего не записано. Для записи добавьте --apply\n'); db.close(); process.exit(0); }
const upsert = db.prepare(`
INSERT INTO exam_tasks (exam_key, variant, task_idx, task_type, text_html, figure_html, opts_json, answer, solution_html, topic, subtopic, difficulty)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(exam_key, variant, task_idx) DO UPDATE SET
task_type=excluded.task_type, text_html=excluded.text_html, figure_html=excluded.figure_html,
opts_json=excluded.opts_json, answer=excluded.answer, solution_html=excluded.solution_html,
topic=excluded.topic, subtopic=excluded.subtopic, difficulty=excluded.difficulty`);
let n = 0; db.exec('BEGIN');
try {
for (const t of TASKS) { upsert.run(EXAM, VARIANT, t.idx, t.type, t.text, t.fig || null, t.type === 'mc' ? JSON.stringify(t.opts) : null, t.answer, buildSolution(t), t.topic, t.subtopic, t.diff); n++; }
const distinct = db.prepare(`SELECT COUNT(DISTINCT variant) c FROM exam_tasks WHERE exam_key=? AND variant BETWEEN 101 AND 1999`).get(EXAM).c;
db.prepare(`UPDATE exam_tracks SET variants_count=? WHERE exam_key=?`).run(distinct, EXAM);
db.exec('COMMIT');
console.log(`\n✓ Записано/обновлено ${n} заданий (variant=${VARIANT}). variants_count=${distinct}.`);
console.log(`\nПробник: /exam-prep/ctmath → «Варианты» → «Вариант ${VARIANT}».\n`);
} catch (e) { db.exec('ROLLBACK'); console.error('\n✗ Ошибка записи, откат:', e.message); process.exitCode = 1; }
db.close();
+294
View File
@@ -0,0 +1,294 @@
'use strict';
/* ───────────────────────────────────────────────────────────────────────────
seed_ctmath_rt2425_e3v1.js — РТ–2024/2025, Этап III, Вариант 1 → variant=103
Чистый 30-задачный пробник (А1–А10 + В1–В20). Этап III — завершающий, полный
охват программы (стереометрия тел вращения, сфера, производная, сечения).
Перенабрано вручную в KaTeX по PDF (…\РТ\2024-2025\МАТ РТ-3 24_25 В1.pdf).
Правило тиража: 1 вариант на Этап. Только А2 содержит данные на чертеже.
Запуск: node backend/scripts/seed_ctmath_rt2425_e3v1.js [--apply]
─────────────────────────────────────────────────────────────────────────── */
const { DatabaseSync } = require('node:sqlite');
const path = require('path');
const APPLY = process.argv.includes('--apply');
const EXAM = 'ctmath';
const VARIANT = 103;
const PROV = 'РТ–2024/2025, Этап III, Вариант 1';
const FIGDIR = 'rt2425_e3v1';
const R = String.raw;
const FIG = (name, alt) =>
`<img src="/img/ct/math/${FIGDIR}/${name}" alt="${alt}" ` +
`style="max-width:300px;width:100%;height:auto;display:block;margin:10px auto;` +
`background:#fff;border-radius:8px;padding:6px;">`;
const L = ['а', 'б', 'в', 'г', 'д'];
const mc = (...html) => html.map((h, i) => [L[i], h]);
const TASKS = [
// ── Часть A ──────────────────────────────────────────────────────────────
{ idx: 1, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1,
text: R`Среди чисел $-0{,}5;\ 2^{-1};\ -0{,}2;\ -\sqrt2;\ 2$ укажите число, противоположное числу $\dfrac12$.`,
opts: mc('$-0{,}5$', '$2^{-1}$', '$-0{,}2$', '$-\sqrt2$', '$2$'),
answer: 'а',
sol: R`Противоположные числа имеют равные модули, но разные знаки. Числу $\dfrac12$ противоположно число $-\dfrac12=-0{,}5$.`,
ref: 'Герасимов «Математика, 6 кл.», гл. 4, § 2' },
{ idx: 2, type: 'mc', topic: 'planimetry', subtopic: 'plan-circle', diff: 2,
text: R`На рисунке изображены три окружности с центрами $O$, $A$, $B$, радиусы которых равны $R$, $\dfrac R4$, $\dfrac R3$ соответственно. Найдите длину отрезка $AB$, если $R=12$.`,
opts: mc('$13$', '$18$', '$15$', '$17$', '$19$'),
answer: 'г',
sol: R`Отрезок $AB$ лежит на диаметре большой окружности (радиус $R=12$, диаметр $24$). Меньшие окружности касаются большой изнутри, их радиусы $\dfrac R4=3$ и $\dfrac R3=4$. Тогда $AB=24-3-4=17$.`,
ref: 'Казаков «Геометрия, 7 кл.», гл. 1, § 4',
fig: FIG('a2.png', 'Большая окружность с центром O и две внутренние окружности A и B на диаметре') },
{ idx: 3, type: 'mc', topic: 'functions', subtopic: 'fn-properties', diff: 2,
text: R`Укажите номер множества чисел, которое может являться областью определения нечётной функции.`,
opts: mc('$[-7;7]$', '$(-6;0)\cup(0;6]$', '$[-5;10]$', '$[-9;2)\cup(2;9]$', '$(-11;0)\cup(0;11)$'),
answer: 'д',
sol: R`Область определения нечётной функции симметрична относительно нуля. Из предложенных множеств этим свойством обладает $(-11;0)\cup(0;11)$.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 2, § 8' },
{ idx: 4, type: 'mc', topic: 'equations', subtopic: 'eq-exponential', diff: 2,
text: R`Укажите номер показательного уравнения, корнем которого является число $-2$.`,
opts: mc('$(0{,}3)^{x-6}=(0{,}3)^{6x+4}$', '$2^{2x}=64$', '$(0{,}5)^{x^2+4}=1$', '$16x+35=3$', '$7^x=11$'),
answer: 'а',
sol: R`Подставим $x=-2$: $(0{,}3)^{-2-6}=(0{,}3)^{6\cdot(-2)+4}$, то есть $(0{,}3)^{-8}=(0{,}3)^{-8}$ — верно. Остальные показательные уравнения числу $-2$ не удовлетворяют (а уравнение 4 не является показательным).`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 2, § 5' },
{ idx: 5, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2,
text: R`Найдите значение выражения $\sqrt[7]{(-49)^7}-|5{,}25-6|$.`,
opts: mc('$-48{,}25$', '$-49{,}75$', '$-49{,}25$', '$-48{,}75$', '$-50$'),
answer: 'б',
sol: R`$\sqrt[7]{(-49)^7}=-49$ (корень нечётной степени), $|5{,}25-6|=0{,}75$. Тогда $-49-0{,}75=-49{,}75$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 2, § 14' },
{ idx: 6, type: 'open', topic: 'expressions', subtopic: 'expr-polynomials', diff: 2,
text: R`Укажите номера пар, состоящих из подобных одночленов.<br>1) $2ab^2$ и $-2a^2b$;<br>2) $\dfrac13 m$ и $-m^3$;<br>3) $5xy$ и $-0{,}2xy$;<br>4) $-16$ и $-16n$;<br>5) $-1{,}2c^8$ и $-8c^8$.<br><i>Ответ запишите номерами в порядке возрастания, без пробелов.</i>`,
answer: '35', ansShow: '3, 5',
sol: R`Подобные одночлены отличаются только числовым коэффициентом (одинаковая буквенная часть). $\ 3)\ 5xy$ и $-0{,}2xy$ — подобны. $\ 5)\ -1{,}2c^8$ и $-8c^8$ — подобны. Остальные пары различаются буквенной частью.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 67' },
{ idx: 7, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2,
text: R`Юра, редактируя изображение шириной $27$ см и высотой $36$ см, уменьшил ширину на $6$ см так, что отношение ширины к высоте полученного изображения не изменилось. Найдите высоту полученного изображения (в см).`,
opts: mc('$31$', '$27$', '$28$', '$30$', '$26$'),
answer: 'в',
sol: R`Новая ширина $27-6=21$ см. Отношение сохранилось: $\dfrac{27}{36}=\dfrac{21}{x}$, откуда $x=\dfrac{36\cdot21}{27}=28$ см.`,
ref: 'Герасимов «Математика, 6 кл.», гл. 2, § 3' },
{ idx: 8, type: 'mc', topic: 'trigonometry', subtopic: 'trig-identities', diff: 2,
text: R`Найдите значение выражения $\operatorname{arcctg}(-\sqrt3)+\dfrac\pi2$.`,
opts: mc('$\dfrac\pi3$', '$\dfrac{7\pi}{6}$', '$\dfrac\pi6$', '$\dfrac{4\pi}{3}$', '$\dfrac{3\pi}{2}$'),
answer: 'г',
sol: R`$\operatorname{arcctg}(-\sqrt3)=\dfrac{5\pi}{6}$ (так как $\dfrac{5\pi}{6}\in(0;\pi)$ и $\operatorname{ctg}\dfrac{5\pi}{6}=-\sqrt3$). Тогда $\dfrac{5\pi}{6}+\dfrac\pi2=\dfrac{5\pi}{6}+\dfrac{3\pi}{6}=\dfrac{8\pi}{6}=\dfrac{4\pi}{3}$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 7' },
{ idx: 9, type: 'mc', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 3,
text: R`Из точки $A$, отстоящей на $\sqrt3$ от плоскости $\alpha$, проведена наклонная $AB$. Проекция наклонной $AB$ на плоскость $\alpha$ равна $\sqrt{13}$. Найдите косинус угла между наклонной $AB$ и плоскостью $\alpha$.`,
opts: mc('$\dfrac{\sqrt3}{4}$', '$\dfrac{\sqrt{13}}{4}$', '$\dfrac{\sqrt{39}}{13}$', '$\dfrac14$', '$\dfrac{\sqrt3}{2}$'),
answer: 'б',
sol: R`Пусть $O$ — основание перпендикуляра: $AO=\sqrt3$, проекция $OB=\sqrt{13}$. По теореме Пифагора $AB=\sqrt{(\sqrt3)^2+(\sqrt{13})^2}=\sqrt{16}=4$. Искомый угол — $\angle ABO$, $\cos\angle ABO=\dfrac{OB}{AB}=\dfrac{\sqrt{13}}{4}$.`,
ref: 'Латотин «Геометрия, 10 кл.», разд. 3, § 9' },
{ idx: 10, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 3,
text: R`Укажите номера верных утверждений.<br>1) функция $f(x)=(\sqrt3-1)^x$ является возрастающей на области определения;<br>2) график функции $f(x)=3^x$ пересекает прямую $y=1$;<br>3) значение функции $f(x)=\log_{0{,}5}x$ меньше нуля при $x=\dfrac23$;<br>4) функция $f(x)=\log_{2{,}02}x$ является возрастающей на области определения;<br>5) $f(3{,}5)>f(4{,}2)$, если $f(x)=\left(\dfrac13\right)^x$.<br><i>Ответ запишите номерами в порядке возрастания, без пробелов.</i>`,
answer: '245', ansShow: '2, 4, 5',
sol: R`$1)$ неверно: $0<\sqrt3-1<1$, функция убывает. $\ 2)$ верно: график $y=3^x$ пересекает $y=1$ в точке $(0;1)$. $\ 3)$ неверно: $\log_{0{,}5}\dfrac23>0$. $\ 4)$ верно: $2{,}02>1$, функция возрастает. $\ 5)$ верно: при основании $\dfrac13$ функция убывает, и из $3{,}5<4{,}2$ следует $f(3{,}5)>f(4{,}2)$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 2, § 4; гл. 3, § 8' },
// ── Часть B ──────────────────────────────────────────────────────────────
{ idx: 11, type: 'long', topic: 'stereometry', subtopic: 'ster-rotation', diff: 3,
text: R`Конус получен вращением равнобедренного прямоугольного треугольника вокруг прямой, содержащей его катет, равный $\sqrt{21}$. Для начала каждого из предложений А–В подберите его окончание 1–6 так, чтобы получилось верное утверждение.<br><b>Начало:</b><br>А) Диаметр основания конуса равен …<br>Б) Площадь осевого сечения конуса равна …<br>В) Объём конуса, если в качестве числа $\pi$ взято число Архимеда $\dfrac{22}{7}$, равен …<br><b>Окончание:</b><br>1) $42$;&emsp;2) $22\sqrt{21}$;&emsp;3) $66\sqrt{21}$;&emsp;4) $21$;&emsp;5) $2\sqrt{21}$;&emsp;6) $\sqrt{21}$.<br><i>Ответ запишите сочетанием букв и цифр, например: А1Б1В4.</i>`,
answer: 'А5Б4В2', ansShow: 'А5Б4В2',
sol: R`Радиус и высота конуса равны катету $\sqrt{21}$. А) Диаметр $=2\sqrt{21}$ — окончание 5. Б) Осевое сечение — равнобедренный треугольник с основанием $2\sqrt{21}$ и высотой $\sqrt{21}$: $S=\tfrac12\cdot2\sqrt{21}\cdot\sqrt{21}=21$ — окончание 4. В) $V=\tfrac13\cdot\dfrac{22}{7}\cdot(\sqrt{21})^2\cdot\sqrt{21}=\tfrac13\cdot\dfrac{22}{7}\cdot21\sqrt{21}=22\sqrt{21}$ — окончание 2.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 2, § 4' },
{ idx: 12, type: 'open', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 3,
text: R`Выберите верные утверждения.<br>1) значение выражения $(-1)^{-5}\cdot(-2)^2$ равно $-4$;<br>2) значение выражения $8^{1/3}\cdot12^0$ равно $-2$;<br>3) значение выражения $5^{-1/7}:25^{-4/7}$ равно $0{,}2$;<br>4) значение выражения $4-64^{1/3}$ равно $8$;<br>5) значение выражения $16^{-1/4}$ равно $0{,}5$;<br>6) значение выражения $2\cdot49^{0{,}5}+\left(2^{-1{,}5}\right)^{-2}$ равно $22$.<br><i>Ответ запишите номерами в порядке возрастания, без пробелов.</i>`,
answer: '156', ansShow: '1, 5, 6',
sol: R`$1)\ (-1)^{-5}\cdot(-2)^2=-1\cdot4=-4$ — верно. $\ 2)\ 8^{1/3}\cdot1=2\ne-2$ — неверно. $\ 3)\ 5^{-1/7}:5^{-8/7}=5^{1}=5\ne0{,}2$ — неверно. $\ 4)\ 4-4=0\ne8$ — неверно. $\ 5)\ 16^{-1/4}=2^{-1}=0{,}5$ — верно. $\ 6)\ 2\cdot7+2^3=14+8=22$ — верно.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 1, § 1' },
{ idx: 13, type: 'open', topic: 'numbers', subtopic: 'num-divisibility', diff: 2,
text: R`Первый диспетчер такси принял за день $155$ заявок. Найдите наибольшее число заявок, принятых вторым диспетчером, если число заявок, принятых двумя диспетчерами вместе, не превосходит $300$ и кратно $9$.`,
answer: '142',
sol: R`Наибольшее не превосходящее $300$ число, кратное $9$, равно $297$. Тогда наибольшее число заявок второго диспетчера $297-155=142$.`,
ref: 'Герасимов «Математика, 5 кл.», ч. 1, гл. 1, § 13' },
{ idx: 14, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 2,
text: R`В параллелограмме $ABCD$ угол $BAD$ равен $45^\circ$, $BH$ — высота, проведённая к стороне $AD$, $AH=4$, $DH=8$. Найдите площадь параллелограмма $ABCD$.`,
answer: '48',
sol: R`Так как $\angle BAD=45^\circ$, прямоугольный треугольник $BHA$ равнобедренный, поэтому $BH=AH=4$. Сторона $AD=AH+HD=12$. Площадь $S=AD\cdot BH=12\cdot4=48$.`,
ref: 'Казаков «Геометрия, 8 кл.», гл. 2, § 14' },
{ idx: 15, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 4,
text: R`Найдите значение выражения $x_0-4$, где $x_0$ — корень уравнения $\log_{81}(7-x)-1\dfrac14=0$.`,
answer: '-240',
sol: R`$\log_{81}(7-x)=\dfrac54$, $\dfrac14\log_3(7-x)=\dfrac54$, $\log_3(7-x)=5$, $7-x=3^5=243$, $x=-236$. Тогда $x_0-4=-236-4=-240$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 3, § 9' },
{ idx: 16, type: 'open', topic: 'functions', subtopic: 'fn-graphs', diff: 3,
text: R`Найдите количество всех целых значений аргумента, при которых функция $f(x)=\dfrac1{12}(x-8)^2-3$ принимает отрицательные значения.`,
answer: '11',
sol: R`Нули функции: $\dfrac1{12}(x-8)^2-3=0$, $(x-8)^2=36$, $x_1=2$, $x_2=14$. Ветви параболы направлены вверх, поэтому функция отрицательна на $(2;14)$. Целых значений на этом промежутке — $11$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 3, § 14' },
{ idx: 17, type: 'open', topic: 'trigonometry', subtopic: 'trig-identities', diff: 3,
text: R`Найдите значение выражения $64\cos 2\alpha$, если $\sin\alpha=\dfrac18$.`,
answer: '62',
sol: R`$\cos2\alpha=1-2\sin^2\alpha=1-2\cdot\dfrac1{64}=\dfrac{62}{64}$. Тогда $64\cos2\alpha=64\cdot\dfrac{62}{64}=62$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 11' },
{ idx: 18, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 4,
text: R`Два дачных участка прямоугольной формы имеют одинаковую длину. Площадь первого участка равна $434$ м$^2$, площадь второго участка равна $558$ м$^2$. Найдите (в метрах) периметр второго участка, если известно, что сумма ширин двух участков составляет $320$ дм.`,
answer: '98',
sol: R`$320$ дм $=32$ м. Пусть ширина второго участка $x$ м, первого $(32-x)$ м, общая длина $y$ м. Тогда $\begin{cases}(32-x)y=434,\\ xy=558.\end{cases}$ Подставив $xy=558$: $32y-558=434$, $32y=992$, $y=31$, $x=18$. Второй участок $31\times18$, периметр $2(31+18)=98$ м.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 3, § 11' },
{ idx: 19, type: 'open', topic: 'word-sequences', subtopic: 'seq-progressions', diff: 4,
text: R`В арифметической прогрессии $(a_n)$ четвёртый, пятый и шестой члены имеют вид $a_4=-2x$; $\ a_5=15-3x$; $\ a_6=55-5x$. Найдите сумму тридцати первых членов этой прогрессии.`,
answer: '-4950',
sol: R`По свойству $a_5=\dfrac{a_4+a_6}{2}$: $15-3x=\dfrac{-2x+55-5x}{2}$, $30-6x=-7x+55$, $x=25$. Тогда $a_4=-50$, $a_5=-60$, $a_6=-70$, разность $d=-10$, $a_1=a_4-3d=-20$. $S_{30}=\dfrac{2a_1+d(30-1)}{2}\cdot30=\dfrac{-40-290}{2}\cdot30=-4950$.`,
ref: 'Арефьева «Алгебра, 9 кл.», гл. 4, § 1516' },
{ idx: 20, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 4,
text: R`Радиус окружности, вписанной в равнобедренную трапецию, равен $3\sqrt2$. Тупой угол равнобедренной трапеции равен $120^\circ$. Найдите значение выражения $P^2$, где $P$ — периметр равнобедренной трапеции.`,
answer: '1536',
sol: R`Высота трапеции равна диаметру вписанной окружности: $BK=6\sqrt2$. В прямоугольном треугольнике с острым углом $30^\circ$ боковая сторона $AB=\dfrac{BK}{\sin60^\circ}=\dfrac{6\sqrt2}{\sqrt3/?}$… Для описанной окружностью трапеции $AB+CD=BC+AD$, $AB=CD=4\sqrt6$, поэтому сумма оснований $BC+AD=8\sqrt6$. Периметр $P=2\cdot8\sqrt6=16\sqrt6$, тогда $P^2=256\cdot6=1536$.`,
ref: 'Казаков «Геометрия, 9 кл.», гл. 2, § 10' },
{ idx: 21, type: 'open', topic: 'equations', subtopic: 'eq-linear', diff: 3,
text: R`Найдите сумму всех целых решений совокупности неравенств $\left[\begin{array}{l}\dfrac{x-2}{7}<\dfrac{x+2}{2}-\dfrac1{14},\\[4pt] (x-3)^2+5<(x+2)^2-20\end{array}\right.$ на промежутке $[-7;7]$.`,
answer: '22',
sol: R`Первое неравенство: $2x-4<7x+14-1$, $-5x<17$, $x>-3{,}4$. Второе: $x^2-6x+9+5<x^2+4x+4-20$, $-10x<-30$, $x>3$. Объединение совокупности — луч $(-3{,}4;+\infty)$. Пересечение с $[-7;7]$ даёт $(-3{,}4;7]$. Сумма целых от $-3$ до $7$ равна $22$.`,
ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 6' },
{ idx: 22, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 3,
text: R`Имеется $28$ кг сплава меди с цинком, содержащего $34{,}5\%$ меди. Сколько меди (в граммах) необходимо добавить к этому сплаву, чтобы получить сплав, содержащий $60\%$ меди?`,
answer: '17850',
sol: R`Масса меди в исходном сплаве $28\cdot0{,}345=9{,}66$ кг. Пусть добавили $x$ кг меди: $(9{,}66+x)=(28+x)\cdot0{,}6$, $9{,}66+x=16{,}8+0{,}6x$, $0{,}4x=7{,}14$, $x=17{,}85$ кг $=17850$ г.`,
ref: 'Арефьева «Алгебра, 7 кл.», гл. 3, § 16' },
{ idx: 23, type: 'open', topic: 'equations', subtopic: 'eq-irrational', diff: 4,
text: R`Найдите произведение корней (корень, если он единственный) уравнения $\sqrt{2x^2+11x-14}=-x-2$.`,
answer: '-9',
sol: R`Возведём в квадрат: $2x^2+11x-14=x^2+4x+4$, $x^2+7x-18=0$, корни $-9$ и $2$. Проверка: при $x=-9$ $\sqrt{49}=7=-(-9)-2$ — верно; при $x=2$ $\sqrt{16}=4\ne-4$ — посторонний. Единственный корень $-9$; произведение равно $-9$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 2, § 17' },
{ idx: 24, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 5,
text: R`$ABCDA_1B_1C_1D_1$ — куб, у которого длина ребра равна $6\sqrt3$. Точки $M$ и $N$ — середины рёбер $AB$ и $AD$. Через точки $M$, $N$ и $C_1$ проведена секущая плоскость. Найдите значение выражения $n\cdot a^2$, где $n$ — количество вершин многоугольника сечения, $a$ — длина отрезка, по которому секущая плоскость пересекает грань $AA_1D_1D$.`,
answer: '195',
sol: R`Сечение — пятиугольник $C_1LNMK$, поэтому $n=5$. Сторона $NL$ (по грани $AA_1D_1D$): из построения и подобия $DL=2\sqrt3$, $DN=3\sqrt3$, тогда $NL=\sqrt{DL^2+DN^2}=\sqrt{(2\sqrt3)^2+(3\sqrt3)^2}=\sqrt{39}$, то есть $a=\sqrt{39}$. Значение $n\cdot a^2=5\cdot39=195$.`,
ref: 'Латотин «Геометрия, 10 кл.», разд. 1, § 3' },
{ idx: 25, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 5,
text: R`Найдите (в градусах) сумму различных корней уравнения $\sin 3x\cos 3x\cos 6x=-\dfrac{\sqrt3}{8}$ на промежутке $[-60^\circ;0^\circ]$.`,
answer: '-90',
sol: R`$\tfrac12\sin6x\cos6x=-\dfrac{\sqrt3}{8}$, $\tfrac14\sin12x=-\dfrac{\sqrt3}{8}$, $\sin12x=-\dfrac{\sqrt3}{2}$. Тогда $12x=(-1)^{k+1}60^\circ+180^\circ k$, $x=(-1)^{k+1}5^\circ+15^\circ k$. На $[-60^\circ;0^\circ]$ корни: $-5^\circ,\ -10^\circ,\ -35^\circ,\ -40^\circ$. Их сумма $-90^\circ$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 8; § 11' },
{ idx: 26, type: 'open', topic: 'stereometry', subtopic: 'ster-rotation', diff: 5,
text: R`Сфера касается всех сторон равнобедренного треугольника $ABC$, у которого длина основания $AC$ равна $10$ и длина боковой стороны $AB$ равна $11$. Расстояние от центра сферы до плоскости треугольника $ABC$ равно $\dfrac{5\sqrt{42}}{4}$. Найдите значение выражения $\dfrac{S}{\pi}$, где $S$ — площадь сферы.`,
answer: '300',
sol: R`Точки касания равноудалены от проекции $O_1$ центра сферы, значит $O_1$ — центр вписанной в $ABC$ окружности. Площадь по Герону: $p=16$, $S_{ABC}=\sqrt{16\cdot5\cdot5\cdot6}=20\sqrt6$, радиус вписанной $r=\dfrac{S}{p}=\dfrac{20\sqrt6}{16}=\dfrac{5\sqrt6}{4}$. Радиус сферы $OK=\sqrt{OO_1^2+r^2}=\sqrt{\dfrac{25\cdot42}{16}+\dfrac{25\cdot6}{16}}=\sqrt{75}=5\sqrt3$. Площадь сферы $S=4\pi R^2=4\pi\cdot75=300\pi$, поэтому $\dfrac{S}{\pi}=300$.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 3, § 5' },
{ idx: 27, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 4,
text: R`Найдите сумму всех целых решений неравенства $\log_{\lg 8}(8-x)-\log_{\lg 8}(x-4)\ge 0$.`,
answer: '13',
sol: R`Так как $0<\lg8<1$, функция $\log_{\lg8}t$ убывает, поэтому неравенство $\log_{\lg8}(8-x)\ge\log_{\lg8}(x-4)$ равносильно системе $8-x\le x-4$ и $8-x>0$, то есть $x\ge6$ и $x<8$. Решение $[6;8)$, целые $6$ и $7$, сумма $13$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 3, § 10' },
{ idx: 28, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 4,
text: R`Найдите произведение наименьшего целого решения на количество всех целых решений неравенства $\left(\sqrt2-1\right)^{\frac{(x+9)^2(3-x)}{x-6}}\le 1$.`,
answer: '-36',
sol: R`Так как $\sqrt2-1\in(0;1)$, неравенство равносильно $\dfrac{(x+9)^2(3-x)}{x-6}\ge0$, или $\dfrac{(x+9)^2(x-3)}{x-6}\le0$. Методом интервалов (нули $-9,3$; разрыв $6$): решение $\{-9\}\cup[3;6)$. Целых решений $4$ ($-9,3,4,5$), наименьшее $-9$. Произведение $-9\cdot4=-36$.`,
ref: 'Арефьева «Алгебра, 11 кл.», гл. 2, § 6' },
{ idx: 29, type: 'open', topic: 'functions', subtopic: 'fn-derivative', diff: 5,
text: R`Дана функция $f(x)=\dfrac{2x^2-x}{x+5}$. Найдите значение выражения $a\cdot n$, где $a$ — наименьшее целое число из промежутков убывания данной функции, $n$ — количество всех целых чисел из промежутков убывания данной функции.`,
answer: '-100',
sol: R`$f'(x)=\dfrac{2x^2+20x-5}{(x+5)^2}$. Убывание: $f'(x)<0$ при $\dfrac{-10-\sqrt{110}}{2}<x<-5$ и $-5<x<\dfrac{-10+\sqrt{110}}{2}$ (то есть примерно на $(-10{,}2;-5)$ и $(-5;0{,}2)$). Наименьшее целое из этих промежутков $a=-10$, количество целых $n=10$. Значение $a\cdot n=-100$.`,
ref: 'Арефьева «Алгебра, 10 кл.», гл. 3, § 20' },
{ idx: 30, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 5,
text: R`В основании пирамиды лежит прямоугольный треугольник, у которого гипотенуза равна $8$ и один из острых углов равен $60^\circ$. Каждая боковая грань пирамиды наклонена к плоскости основания под углом, равным $\operatorname{arcctg}\dfrac{\sqrt5}{2}$. Найдите значение выражения $\left(3\sqrt5+\sqrt{15}\right)\cdot V$, где $V$ — объём данной пирамиды.`,
answer: '64',
sol: R`Высота пирамиды опущена в центр вписанной в основание окружности (двугранные углы при основании равны). В прямоугольном треугольнике $BC=4$, $AB=4\sqrt3$, $S_{ABC}=\tfrac12\cdot4\sqrt3\cdot4=8\sqrt3$, $r=\dfrac{AB+BC-AC}{2}=2\sqrt3-2$. Высота $SO=\dfrac{r}{\operatorname{ctg}\angle SMO}=\dfrac{2\sqrt3-2}{\sqrt5/2}=\dfrac{4\sqrt{15}-4\sqrt5}{5}$. Объём $V=\tfrac13\cdot8\sqrt3\cdot SO=\dfrac{32(3\sqrt5-\sqrt{15})}{15}$. Тогда $\left(3\sqrt5+\sqrt{15}\right)\cdot V=64$.`,
ref: 'Латотин «Геометрия, 11 кл.», разд. 2, § 3' },
];
/* ── машинерия ─────────────────────────────────────────────────────────────── */
function ansShowOf(t) { if (t.ansShow != null) return t.ansShow; if (t.type === 'mc') return `${t.answer})`; return `$${t.answer}$`; }
function buildSolution(t) {
let html = `${t.sol}<div class="sol-ans">Ответ: ${ansShowOf(t)}</div>`;
if (t.ref) html += `<div class="sol-ref" style="margin-top:6px;font-size:.85em;opacity:.7">Учебник: ${t.ref}</div>`;
return html;
}
const EPS = 1e-6;
function srvToNumber(s) {
if (s == null) return NaN;
let t = String(s).trim().replace(/\$/g, '').replace(/\s+/g, '').replace(',', '.');
const f = t.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(-?\d+(?:\.\d+)?)$/);
if (f) { const n = Number(f[1]), d = Number(f[2]); return d === 0 ? NaN : n / d; }
const n = Number(t); return Number.isFinite(n) ? n : NaN;
}
function checkAnswerServer(u, c0) {
if (u == null || c0 == null) return false;
const c = String(c0).trim();
if (/^[а-д]$/.test(c)) return String(u).trim().toLowerCase() === c.toLowerCase();
if (/^[^;]+;[^;]+$/.test(c)) return false;
const cn = srvToNumber(c), un = srvToNumber(u);
if (Number.isNaN(cn) || Number.isNaN(un)) return false;
return Math.abs(cn - un) < EPS;
}
const problems = [];
if (TASKS.length !== 30) problems.push(`Ожидалось 30, получено ${TASKS.length}`);
const seen = new Set();
for (const t of TASKS) {
if (seen.has(t.idx)) problems.push(`Дубль idx=${t.idx}`); seen.add(t.idx);
if (t.idx < 1 || t.idx > 30) problems.push(`idx вне 1..30: ${t.idx}`);
if (!['mc', 'open', 'long'].includes(t.type)) problems.push(`#${t.idx}: тип ${t.type}`);
if (t.type === 'mc') {
if (!Array.isArray(t.opts) || t.opts.length !== 5) problems.push(`#${t.idx}: mc!=5 опций`);
if (!t.opts.some(o => o[0] === t.answer)) problems.push(`#${t.idx}: answer "${t.answer}" не среди меток`);
}
if (!t.text || !t.sol) problems.push(`#${t.idx}: пустой text/sol`);
if (t.type !== 'long' && !checkAnswerServer(t.answer, t.answer)) problems.push(`#${t.idx}: self-check "${t.answer}"`);
if (//.test(String(t.answer))) problems.push(`#${t.idx}: Unicode-минус в answer`);
}
module.exports = { TASKS, buildSolution, ansShowOf, checkAnswerServer, EXAM, VARIANT, PROV };
if (require.main !== module) return;
const DB = path.join(__dirname, '..', 'data', 'learnspace.db');
const db = new DatabaseSync(DB);
if (!db.prepare(`SELECT exam_key FROM exam_tracks WHERE exam_key=?`).get(EXAM)) { console.error(`✗ Трек '${EXAM}' не найден.`); process.exit(1); }
console.log(`\n=== seed_ctmath_rt2425_e3v1 (${PROV}) variant=${VARIANT} ===`);
console.log(`Режим: ${APPLY ? 'APPLY' : 'DRY-RUN'}\n`);
console.log('Типы:', JSON.stringify(TASKS.reduce((a, t) => (a[t.type] = (a[t.type] || 0) + 1, a), {})), '| фигур:', TASKS.filter(t => t.fig).length, '\n');
console.log('idx | type | subtopic | d | answer | fig');
console.log('----+------+-----------------------+---+-----------+----');
for (const t of TASKS) console.log(`${String(t.idx).padStart(3)} | ${t.type.padEnd(4)} | ${String(t.subtopic).padEnd(21)} | ${t.diff} | ${String(t.answer).padEnd(9)} | ${t.fig ? '✓' : ''}`);
if (problems.length) { console.error(`\n✗ ПРОБЛЕМЫ (${problems.length}):`); problems.forEach(p => console.error(' - ' + p)); db.close(); process.exit(1); }
console.log('\n✓ Валидация и self-check ответов пройдены (30/30).');
if (!APPLY) { console.log('\nDRY-RUN: ничего не записано. Для записи добавьте --apply\n'); db.close(); process.exit(0); }
const upsert = db.prepare(`
INSERT INTO exam_tasks (exam_key, variant, task_idx, task_type, text_html, figure_html, opts_json, answer, solution_html, topic, subtopic, difficulty)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(exam_key, variant, task_idx) DO UPDATE SET
task_type=excluded.task_type, text_html=excluded.text_html, figure_html=excluded.figure_html,
opts_json=excluded.opts_json, answer=excluded.answer, solution_html=excluded.solution_html,
topic=excluded.topic, subtopic=excluded.subtopic, difficulty=excluded.difficulty`);
let n = 0; db.exec('BEGIN');
try {
for (const t of TASKS) { upsert.run(EXAM, VARIANT, t.idx, t.type, t.text, t.fig || null, t.type === 'mc' ? JSON.stringify(t.opts) : null, t.answer, buildSolution(t), t.topic, t.subtopic, t.diff); n++; }
const distinct = db.prepare(`SELECT COUNT(DISTINCT variant) c FROM exam_tasks WHERE exam_key=? AND variant BETWEEN 101 AND 1999`).get(EXAM).c;
db.prepare(`UPDATE exam_tracks SET variants_count=? WHERE exam_key=?`).run(distinct, EXAM);
db.exec('COMMIT');
console.log(`\n✓ Записано/обновлено ${n} заданий (variant=${VARIANT}). variants_count=${distinct}.`);
console.log(`\nПробник: /exam-prep/ctmath → «Варианты» → «Вариант ${VARIANT}».\n`);
} catch (e) { db.exec('ROLLBACK'); console.error('\n✗ Ошибка записи, откат:', e.message); process.exitCode = 1; }
db.close();
+32 -3
View File
@@ -15,6 +15,33 @@ router.param('examKey', (req, res, next, examKey) => {
next();
});
/* ── Mock/variant picker: какие variant считаются «пробниками» ──────
ctmath: год-пачки (variant=год 20112024 и 0) — это тематический ПУЛ для
тренажёра по темам, а НЕ чистые 30-задачные варианты (у части до 114 задач).
Чистые варианты-пробники нумеруются 3-значно (101, 102, …), а год-пачки —
4-значными годами (≥2011) и 0, поэтому фильтр — ДИАПАЗОН [101;1999], а не
просто порог (год 2024 > 101 и иначе бы прошёл!). В пикере пробников,
mock/start и просмотре вариантов показываем только чистые. Тренажёр по темам
отбирает по subtopic и этот фильтр НЕ использует — пул задач не теряется.
Для остальных треков (math9: варианты 1..80) диапазона нет — показываются все. */
const MOCK_VARIANT_RANGE = { ctmath: [101, 1999] };
const isMockVariant = (examKey, v) => {
const r = MOCK_VARIANT_RANGE[examKey];
return r ? (v >= r[0] && v <= r[1]) : (v >= 1);
};
/* Человекочитаемая подпись варианта (номер в БД остаётся техническим, напр. 101).
Для ctmath варианты-пробники именуются по источнику; при добавлении новых
вариантов (104+) — дописывать сюда. Иначе fallback «Вариант N». */
const VARIANT_LABEL = {
ctmath: {
101: 'РТ-2024/25 · этап I',
102: 'РТ-2024/25 · этап II',
103: 'РТ-2024/25 · этап III',
},
};
const examVariantLabel = (examKey, v) => VARIANT_LABEL[examKey]?.[v] || `Вариант ${v}`;
/* ── Statements (prepared once) ────────────────────────────────── */
const SQL = {
listTracks: db.prepare(`
@@ -478,10 +505,10 @@ router.get('/:examKey/info', (req, res) => {
router.get('/:examKey/variants', (req, res) => {
const { examKey } = req.params;
if (!SQL.getTrack.get(examKey)) return res.status(404).json({ error: 'Unknown exam track' });
const rows = SQL.listVariants.all(req.user.id, examKey);
const rows = SQL.listVariants.all(req.user.id, examKey).filter(r => isMockVariant(examKey, r.variant));
const variants = rows.map(r => ({
n: r.variant,
label: `Вариант ${r.variant}`,
label: examVariantLabel(examKey, r.variant),
total: r.total,
solved: r.solved,
viewed_sol: r.viewed_sol,
@@ -498,6 +525,7 @@ router.get('/:examKey/variants/:n/tasks', (req, res) => {
const { examKey } = req.params;
const n = parseInt(req.params.n, 10);
if (!Number.isFinite(n) || n < 1) return res.status(400).json({ error: 'Bad variant number' });
if (!isMockVariant(examKey, n)) return res.status(404).json({ error: 'Variant not found or empty' });
const rows = SQL.getVariantTasks.all(examKey, n);
if (!rows.length) return res.status(404).json({ error: 'Variant not found or empty' });
@@ -1180,7 +1208,7 @@ router.post('/:examKey/mock/start', (req, res) => {
if (source === 'variant') {
variant = Number(req.body?.variant);
if (!Number.isInteger(variant) || variant < 1) {
if (!Number.isInteger(variant) || !isMockVariant(examKey, variant)) {
return res.status(400).json({ error: 'Variant number required' });
}
const rows = SQL.getTasksByVariant.all(examKey, variant);
@@ -1251,6 +1279,7 @@ router.get('/mock/:id', (req, res) => {
id: sess.id,
exam_key: sess.exam_key,
variant: sess.variant,
variant_label: sess.variant != null ? examVariantLabel(sess.exam_key, sess.variant) : null,
source: sess.source,
status: sess.status,
started_at: sess.started_at,
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+12 -7
View File
@@ -44,11 +44,16 @@
/* ════════════════════════════════════════════════════════════
PHASE 1: SETUP
════════════════════════════════════════════════════════════ */
function renderSetup() {
async function renderSetup() {
const title = EP.info?.track?.title || 'Пробный экзамен';
const dur = EP.info?.track?.duration_min || 180;
const tpv = EP.info?.track?.tasks_per_variant || 10;
const vc = EP.info?.track?.variants_count || 80;
// Реальный список вариантов-пробников (бэкенд уже отфильтровал год-пачки):
// номера вариантов могут быть не подряд (ctmath: 101, 102, …), поэтому
// показываем выпадающий список реальных вариантов, а не диапазон 1..N.
let vlist = [];
try { vlist = (await EP.api.listVariants(examKey)).variants || []; } catch {}
const vOpts = vlist.map(v => `<option value="${v.n}">${v.label}</option>`).join('');
main.innerHTML = `
<div class="ep-card mk-setup">
@@ -65,10 +70,10 @@
<span>По варианту</span>
</div>
<div class="mk-source-body">
<label>Номер варианта:
<input type="number" min="1" max="${vc}" value="1" id="mk-variant-input" class="mk-input" />
<label>Вариант:
<select id="mk-variant-input" class="mk-input" style="width:auto;min-width:14rem;max-width:100%">${vOpts || '<option value="">—</option>'}</select>
</label>
<div class="mk-source-hint">Один из ${vc} реальных вариантов целиком.</div>
<div class="mk-source-hint">Один из ${vlist.length} готовых вариантов целиком.</div>
</div>
</div>
@@ -116,7 +121,7 @@
if (!Number.isInteger(v) || v < 1) {
btn.disabled = false; btn.innerHTML = '<i data-lucide="play"></i> Начать пробник';
if (window.lucide) lucide.createIcons();
return alert('Введите номер варианта');
return alert('Выберите вариант');
}
body.variant = v;
} else {
@@ -144,7 +149,7 @@
const totalMs = session.duration_planned_min * 60 * 1000;
const sourceLabel = session.source === 'variant'
? `Вариант ${session.variant}`
? (session.variant_label || `Вариант ${session.variant}`)
: `Случайные ${tasks.length} задач`;
main.innerHTML = `