'use strict'; /* ─────────────────────────────────────────────────────────────────────────── seed_ctmath_ct2018_v1.js Чистый вариант-пробник для трека exam-prep `ctmath`. Источник: Централизованное тестирование (ЦТ) по математике, 2018, Вариант 1. Формат: Часть А = А1–А18 (закрытые, 5 вариантов), Часть В = В1–В12 (открытые, В1 — на соответствие). Всего 30 заданий. Перенабрано вручную в KaTeX по PDF: F:\!Рабочие\ЦТ\Математика\Математика\ЦТ-ЦЭ\ЦТ 2018.pdf (10 вариантов, табл. ответов стр.32–33). ⚠️ Ответы решены самостоятельно и СВЕРЕНЫ с официальной таблицей (столбец «Вариант 1»): ВСЕ 30 совпали, включая B8=-18, B9=-130 (двугранный угол), B11=32, B12=45 (координатный метод, PT=5/2). variant=114 (после ЦТ-2016 = 113). Адаптации/реконструкции заданий-«с-картинкой» (смысл/ответ сохранены, авто-проверка): • А3 (точки на прямой) → координаты точек заданы явно (противоположны $C$ и $A$); • А9 (графики движения) → пройденные пути даны числами ($80$ и $35$ км → $2\tfrac27$); • А11 (заштрихованная лестница в квадрате) → $12$ вырезанных квадратиков $x$ → $1-12x^{2}$; • В1/В2 (функция/график) → данные функции заданы формулой/ломаной по узлам в тексте; • В8 (громоздкое показательное, в скане несогласованно) → экв. уравнение $3^{x^2}5^{x^2}=15^3$ с тем же ответом ($-18$ = $6\cdot(-3)$, корни $\pm\sqrt3$); • В10 (множитель $(6-x)^{2}$ восстановлен по официальному ответу $13$). Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx). Запуск: node backend/scripts/seed_ctmath_ct2018_v1.js # DRY-RUN (по умолчанию) node backend/scripts/seed_ctmath_ct2018_v1.js --apply # запись в БД ⚠️ Массовую запись в БД запускает ПОЛЬЗОВАТЕЛЬ вручную. Без --apply ничего не пишется. ─────────────────────────────────────────────────────────────────────────── */ const { DatabaseSync } = require('node:sqlite'); const path = require('path'); const APPLY = process.argv.includes('--apply'); const EXAM = 'ctmath'; const VARIANT = 114; const PROV = 'ЦТ–2018, Вариант 1'; const R = String.raw; const L = ['а', 'б', 'в', 'г', 'д']; const mc = (...html) => html.map((h, i) => [L[i], h]); /* ── 30 заданий ─────────────────────────────────────────────────────────── */ const TASKS = [ // ── Часть A: А1–А18 ────────────────────────────────────────────────────── { idx: 1, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`Сегодня в Лиде $24$ °C, а в Барановичах температура $t$ °C воздуха не ниже, чем в Лиде. Укажите верное соотношение для $t$.`, opts: mc('$t>24$', '$t=23$', '$t\ge24$', '$t\le24$', '$t<24$'), answer: 'в', sol: R`«Не ниже $24$» означает «больше или равно $24$»: $t\ge24$.`, ref: 'Алгебра, 8 класс, гл. 1' }, { idx: 2, type: 'mc', topic: 'planimetry', subtopic: 'plan-circle', diff: 2, text: R`Две окружности с центрами $A$ и $B$ касаются внешним образом в точке $C$. Точки $M$ и $K$ — концы их диаметров, лежащих на прямой $AB$ (в порядке $M,A,C,B,K$). Найдите радиус большей окружности, если радиус меньшей равен $5$, а $MK=28$.`, opts: mc('$9$', '$10$', '$14$', '$18$', '$8$'), answer: 'а', sol: R`$MK=2\cdot5+2R=28$, где $R$ — больший радиус, откуда $2R=18$, $R=9$.`, ref: 'Геометрия, 9 класс, гл. 1' }, { idx: 3, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`На координатной прямой отмечены точки $D(-3)$, $C(-2)$, $A(2)$, $B(5)$. Укажите точки, координаты которых являются противоположными числами.`, opts: mc('$A$ и $D$', '$A$ и $C$', '$B$ и $D$', '$B$ и $C$', '$A$ и $B$'), answer: 'б', sol: R`Противоположные числа $-2$ и $2$ — это координаты точек $C$ и $A$.`, ref: 'Математика, 6 класс, гл. 5' }, { idx: 4, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2, text: R`Из вершины угла $KMN$, градусная мера которого равна $170^\circ$, проведены два луча: $MP$, делящий угол пополам, и $MF$, делящий его в отношении $9:8$ (считая от стороны $MK$). Найдите градусную меру угла $FMP$.`, opts: mc('$20^\circ$', '$17^\circ$', '$4^\circ$', '$10^\circ$', '$5^\circ$'), answer: 'д', sol: R`$\angle KMP=\dfrac{170^\circ}{2}=85^\circ$, $\angle KMF=170^\circ\cdot\dfrac{9}{17}=90^\circ$. Тогда $\angle FMP=90^\circ-85^\circ=5^\circ$.`, ref: 'Геометрия, 7 класс, гл. 2' }, { idx: 5, type: 'mc', topic: 'word-sequences', subtopic: 'seq-progressions', diff: 1, text: R`Известно, что число $177$ является членом арифметической прогрессии $(a_n)$, заданной формулой $a_n=6n-3$. Найдите его номер.`, opts: mc('$30$', '$29$', '$27$', '$26$', '$25$'), answer: 'а', sol: R`$6n-3=177$, $6n=180$, $n=30$.`, ref: 'Алгебра, 9 класс, гл. 4' }, { idx: 6, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, text: R`Вычислите $8^{\,1+\log_{8}6}$.`, opts: mc('$6$', '$14$', '$24$', '$48$', '$56$'), answer: 'г', sol: R`$8^{\,1+\log_{8}6}=8\cdot8^{\log_{8}6}=8\cdot6=48$.`, ref: 'Алгебра, 11 класс, гл. 3' }, { idx: 7, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 1, text: R`Укажите уравнение прямой, проходящей через точку $A(5;9)$ параллельно оси абсцисс.`, opts: mc('$x=5$', '$y=5$', '$y=9$', '$x=9$', '$5x+9y=0$'), answer: 'в', sol: R`Прямая, параллельная оси абсцисс, горизонтальна, поэтому имеет вид $y=b$. Через точку $A(5;9)$ проходит прямая $y=9$.`, ref: 'Алгебра, 7 класс, гл. 5' }, { idx: 8, type: 'mc', topic: 'expressions', subtopic: 'expr-polynomials', diff: 2, text: R`Для одночлена $-5c^{3}\cdot3c^{2}y$ укажите номер верного утверждения.`, opts: mc('стандартный вид одночлена — $-15c^{5}y$', 'значение при $c=-1$, $y=-1$ равно $15$', 'при делении на $3$ получится $-c^{5}y$', 'коэффициент одночлена равен $-5$', 'степень одночлена равна $5$'), answer: 'а', sol: R`$-5c^{3}\cdot3c^{2}y=-15c^{5}y$ — это стандартный вид (утверждение 1). Остальные неверны: значение при $c=-1,y=-1$ равно $-15$; деление на $3$ даёт $-5c^{5}y$; коэффициент $-15$; степень $5+1=6$.`, ref: 'Алгебра, 7 класс, гл. 2' }, { idx: 9, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2, text: R`Мотоциклист и велосипедист выехали одновременно из одного пункта в одном направлении. По графику движения к некоторому моменту мотоциклист проехал $80$ км, а велосипедист — $35$ км. Во сколько раз скорость мотоциклиста больше скорости велосипедиста?`, opts: mc('$3\tfrac12$ раза', '$1\tfrac19$ раза', '$2\tfrac17$ раза', '$2\tfrac27$ раза', '$2\tfrac{1}{16}$ раза'), answer: 'г', sol: R`За одно и то же время отношение скоростей равно отношению путей: $\dfrac{80}{35}=\dfrac{16}{7}=2\tfrac27$.`, ref: 'Алгебра, 7 класс, гл. 3' }, { idx: 10, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, text: R`Значение выражения $\sqrt{\left(11+8\sqrt2\right)^{2}}+\sqrt{\left(11-8\sqrt2\right)^{2}}$ равно:`, opts: mc('$16\sqrt2$', '$38\sqrt2$', '$22$', '$16\sqrt2-22$', '$16\sqrt2+22$'), answer: 'а', sol: R`$\sqrt{(11+8\sqrt2)^{2}}=11+8\sqrt2$; так как $8\sqrt2>11$, то $\sqrt{(11-8\sqrt2)^{2}}=8\sqrt2-11$. Сумма $=(11+8\sqrt2)+(8\sqrt2-11)=16\sqrt2$.`, ref: 'Алгебра, 8 класс, гл. 2' }, { idx: 11, type: 'mc', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 2, text: R`Из квадрата со стороной $1$ удалили $12$ равных квадратов со стороной $x$. Найдите выражение для площади оставшейся (заштрихованной) части квадрата.`, opts: mc('$1-4x^{2}$', '$4-12x^{2}$', '$1-8x^{2}$', '$4-16x$', '$1-12x^{2}$'), answer: 'д', sol: R`Площадь квадрата равна $1$, площадь $12$ вырезанных квадратиков — $12x^{2}$. Оставшаяся часть: $1-12x^{2}$.`, ref: 'Алгебра, 7 класс, гл. 2' }, { idx: 12, type: 'mc', topic: 'trigonometry', subtopic: 'trig-identities', diff: 2, text: R`Найдите значение выражения $\sin\left(\operatorname{arctg}\sqrt3\right)$.`, opts: mc('$\dfrac{\sqrt3}{3}$', '$\dfrac12$', '$\dfrac{\sqrt3}{2}$', '$\dfrac{\sqrt2}{2}$', '$1$'), answer: 'в', sol: R`$\operatorname{arctg}\sqrt3=60^\circ$, поэтому $\sin60^\circ=\dfrac{\sqrt3}{2}$.`, ref: 'Алгебра, 10 класс, гл. 1' }, { idx: 13, type: 'mc', topic: 'equations', subtopic: 'eq-rational', diff: 2, text: R`Найдите сумму наименьшего и наибольшего целых решений двойного неравенства $-5{,}2<3-0{,}1x<4{,}59$.`, opts: mc('$96$', '$97$', '$65$', '$67$', '$66$'), answer: 'д', sol: R`Из $3-0{,}1x<4{,}59$: $x>-15{,}9$; из $-5{,}2<3-0{,}1x$: $x<82$. Целые $x$ от $-15$ до $81$; их сумма наименьшего и наибольшего $-15+81=66$.`, ref: 'Алгебра, 8 класс, гл. 3' }, { idx: 14, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 3, text: R`Длины двух сторон треугольника равны $6$ и $7$, его площадь равна $3\sqrt{33}$. Найдите наибольшее значение, которое может принимать длина третьей стороны.`, opts: mc('$\sqrt{151}$', '$\sqrt{133}$', '$12$', '$13$', '$2\sqrt{33}$'), answer: 'б', sol: R`$S=\dfrac12\cdot6\cdot7\sin C=21\sin C=3\sqrt{33}$, поэтому $\sin C=\dfrac{\sqrt{33}}{7}$, $\cos C=\pm\dfrac47$. Третья сторона $c^{2}=36+49-84\cos C$; наибольшая при $\cos C=-\dfrac47$: $c^{2}=85+48=133$, $c=\sqrt{133}$.`, ref: 'Геометрия, 9 класс, гл. 1' }, { idx: 15, type: 'mc', topic: 'equations', subtopic: 'eq-linear', diff: 2, text: R`Укажите номер уравнения, которое имеет более одного корня.`, opts: mc('$5x+2=2$', '$2(9-2x)=-4x$', '$\dfrac25x+7=x$', '$\dfrac{5x+2}{3}=4$', '$5x+2=\dfrac{15x+6}{3}$'), answer: 'д', sol: R`Уравнение $5x+2=\dfrac{15x+6}{3}=5x+2$ — тождество, верно при любом $x$ (бесконечно много корней). Остальные имеют ровно один корень или ни одного.`, ref: 'Алгебра, 7 класс, гл. 1' }, { idx: 16, type: 'mc', topic: 'stereometry', subtopic: 'ster-rotation', diff: 3, text: R`Найдите объём конуса, образующая которого равна $4\sqrt6$, а угол при вершине осевого сечения равен $60^\circ$.`, opts: mc('$144\sqrt2\,\pi$', '$16\sqrt2\,\pi$', '$48\sqrt2\,\pi$', '$48\sqrt6\,\pi$', '$384\sqrt2\,\pi$'), answer: 'в', sol: R`Осевое сечение — равнобедренный треугольник с углом $60^\circ$ при вершине, то есть равносторонний. Радиус $R=l\sin30^\circ=4\sqrt6\cdot\dfrac12=2\sqrt6$, высота $h=l\cos30^\circ=4\sqrt6\cdot\dfrac{\sqrt3}{2}=6\sqrt2$. Объём $V=\dfrac13\pi R^{2}h=\dfrac13\pi\cdot24\cdot6\sqrt2=48\sqrt2\,\pi$.`, ref: 'Геометрия, 11 класс, разд. 2' }, { idx: 17, type: 'mc', topic: 'trigonometry', subtopic: 'trig-equations', diff: 3, text: R`Сумма (в градусах) наименьшего положительного и наибольшего отрицательного корней уравнения $\sin(5x-10^\circ)=-\dfrac{\sqrt2}{2}$ равна:`, opts: mc('$81^\circ$', '$55^\circ$', '$60^\circ$', '$40^\circ$', '$35^\circ$'), answer: 'г', sol: R`$5x-10^\circ=-45^\circ+360^\circ k$ или $5x-10^\circ=225^\circ+360^\circ k$, то есть $x=-7^\circ+72^\circ k$ или $x=47^\circ+72^\circ k$. Наименьший положительный корень $47^\circ$, наибольший отрицательный $-7^\circ$; их сумма $40^\circ$.`, ref: 'Алгебра, 10 класс, гл. 1, § 8' }, { idx: 18, type: 'mc', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 4, text: R`$ABCA_1B_1C_1$ — правильная треугольная призма, все рёбра которой равны $9$. Точки $P$ и $K$ — середины рёбер $BB_1$ и $AC$, точка $M$ на ребре $CC_1$ такова, что $C_1M:C_1C=1:3$. Найдите длину отрезка, по которому плоскость, проходящая через $K,M,P$, пересекает грань $AA_1B_1B$.`, opts: mc('$\dfrac{9\sqrt5}{7}$', '$\dfrac{9\sqrt{85}}{14}$', '$\dfrac{9\sqrt2}{2}$', '$\dfrac{9\sqrt{65}}{14}$', '$\dfrac{3\sqrt{17}}{2}$'), answer: 'б', sol: R`Введём координаты $A(0;0;0)$, $B(9;0;0)$, $C\left(4{,}5;\dfrac{9\sqrt3}{2};0\right)$ и верхние вершины со сдвигом $+9$ по оси $z$. Секущая плоскость через $K,M,P$ пересекает грань $AA_1B_1B$ (плоскость $y=0$) по прямой $10{,}5x-9z=54$. Её отрезок внутри грани идёт от $\left(\dfrac{36}{7};0;0\right)$ до $P(9;0;4{,}5)$; длина $\sqrt{\left(\dfrac{27}{7}\right)^{2}+4{,}5^{2}}=\dfrac{9\sqrt{85}}{14}$.`, ref: 'Геометрия, 10 класс, разд. 4' }, // ── Часть B: В1–В12 ────────────────────────────────────────────────────── { idx: 19, type: 'long', topic: 'functions', subtopic: 'fn-properties', diff: 3, text: R`Функция задана формулой $f(x)=x^{2}-10x-3$ на множестве $\mathbb{R}$. Для начала каждого из предложений А–В подберите его окончание $1$–$6$ так, чтобы получилось верное утверждение.
А) Сумма координат точки пересечения графика с осью $Oy$ равна …
Б) Сумма нулей функции равна …
В) Если ось симметрии графика задаётся уравнением $x=a$, то значение $a$ равно …
Окончания: $1)\;-3$; $\ 2)\;3$; $\ 3)\;5$; $\ 4)\;-10$; $\ 5)\;-5$; $\ 6)\;10$.`, answer: 'А1Б6В3', ansShow: 'А1Б6В3', sol: R`А) График пересекает $Oy$ в точке $(0;f(0))=(0;-3)$, сумма координат $-3$ (окончание 1). Б) Сумма нулей по теореме Виета равна $10$ (окончание 6). В) Ось симметрии $x=\dfrac{10}{2}=5$, значит $a=5$ (окончание 3). Ответ: А1Б6В3.`, ref: 'Алгебра, 8 класс, гл. 3' }, { idx: 20, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 3, text: R`Функция $y=f(x)$ на промежутке $[-6;4]$ задана ломаной, последовательно соединяющей точки $(-6;-1)$, $(-5;0)$, $(-4;1)$, $(-3;1)$, $(-2;0)$, $(0;-3)$, $(2;-2)$, $(4;3)$. Выберите номера верных утверждений (запишите цифрами в порядке возрастания).
$1)$ нулём функции является число $-3$;
$2)$ $f(x)>0$ при $x\in(-5;-2)$;
$3)$ функция возрастает на промежутке $[2;4]$;
$4)$ наибольшее значение функции на $[-6;4]$ равно $2$;
$5)$ график пересекает ось ординат в точке $(0;-2)$.`, answer: '23', sol: R`Нули функции — $-5$ и $-2$ (не $-3$), значит 1 неверно. На $(-5;-2)$ ломаная положительна — 2 верно. На $[2;4]$: $f(2)=-2b$, $a+b=85$ и НОК$(a;b)=102$. Найдите число $b$.`, answer: '34', sol: R`Пусть $d=$НОД$(a;b)$, $a=dm$, $b=dn$, $\gcd(m;n)=1$. Тогда $d(m+n)=85$, $dmn=102$; общий делитель $85$ и $102$ равен $17$, поэтому $d=17$, $m+n=5$, $mn=6$, откуда $m=3$, $n=2$. Значит $a=51$, $b=34$.`, ref: 'Алгебра, 9 класс, гл. 4' }, { idx: 26, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 3, text: R`Найдите увеличенное в $6$ раз произведение корней уравнения $3^{x^{2}}\cdot5^{x^{2}}=15^{3}$.`, answer: '-18', sol: R`$3^{x^{2}}\cdot5^{x^{2}}=15^{x^{2}}=15^{3}$, поэтому $x^{2}=3$, $x=\pm\sqrt3$. Произведение корней $-3$; увеличенное в $6$ раз — это $-18$.`, ref: 'Алгебра, 11 класс, гл. 2' }, { idx: 27, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 4, text: R`В основании пирамиды $SABCD$ лежит квадрат $ABCD$ со стороной $1$. Боковое ребро $SB$ перпендикулярно плоскости основания и равно $3$. Найдите значение выражения $\dfrac{13}{\cos\varphi}$, где $\varphi$ — линейный угол двугранного угла при боковом ребре $SD$.`, answer: '-130', sol: R`Координаты $A(0;0;0)$, $B(1;0;0)$, $C(1;1;0)$, $D(0;1;0)$, $S(1;0;3)$. Для двугранного угла при ребре $SD$ берём в гранях $SAD$ и $SCD$ векторы из $D$, перпендикулярные $DS$. Вычисление даёт $\cos\varphi=-\dfrac{1}{10}$, поэтому $\dfrac{13}{\cos\varphi}=-130$.`, ref: 'Геометрия, 10 класс, разд. 4' }, { idx: 28, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 4, text: R`Найдите сумму целых решений неравенства $\dfrac{(x^{2}-x-12)(6-x)^{2}}{6-x^{2}-x}\ge0$.`, answer: '13', sol: R`После сокращения на $(x+3)$ (при $x\ne-3$): $\dfrac{(x-4)(6-x)^{2}}{-(x-2)}\ge0$. Множитель $(6-x)^{2}\ge0$, поэтому решение — промежуток $(2;4]$ и отдельная точка $x=6$. Целые решения $3,4,6$; их сумма $13$.`, ref: 'Алгебра, 9 класс, гл. 3' }, { idx: 29, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 5, text: R`От пристани $B$ отплывает плот и одновременно против течения отходит катер. Доплыв до пристани $A$ (на расстоянии $s_1$ от $B$ выше по течению), катер разворачивается и плывёт к пристани $C$ (на расстоянии $s_2$ ниже по течению от $B$). Найдите наибольшее возможное значение скорости катера (в км/ч) в стоячей воде, при которой он прибудет к $C$ не раньше плота, если скорость течения равна $4$ км/ч и $s_1:s_2=7:2$.`, answer: '32', sol: R`Пусть $u$ — скорость катера, $s_1=7k$, $s_2=2k$. Время плота $\dfrac{2k}{4}=\dfrac{k}{2}$, время катера $\dfrac{7k}{u-4}+\dfrac{9k}{u+4}$. Наибольшему $u$ отвечает равенство $\dfrac{7}{u-4}+\dfrac{9}{u+4}=\dfrac12$, откуда $u^{2}-32u=0$, $u=32$.`, ref: 'Алгебра, 9 класс, гл. 1' }, { idx: 30, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 5, text: R`В правильной треугольной пирамиде $SABC$ с вершиной $S$ проведена медиана $CM$ треугольника $SBC$ ($M$ — середина $SB$); $BC=2\sqrt7$, $SB=\sqrt{85}$. Через середину $K$ ребра $SC$ проведена прямая $KD$, параллельная ребру $AB$. Через точку $A$ проведена прямая, пересекающая прямые $CM$ и $KD$ в точках $P$ и $T$ соответственно. Найдите увеличенную в $18$ раз длину отрезка $PT$.`, answer: '45', sol: R`Введём координаты основания (сторона $2\sqrt7$) и вершины $S$ (из $SB=\sqrt{85}$ высота $h^{2}=\dfrac{227}{3}$). Прямая через $A$, пересекающая $CM$ и $KD$, определяется условием коллинеарности: $P$ делит $CM$ так, что $\lambda=\dfrac23$, а $T$ лежит на $KD$. Тогда $PT^{2}=\left(\dfrac{2\sqrt7}{3}\right)^{2}+\left(\dfrac{2\sqrt{21}}{9}\right)^{2}+\left(\dfrac{h}{6}\right)^{2}=\dfrac{2025}{324}$, откуда $PT=\dfrac{45}{18}=\dfrac52$. Увеличенная в $18$ раз длина — $45$.`, ref: 'Геометрия, 11 класс, разд. 1' }, ]; /* ── Сборка 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 !== 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`); 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_ct2018_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 ответов пройдены (30/30).'); /* ── APPLY: upsert ─────────────────────────────────────────────────────────── */ if (!APPLY) { console.log('\nDRY-RUN: ничего не записано. Для записи: node backend/scripts/seed_ctmath_ct2018_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 → «Варианты» → «ЦТ-2018».\n`); } catch (e) { db.exec('ROLLBACK'); console.error('\n✗ Ошибка записи, откат транзакции:', e.message); process.exitCode = 1; } db.close();