'use strict'; /* ─────────────────────────────────────────────────────────────────────────── seed_ctmath_ct2020_v1.js Чистый вариант-пробник для трека exam-prep `ctmath`. Источник: Централизованное тестирование (ЦТ) по математике, 2020, Вариант 1. Формат 2020: Часть А = А1–А20 (закрытые), Часть В = В1–В12 (открытые; В1 — на соответствие, В2 — множественный выбор). Всего **32 задания** (не 30!). Перенабрано вручную в KaTeX по PDF: F:\!Рабочие\ЦТ\Математика\Математика\ЦТ-ЦЭ\ЦТ 2020.pdf (10 вариантов, табл. ответов стр.44). ⚠️ Ответы решены самостоятельно и СВЕРЕНЫ с официальной таблицей (стр.44, столбец «Вариант 1»): ВСЕ 32 совпали, включая A20=37√13/3, B5=-335, B8=-320, B9=160, B10=577, B11=-16, B12=336. variant=116 (после ЦТ-2019 = 115). Реконструкции заданий-«с-картинкой» (смысл/ответ сохранены, авто-проверка): • А9 (точка и прямая на сетке) → A(-1;2), прямая l: y=-x; симметрия → (-2;1); • А11 (графики плот/катер) → скорость плота и расстояние даны числами (→ 960 мин); • А2/А7 — добавлены явные условия (точки на одной дуге; M,N — середины сторон); • В1/В2 — данные предложений/утверждений приведены текстом (как в оригинале). Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx). Без авторских ссылок (политика «все учебники наши»). Запуск: node backend/scripts/seed_ctmath_ct2020_v1.js # DRY-RUN (по умолчанию) node backend/scripts/seed_ctmath_ct2020_v1.js --apply # запись в БД ⚠️ Массовую запись в БД запускает ПОЛЬЗОВАТЕЛЬ вручную. Без --apply ничего не пишется. ─────────────────────────────────────────────────────────────────────────── */ const { DatabaseSync } = require('node:sqlite'); const path = require('path'); const APPLY = process.argv.includes('--apply'); const EXAM = 'ctmath'; const VARIANT = 116; const N_TASKS = 32; const PROV = 'ЦТ–2020, Вариант 1'; const R = String.raw; const L = ['а', 'б', 'в', 'г', 'д']; const mc = (...html) => html.map((h, i) => [L[i], h]); /* ── 32 задания ─────────────────────────────────────────────────────────── */ const TASKS = [ // ── Часть A: А1–А20 ────────────────────────────────────────────────────── { idx: 1, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 1, text: R`Укажите номер точки, которая принадлежит графику функции $y=5^{x}$.`, opts: mc('$(25;2)$', '$(2;10)$', '$(5;25)$', '$(2;25)$', '$(1;0)$'), answer: 'г', sol: R`При $x=2$ имеем $y=5^{2}=25$, поэтому точка $(2;25)$ лежит на графике.` }, { idx: 2, type: 'mc', topic: 'planimetry', subtopic: 'plan-circle', diff: 2, text: R`Вписанный угол $KML$ равен $38^\circ$. Точки $M$ и $N$ лежат на одной дуге окружности (по одну сторону от хорды $KL$). Найдите вписанный угол $KNL$.`, opts: mc('$46^\circ$', '$38^\circ$', '$19^\circ$', '$52^\circ$', '$76^\circ$'), answer: 'б', sol: R`Вписанные углы, опирающиеся на одну и ту же дугу $KL$ с одной стороны, равны: $\angle KNL=\angle KML=38^\circ$.` }, { idx: 3, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`Укажите номер выражения для натурального числа, содержащего $c$ десятков и $3$ единицы ($c$ — цифра).`, opts: mc('$c+3$', '$3c$', '$3c+10$', '$10c+3$', '$30+c$'), answer: 'г', sol: R`$c$ десятков и $3$ единицы — это $10c+3$.` }, { idx: 4, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`Определите, на сколько неизвестное слагаемое меньше суммы, если $x+20=80$.`, opts: mc('$80$', '$20$', '$60$', '$40$', '$100$'), answer: 'б', sol: R`Неизвестное слагаемое $x=80-20=60$, сумма равна $80$. Разность $80-60=20$.` }, { idx: 5, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`Среди точек $C(33)$, $D(24)$, $E(28)$, $F(43)$, $K(12)$ координатной прямой укажите точку, симметричную точке $A(5)$ относительно точки $B(19)$.`, opts: mc('$C(33)$', '$D(24)$', '$E(28)$', '$F(43)$', '$K(12)$'), answer: 'а', sol: R`Симметричная точка имеет координату $2\cdot19-5=33$ — это точка $C(33)$.` }, { idx: 6, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 2, text: R`Найдите значение выражения $\left(3\tfrac17-2\right)\cdot\left(1+\tfrac34\right):9$.`, opts: mc('$1\tfrac{41}{63}$', '$\tfrac{3}{28}$', '$1\tfrac{19}{252}$', '$-\tfrac{11}{36}$', '$\tfrac29$'), answer: 'д', sol: R`$\left(\tfrac{22}{7}-2\right)\cdot\tfrac74:9=\tfrac87\cdot\tfrac74:9=2:9=\tfrac29$.` }, { idx: 7, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2, text: R`В треугольнике $ABC$ $\angle ABC=104^\circ$, $\angle ACB=29^\circ$. Точки $M$ и $N$ — середины сторон $BC$ и $AC$ соответственно. Найдите градусную меру угла $ANM$ четырёхугольника $ABMN$.`, opts: mc('$151^\circ$', '$128^\circ$', '$119^\circ$', '$133^\circ$', '$104^\circ$'), answer: 'г', sol: R`$MN$ — средняя линия, поэтому $MN\parallel AB$ и $\angle MNC=\angle BAC=180^\circ-104^\circ-29^\circ=47^\circ$. Так как $A,N,C$ лежат на одной прямой, $\angle ANM=180^\circ-47^\circ=133^\circ$.` }, { idx: 8, type: 'mc', topic: 'numbers', subtopic: 'num-divisibility', diff: 1, text: R`У Юры некоторое количество марок, а у Яна — в $2$ раза больше. Все марки поместили в один альбом. Среди чисел $26$, $38$, $20$, $37$, $39$ выберите то, которое может выражать количество марок в альбоме.`, opts: mc('$26$', '$38$', '$20$', '$37$', '$39$'), answer: 'д', sol: R`Всего марок $x+2x=3x$ — число, кратное $3$. Из данных чисел кратно $3$ только $39$.` }, { idx: 9, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 2, text: R`Даны точка $A(-1;2)$ и прямая $l$, заданная уравнением $y=-x$. Найдите координаты точки, симметричной точке $A$ относительно прямой $l$.`, opts: mc('$(1;1)$', '$(-1;0)$', '$(-2;1)$', '$(0;2)$', '$(-2;4)$'), answer: 'в', sol: R`Симметрия относительно прямой $y=-x$ переводит точку $(x;y)$ в $(-y;-x)$, поэтому $(-1;2)\to(-2;1)$.` }, { idx: 10, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 2, text: R`График уравнения $1{,}8x-0{,}6y=a$ проходит через точку $A(-2;9)$. Найдите число $a$.`, opts: mc('$-9$', '$9$', '$7$', '$-18$', '$-2{,}4$'), answer: 'а', sol: R`$a=1{,}8\cdot(-2)-0{,}6\cdot9=-3{,}6-5{,}4=-9$.` }, { idx: 11, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2, text: R`Из двух пунктов навстречу друг другу одновременно отправляются плот (по течению) и катер (против течения). По графику движения скорость плота (равная скорости течения) составляет $0{,}5$ км/ч, а расстояние между пунктами — $8$ км. За сколько минут плот придёт в пункт, из которого отправился катер?`, opts: mc('$1020$ мин', '$960$ мин', '$510$ мин', '$900$ мин', '$480$ мин'), answer: 'б', sol: R`Плоту нужно пройти $8$ км со скоростью $0{,}5$ км/ч: $\dfrac{8}{0{,}5}=16$ ч $=960$ мин.` }, { idx: 12, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, text: R`Внесите множитель под знак корня в выражении $-x\cdot\sqrt[5]{2x^{2}}$.`, opts: mc('$\sqrt[5]{2x^{3}}$', '$\sqrt[5]{2x^{7}}$', '$\sqrt[5]{-2x^{7}}$', '$\sqrt[5]{-2x^{3}}$', '$\sqrt[5]{-2x^{10}}$'), answer: 'в', sol: R`$-x\cdot\sqrt[5]{2x^{2}}=\sqrt[5]{(-x)^{5}\cdot2x^{2}}=\sqrt[5]{-2x^{7}}$.` }, { idx: 13, type: 'mc', topic: 'planimetry', subtopic: 'plan-circle', diff: 2, text: R`В окружности радиуса $13$ проведена хорда $AB$. Точка $M$ делит хорду $AB$ на отрезки длиной $10$ и $12$. Найдите расстояние от точки $M$ до центра окружности.`, opts: mc('$11$', '$7$', '$5$', '$6$', '$8$'), answer: 'б', sol: R`По свойству хорд $AM\cdot MB=R^{2}-OM^{2}$: $10\cdot12=169-OM^{2}$, откуда $OM^{2}=49$, $OM=7$.` }, { idx: 14, type: 'mc', topic: 'equations', subtopic: 'eq-rational', diff: 3, text: R`Для неравенства $(8-x)(x+3)\ge0$ укажите номера верных утверждений.
$1)$ число $0$ не является решением неравенства;
$2)$ неравенство равносильно неравенству $|x|\le8$;
$3)$ количество всех целых решений неравенства равно $12$;
$4)$ неравенство верно при $x\in[-2;3]$;
$5)$ решением неравенства является промежуток $[-8;3]$.`, opts: mc('$2$ и $4$', '$3$ и $5$', '$3$ и $4$', '$1$ и $2$', '$1$ и $5$'), answer: 'в', sol: R`Решение неравенства — отрезок $[-3;8]$. Тогда: $0$ — решение (1 неверно); $|x|\le8$ даёт $[-8;8]$ (2 неверно); целых решений от $-3$ до $8$ ровно $12$ (3 верно); на $[-2;3]$ неравенство выполнено (4 верно); промежуток $[-3;8]$, не $[-8;3]$ (5 неверно). Верны $3$ и $4$.` }, { idx: 15, type: 'mc', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 2, text: R`Длины диагоналей ромба являются корнями уравнения $0{,}1x^{2}-2{,}2x+7{,}4=0$. Найдите площадь ромба.`, opts: mc('$22$', '$48$', '$74$', '$11$', '$37$'), answer: 'д', sol: R`Уравнение равносильно $x^{2}-22x+74=0$; по теореме Виета произведение корней-диагоналей $d_1d_2=74$. Площадь ромба $\tfrac12 d_1d_2=37$.` }, { idx: 16, type: 'mc', topic: 'planimetry', subtopic: 'plan-circle', diff: 3, text: R`На одной стороне прямого угла с вершиной $O$ отмечены точки $A$ и $B$ так, что $OA=1{,}7$, $OB=a$, $OAА) Разность этой прогрессии равна …
Б) Первый член этой прогрессии равен …
В) Сумма первых восьми членов этой прогрессии равна …
Окончания: $1)\;2$; $\ 2)\;-13$; $\ 3)\;4$; $\ 4)\;-26$; $\ 5)\;-20$; $\ 6)\;3$.`, answer: 'А6Б2В5', ansShow: 'А6Б2В5', sol: R`$a_9-a_5=4d=12$, $d=3$ (окончание 6). $a_{10}=a_1+9d=14$, $a_1=-13$ (окончание 2). $S_8=4(2a_1+7d)=4(-26+21)=-20$ (окончание 5). Ответ: А6Б2В5.` }, { idx: 22, type: 'open', topic: 'trigonometry', subtopic: 'trig-identities', diff: 3, text: R`Выберите номера трёх верных утверждений, если известно, что $\sin\alpha=\sin23^\circ$ и $\cos\alpha=-\cos23^\circ$ (запишите цифрами в порядке возрастания).
$1)$ $\sin(\alpha+23^\circ)=0$;
$2)$ $\operatorname{tg}\alpha>0$;
$3)$ $\operatorname{ctg}\alpha<0$;
$4)$ $\alpha$ — угол первой четверти;
$5)$ $\sin^{2}\alpha+\cos^{2}\alpha=1$;
$6)$ $\alpha=-23^\circ$.`, answer: '135', sol: R`Из условий $\alpha=157^\circ$ (вторая четверть). Тогда $\sin(157^\circ+23^\circ)=\sin180^\circ=0$ (1 верно); $\operatorname{tg}157^\circ<0$ (2 неверно); $\operatorname{ctg}157^\circ<0$ (3 верно); это вторая четверть (4 неверно); основное тождество всегда верно (5 верно); $\alpha\ne-23^\circ$ (6 неверно). Верны $1,3,5$.` }, { idx: 23, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 3, text: R`В каждую из трёх корзин положили одинаковое количество яблок. Если в одну из корзин добавить $19$ яблок, то в ней окажется меньше, чем в двух других корзинах вместе. Если же в эту корзину положить ещё $23$ яблока, то в ней их станет больше, чем было первоначально в трёх корзинах вместе. Сколько яблок было в каждой корзине первоначально?`, answer: '20', sol: R`Пусть в корзине $x$ яблок. Тогда $x+19<2x$, то есть $x>19$; и $x+19+23>3x$, то есть $x<21$. Значит $x=20$.` }, { idx: 24, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 3, text: R`В равнобедренную трапецию, площадь которой равна $115$, вписана окружность радиуса $5$. Найдите периметр трапеции.`, answer: '46', sol: R`Высота $h=2r=10$. Площадь $\tfrac12(a+b)h=5(a+b)=115$, откуда $a+b=23$. Для описанной около окружности трапеции сумма оснований равна сумме боковых сторон, поэтому периметр $=2(a+b)=46$.` }, { idx: 25, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 4, text: R`Найдите произведение наименьшего корня (в градусах) на количество различных корней уравнения $\sin5x=\cos65^\circ$ на промежутке $(-90^\circ;90^\circ)$.`, answer: '-335', sol: R`$\cos65^\circ=\sin25^\circ$, поэтому $5x=25^\circ+360^\circ k$ или $5x=155^\circ+360^\circ k$, то есть $x=5^\circ+72^\circ k$ или $x=31^\circ+72^\circ k$. На $(-90^\circ;90^\circ)$ корни $-67^\circ,-41^\circ,5^\circ,31^\circ,77^\circ$ — всего $5$; наименьший $-67^\circ$. Произведение $-67\cdot5=-335$.` }, { idx: 26, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 4, text: R`Точки $N$ и $M$ лежат на сторонах $AB$ и $AD$ параллелограмма $ABCD$ так, что $AN:NB=1:2$ и $AM:MD=1:2$. Площадь треугольника $CMN$ равна $45$. Найдите площадь параллелограмма $ABCD$.`, answer: '162', sol: R`Пусть площадь параллелограмма равна $S$. Через векторы $\vec{AB}$ и $\vec{AD}$ площадь треугольника $CMN$ равна $\tfrac{5}{18}S$. Из $\tfrac{5}{18}S=45$ получаем $S=162$.` }, { idx: 27, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 5, text: R`Найдите произведение наибольшего целого отрицательного и наибольшего целого положительного решений неравенства $3\cdot16^{\frac{x^{2}-29}{-3x}}-10\cdot16^{\frac{x^{2}-29}{-6x}}>8$.`, answer: '-32', sol: R`Пусть $t=16^{\frac{x^{2}-29}{-6x}}>0$. Тогда $3t^{2}-10t-8>0$, $(3t+2)(t-4)>0$, значит $t>4$, то есть $\frac{x^{2}-29}{-6x}>\tfrac12$, что приводит к $\frac{x^{2}+3x-29}{x}<0$. Решение: $x<\frac{-3-5\sqrt5}{2}$ или $00$, $x\ne17$. Уравнение приводится к $\log_{18}\bigl(x\,|17-x|\bigr)=1$, то есть $x\,|17-x|=18$. При $x<17$: $x^{2}-17x+18=0$ (корни $p,q$ с $p+q=17$, $pq=18$); при $x>17$: $x=18$. Сумма квадратов $(17^{2}-2\cdot18)+18^{2}=253+324=577$.` }, { idx: 31, type: 'open', topic: 'numbers', subtopic: 'num-divisibility', diff: 5, text: R`Найдите все пары $(m,n)$ целых чисел, связанных соотношением $m^{2}+2m=n^{2}-6n+13$. Пусть $k$ — количество таких пар, $m_0$ — наименьшее из значений $m$. Найдите значение выражения $k\cdot m_0$.`, answer: '-16', sol: R`Равенство приводится к $(m+1)^{2}-(n-3)^{2}=5$. Полагая $a=m+1$, $b=n-3$, имеем $(a-b)(a+b)=5$; целые решения дают пары $(m;n)$: $(2;5),(2;1),(-4;1),(-4;5)$. Значит $k=4$, $m_0=-4$, и $k\cdot m_0=-16$.` }, { idx: 32, type: 'open', topic: 'stereometry', subtopic: 'ster-rotation', diff: 5, text: R`$ABCDA_1B_1C_1D_1$ — куб, длина ребра которого равна $4\sqrt6$. Сфера проходит через его вершины $B$ и $D_1$ и середины рёбер $BB_1$ и $CC_1$. Найдите площадь сферы $S$ и в ответ запишите значение выражения $\dfrac{S}{\pi}$.`, answer: '336', sol: R`В координатах с ребром $a$ центр сферы — $\left(\tfrac{a}{4};\tfrac{a}{2};\tfrac{a}{4}\right)$, а $R^{2}=\tfrac{7a^{2}}{8}$. При $a=4\sqrt6$ ($a^{2}=96$) получаем $R^{2}=84$, $S=4\pi R^{2}=336\pi$ и $\dfrac{S}{\pi}=336$.` }, ]; /* ── Сборка solution_html ────────────────────────────────────────────────── */ function ansShowOf(t) { if (t.ansShow != null) return t.ansShow; if (t.type === 'mc') return `${t.answer})`; return `$${t.answer}$`; } function buildSolution(t) { const ans = ansShowOf(t); let html = `${t.sol}
Ответ: ${ans}
`; if (t.ref) html += `
Учебник: ${t.ref}
`; 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 !== N_TASKS) problems.push(`Ожидалось ${N_TASKS} заданий, получено ${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 > N_TASKS) problems.push(`task_idx вне 1..${N_TASKS}: ${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}: answer "${t.answer}" не проходит self-check (Unicode-минус? пробел?)`); 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_ct2020_v1 (${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), '\n'); console.log('idx | type | subtopic | d | answer'); 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)}`); } 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 ответов пройдены (${N_TASKS}/${N_TASKS}).`); /* ── APPLY: upsert ─────────────────────────────────────────────────────────── */ if (!APPLY) { console.log('\nDRY-RUN: ничего не записано. Для записи: node backend/scripts/seed_ctmath_ct2020_v1.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++; } 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 → «Варианты» → «ЦТ-2020».\n`); } catch (e) { db.exec('ROLLBACK'); console.error('\n✗ Ошибка записи, откат транзакции:', e.message); process.exitCode = 1; } db.close();