'use strict'; /* ─────────────────────────────────────────────────────────────────────────── seed_ctmath_ct2014_v1.js Чистый вариант-пробник для трека exam-prep `ctmath`. Источник: Централизованное тестирование (ЦТ) по математике, 2014, Вариант 1. Формат ЦТ тех лет: Часть А = А1–А18 (закрытые, 5 вариантов), Часть В = В1–В12 (открытые). Всего 30 заданий. Перенабрано вручную в KaTeX по PDF: F:\!Рабочие\ЦТ\Математика\Математика\ЦТ-ЦЭ\ЦТ 2014.pdf ⚠️ В PDF РЕШЕНИЙ НЕТ (только задания). Решения и ответы получены вручную и СВЕРЕНЫ с официальной таблицей ответов в конце сборника (стр. 34, столбец «Вариант 1»). variant=110 (после РТ-вариантов 101–109). Адаптации заданий-«с-картинкой» (исходный ответ/идея сохранены, авто-проверка): • А2 (выбор рисунка с симметричными фигурами — неразборчиво в скане) → эквивалентный MC о симметрии точки относительно оси; • А6 (параллелограмм на координатной сетке) → координаты вершин заданы в тексте (та же длина диагонали $AC=4\sqrt2$); • А10 (касательные/секущая) и А15 (таблица поставщиков) — закодированы текстом (данные с рисунка/таблицы перенесены в условие). Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx). Запуск: node backend/scripts/seed_ctmath_ct2014_v1.js # DRY-RUN (по умолчанию) node backend/scripts/seed_ctmath_ct2014_v1.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 = 110; const PROV = 'ЦТ–2014, Вариант 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`Даны дроби: $1\frac67$, $\ 1\frac17$, $\ 6\frac67$, $\ 7\frac17$, $\ 6\frac17$. Укажите дробь, которая равна дроби $\dfrac{43}{7}$.`, opts: mc('$1\frac67$', '$1\frac17$', '$6\frac67$', '$7\frac17$', '$6\frac17$'), answer: 'д', sol: R`$\dfrac{43}{7}=6\frac17$, так как $43=6\cdot7+1$.`, ref: 'Математика, 5 класс, ч. 1, гл. 2' }, { idx: 2, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 1, text: R`Точка $M(-3;4)$ симметрична точке $N$ относительно оси абсцисс. Укажите координаты точки $N$.`, opts: mc('$(3;4)$', '$(-3;-4)$', '$(3;-4)$', '$(-4;-3)$', '$(-3;4)$'), answer: 'б', sol: R`При симметрии относительно оси абсцисс абсцисса точки сохраняется, а ордината меняет знак: $N(-3;-4)$.`, ref: 'Математика, 6 класс, гл. 5' }, { idx: 3, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 1, text: R`Прямые $a$ и $b$ пересекаются, образуя четыре угла. Известно, что сумма трёх из этих углов равна $210^\circ$. Найдите градусную меру меньшего угла.`, opts: mc('$150^\circ$', '$15^\circ$', '$30^\circ$', '$10^\circ$', '$105^\circ$'), answer: 'в', sol: R`При пересечении двух прямых вертикальные углы равны, а смежные дают $180^\circ$. Сумма трёх углов равна $180^\circ+x$, где $x$ — один из углов; $180^\circ+x=210^\circ$, $x=30^\circ$ — меньший угол.`, ref: 'Геометрия, 7 класс, гл. 2' }, { idx: 4, type: 'mc', topic: 'expressions', subtopic: 'expr-polynomials', diff: 1, text: R`Результат разложения многочлена $x(6a-b)+b-6a$ на множители имеет вид:`, opts: mc('$x$', '$x+1$', '$(6a-b)(x+1)$', '$(6a-b)(x+b)$', '$(6a-b)(x-1)$'), answer: 'д', sol: R`$x(6a-b)+b-6a=x(6a-b)-(6a-b)=(6a-b)(x-1)$.`, ref: 'Алгебра, 7 класс, гл. 2, § 14' }, { idx: 5, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`Вычислите $\dfrac{7{,}3^{2}-2{,}4^{2}+9{,}7\cdot1{,}1}{6}$.`, opts: mc('$\dfrac97$', '$\dfrac32$', '$9$', '$9{,}7$', '$3{,}41$'), answer: 'г', sol: R`$\dfrac{53{,}29-5{,}76+10{,}67}{6}=\dfrac{58{,}2}{6}=9{,}7$.`, ref: 'Математика, 6 класс, гл. 4' }, { idx: 6, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 2, text: R`Вершины параллелограмма $ABCD$ имеют координаты $A(-2;-1)$, $B(-3;2)$, $C(2;3)$, $D(3;0)$. Найдите длину диагонали $AC$.`, opts: mc('$4$', '$5$', '$4\sqrt2$', '$5\sqrt2$', '$9\sqrt2$'), answer: 'в', sol: R`$AC=\sqrt{(2-(-2))^{2}+(3-(-1))^{2}}=\sqrt{16+16}=4\sqrt2$.`, ref: 'Математика, 6 класс, гл. 7' }, { idx: 7, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2, text: R`Длины катетов прямоугольного треугольника являются корнями уравнения $x^{2}-9x+12=0$. Найдите площадь треугольника.`, opts: mc('$6$', '$9$', '$10{,}5$', '$12$', '$4{,}5$'), answer: 'а', sol: R`По теореме Виета произведение корней (катетов) равно $12$. Площадь прямоугольного треугольника $=\dfrac12\cdot12=6$.`, ref: 'Алгебра, 8 класс, гл. 2; Геометрия, 8 класс, гл. 2' }, { idx: 8, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`Пусть $a=5{,}4$, $b=3{,}2\cdot10^{1}$. Найдите произведение $ab$ и запишите его в стандартном виде.`, opts: mc('$0{,}1728\cdot10^{3}$', '$1728\cdot10^{-1}$', '$1{,}728\cdot10^{2}$', '$1{,}728$', '$172{,}8$'), answer: 'в', sol: R`$ab=5{,}4\cdot32=172{,}8=1{,}728\cdot10^{2}$.`, ref: 'Алгебра, 7 класс, гл. 1, § 3' }, { idx: 9, type: 'mc', topic: 'expressions', subtopic: 'expr-fractions', diff: 2, text: R`Выразите $x$ из равенства $\dfrac{2+y}{5}=\dfrac{x-y}{15}$.`, opts: mc('$x=4y-6$', '$x=4y+6$', '$x=20y+30$', '$x=20y-30$', '$x=2y+2$'), answer: 'б', sol: R`$15(2+y)=5(x-y)$, $3(2+y)=x-y$, $6+3y=x-y$, $x=4y+6$.`, ref: 'Алгебра, 7 класс, гл. 2' }, { idx: 10, type: 'mc', topic: 'planimetry', subtopic: 'plan-circle', diff: 2, text: R`Из точки $A$ к окружности проведены касательные $AB$ и $AC$ и секущая $AM$, проходящая через центр окружности $O$ (точки $B$, $C$, $M$ лежат на окружности). Отрезок $BK$ перпендикулярен $AM$ ($K$ на $AM$), $BK=4$, $AC=9$. Найдите длину отрезка $AK$.`, opts: mc('$4$', '$\sqrt{97}$', '$65$', '$5$', '$\sqrt{65}$'), answer: 'д', sol: R`Касательные, проведённые из одной точки, равны: $AB=AC=9$. В прямоугольном треугольнике $ABK$ ($\angle K=90^\circ$): $AK=\sqrt{AB^{2}-BK^{2}}=\sqrt{81-16}=\sqrt{65}$.`, ref: 'Геометрия, 8 класс, гл. 4' }, { idx: 11, type: 'mc', topic: 'equations', subtopic: 'eq-rational', diff: 2, text: R`Даны два числа. Известно, что одно из них меньше другого на $6$. Какому условию удовлетворяет меньшее число $x$, если его удвоенный квадрат не больше суммы квадратов этих чисел?`, opts: mc('$x\le3$', '$x\le-3$', '$x\ge-3$', '$x\ge3$', '$x\le12$'), answer: 'в', sol: R`Числа $x$ и $x+6$. Условие $2x^{2}\le x^{2}+(x+6)^{2}$, то есть $2x^{2}\le2x^{2}+12x+36$, $0\le12x+36$, $x\ge-3$.`, ref: 'Алгебра, 8 класс, гл. 3' }, { idx: 12, type: 'mc', topic: 'expressions', subtopic: 'expr-fractions', diff: 2, text: R`Свежие фрукты при сушке теряют $a\%$ своей массы. Укажите выражение, определяющее массу сухих фруктов (в килограммах), полученных из $20$ кг свежих.`, opts: mc('$\dfrac{2000}{a}$', '$\dfrac{20(100-a)}{100}$', '$\dfrac{2000}{100-a}$', '$\dfrac{20(100+a)}{100}$', '$\dfrac{2000}{100+a}$'), answer: 'б', sol: R`Сухие фрукты составляют $(100-a)\%$ массы свежих: $20\cdot\dfrac{100-a}{100}=\dfrac{20(100-a)}{100}$.`, ref: 'Математика, 6 класс, гл. 2' }, { idx: 13, type: 'mc', topic: 'stereometry', subtopic: 'ster-rotation', diff: 2, text: R`Объём конуса равен $5$, а его высота равна $\dfrac12$. Найдите площадь основания конуса.`, opts: mc('$\dfrac56$', '$\dfrac{10}{3}$', '$10$', '$30$', '$\dfrac{15}{2}$'), answer: 'г', sol: R`$V=\dfrac13 S h$, поэтому $5=\dfrac13 S\cdot\dfrac12=\dfrac{S}{6}$, откуда $S=30$.`, ref: 'Геометрия, 11 класс, разд. 2' }, { idx: 14, type: 'mc', topic: 'functions', subtopic: 'fn-properties', diff: 2, text: R`Известно, что наименьшее значение функции, заданной формулой $y=x^{2}+8x+c$, равно $-3$. Тогда значение $c$ равно:`, opts: mc('$13$', '$16$', '$-51$', '$-19$', '$19$'), answer: 'а', sol: R`Наименьшее значение квадратичной функции равно $c-\dfrac{8^{2}}{4}=c-16$. Из $c-16=-3$ получаем $c=13$.`, ref: 'Алгебра, 8 класс, гл. 3' }, { idx: 15, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2, text: R`Строительная бригада планирует заказать фундаментные блоки у одного из трёх поставщиков. Поставщик 1: стоимость блока $335$ тыс. руб., доставка $1850$ тыс. руб.; поставщик 2: блок $365$, доставка $970$; поставщик 3: блок $420$, доставка бесплатно. При покупке какого количества блоков самыми выгодными будут условия второго поставщика?`, opts: mc('от $18$ до $29$', 'более $17$', 'от $30$ до $55$', 'менее $30$', 'от $17$ до $30$'), answer: 'а', sol: R`Стоимость заказа $n$ блоков: $P_1=335n+1850$, $P_2=365n+970$, $P_3=420n$. Условие $P_2970$, $n\ge18$. Значит, второй поставщик выгоднее при $18\le n\le29$.`, ref: 'Алгебра, 7 класс, гл. 3' }, { idx: 16, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, text: R`Расположите числа $8^{10}$, $3^{18}$, $31^{6}$ в порядке возрастания.`, opts: mc('$3^{18};\ 8^{10};\ 31^{6}$', '$8^{10};\ 3^{18};\ 31^{6}$', '$31^{6};\ 3^{18};\ 8^{10}$', '$3^{18};\ 31^{6};\ 8^{10}$', '$31^{6};\ 8^{10};\ 3^{18}$'), answer: 'г', sol: R`$8^{10}=2^{30}\approx1{,}07\cdot10^{9}$; $\ 3^{18}=9^{9}\approx3{,}87\cdot10^{8}$; $\ 31^{6}\approx8{,}9\cdot10^{8}$. Порядок возрастания: $3^{18};\ 31^{6};\ 8^{10}$.`, ref: 'Алгебра, 10 класс, гл. 1' }, { idx: 17, type: 'mc', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 3, text: R`Через вершину $A$ прямоугольного треугольника $ABC$ ($\angle C=90^\circ$) проведён перпендикуляр $AK$ к его плоскости. Найдите расстояние от точки $K$ до прямой $BC$, если $AK=2$, $AB=4$, $BC=\sqrt{11}$.`, opts: mc('$3$', '$2\sqrt5$', '$\sqrt5$', '$\sqrt{15}$', '$6$'), answer: 'а', sol: R`$AC=\sqrt{AB^{2}-BC^{2}}=\sqrt{16-11}=\sqrt5$. Так как $BC\perp AC$ и $BC\perp AK$, то $BC$ перпендикулярна плоскости $ACK$, поэтому расстояние от $K$ до $BC$ равно $CK=\sqrt{AK^{2}+AC^{2}}=\sqrt{4+5}=3$.`, ref: 'Геометрия, 10 класс, разд. 3' }, { idx: 18, type: 'mc', topic: 'equations', subtopic: 'eq-irrational', diff: 3, text: R`Сумма корней (корень, если он единственный) уравнения $\sqrt{2x+5}\cdot\sqrt{x-1}=3-x$ равна (равен):`, opts: mc('$\dfrac{-9-\sqrt{137}}{2}$', '$9$', '$18$', '$\dfrac{-9+\sqrt{137}}{2}$', '$-14$'), answer: 'г', sol: R`ОДЗ: $x\ge1$ и $3-x\ge0$, то есть $x\in[1;3]$. Возведя в квадрат: $(2x+5)(x-1)=(3-x)^{2}$, $x^{2}+9x-14=0$, $x=\dfrac{-9\pm\sqrt{137}}{2}$. В $[1;3]$ попадает только $\dfrac{-9+\sqrt{137}}{2}$.`, ref: 'Алгебра, 10 класс, гл. 2, § 17' }, // ── Часть B: В1–В12 ────────────────────────────────────────────────────── { idx: 19, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 2, text: R`Найдите сумму целых решений (решение, если оно единственное) системы неравенств $\begin{cases}2x+8\ge x^{2},\\(x-1)^{2}>0.\end{cases}$`, answer: '6', sol: R`$2x+8\ge x^{2}\Rightarrow x^{2}-2x-8\le0\Rightarrow-2\le x\le4$; $\ (x-1)^{2}>0\Rightarrow x\ne1$. Целые решения $-2,-1,0,2,3,4$; их сумма равна $6$.`, ref: 'Алгебра, 8 класс, гл. 3' }, { idx: 20, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 3, text: R`Найдите произведение большего корня на количество корней уравнения $\dfrac{21}{x^{2}-4x+10}-x^{2}+4x=6$.`, answer: '6', sol: R`Пусть $u=x^{2}-4x$, тогда $\dfrac{21}{u+10}-u=6$, откуда $u^{2}+16u+39=0$, $u=-3$ или $u=-13$. При $u=-3$: $x^{2}-4x+3=0$, $x=1;3$. При $u=-13$ дискриминант отрицателен. Корни $1$ и $3$, больший $3$, количество $2$; произведение $3\cdot2=6$.`, ref: 'Алгебра, 9 класс, гл. 1' }, { idx: 21, type: 'open', topic: 'planimetry', subtopic: 'plan-circle', diff: 3, text: R`В окружность радиусом $6$ вписан треугольник, длины двух сторон которого равны $6$ и $10$. Найдите длину высоты треугольника, проведённой к его третьей стороне.`, answer: '5', sol: R`Из формул $S=\dfrac{abc}{4R}$ и $S=\dfrac12 c\,h_c$ следует $h_c=\dfrac{ab}{2R}=\dfrac{6\cdot10}{2\cdot6}=5$.`, ref: 'Геометрия, 9 класс, гл. 1' }, { idx: 22, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 3, text: R`Найдите сумму наименьшего и наибольшего целых решений неравенства $\log_{0{,}3}(x+54)\le2\log_{0{,}3}(x-2)$.`, answer: '13', sol: R`Неравенство равносильно $\log_{0{,}3}(x+54)\le\log_{0{,}3}(x-2)^{2}$ при $x>2$. Основание $0{,}3<1$, поэтому $x+54\ge(x-2)^{2}$, то есть $x^{2}-5x-50\le0$, $-5\le x\le10$. С учётом $x>2$: $(2;10]$. Целые $3,\ldots,10$; сумма наименьшего и наибольшего $3+10=13$.`, ref: 'Алгебра, 11 класс, гл. 3' }, { idx: 23, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 3, text: R`Найдите сумму (в градусах) наименьшего положительного и наибольшего отрицательного корней уравнения $\sin4x-\sqrt3\cos2x=0$.`, answer: '-15', sol: R`$\sin4x=2\sin2x\cos2x$, поэтому $\cos2x(2\sin2x-\sqrt3)=0$. Из $\cos2x=0$: $x=45^\circ+90^\circ n$; из $\sin2x=\dfrac{\sqrt3}{2}$: $x=30^\circ+180^\circ n$ или $x=60^\circ+180^\circ n$. Наименьший положительный корень $30^\circ$, наибольший отрицательный $-45^\circ$; их сумма $-15^\circ$.`, ref: 'Алгебра, 10 класс, гл. 1, § 8' }, { idx: 24, type: 'open', topic: 'word-sequences', subtopic: 'seq-progressions', diff: 4, text: R`Три числа составляют геометрическую прогрессию, в которой $q>1$. Если второй член прогрессии уменьшить на $8$, то полученные три числа в том же порядке опять составят геометрическую прогрессию. Если третий член новой прогрессии уменьшить на $25$, то полученные числа составят арифметическую прогрессию. Найдите сумму исходных чисел.`, answer: '21', sol: R`Пусть числа $a$, $aq$, $aq^{2}$. Из условия $(aq-8)^{2}=a\cdot aq^{2}$ следует $aq=4$. Новая прогрессия $a,\,-4,\,aq^{2}$, где $a\cdot aq^{2}=16$. Условие арифметической прогрессии: $2\cdot(-4)=a+(aq^{2}-25)$, то есть $a+aq^{2}=17$. Так как $aq^{2}=\dfrac{16}{a}$, получаем $a+\dfrac{16}{a}=17$, $a=1$ (тогда $q=4>1$). Числа $1,4,16$, их сумма $21$.`, ref: 'Алгебра, 9 класс, гл. 4' }, { idx: 25, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 3, text: R`Найдите произведение суммы корней уравнения $4^{x-1}-2^{x-1}=2^{x+5}-2^{6}$ на их количество.`, answer: '16', sol: R`Пусть $t=2^{x-1}$. Тогда $t^{2}-t=64t-64$, $t^{2}-65t+64=0$, $t=1$ или $t=64$. Из $2^{x-1}=1$: $x=1$; из $2^{x-1}=64$: $x=7$. Сумма корней $8$, количество $2$; произведение $8\cdot2=16$.`, ref: 'Алгебра, 11 класс, гл. 2' }, { idx: 26, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 4, text: R`Найдите количество корней уравнения $\cos x=\left|\dfrac{x}{11\pi}\right|$.`, answer: '22', sol: R`Правая часть неотрицательна и не больше $1$ при $|x|\le11\pi$, поэтому требуется $\cos x\ge0$. Обе функции чётные. На $(0;11\pi]$ прямая $\dfrac{x}{11\pi}$ пересекает положительные «арки» косинуса $11$ раз; столько же на отрицательной полуоси. Всего $22$ корня.`, ref: 'Алгебра, 10 класс, гл. 1' }, { idx: 27, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 4, text: R`Найдите сумму целых решений неравенства $\dfrac{|4x-10|-|2x-14|}{(x+3)(x-6)}\le0$.`, answer: '7', sol: R`Числитель равен нулю при $x=-2$ и $x=4$; он положителен вне отрезка $[-2;4]$ и отрицателен внутри него. Знаменатель положителен при $x<-3$ и $x>6$, отрицателен при $-3Ответ: ${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_ct2014_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_ct2014_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 → «Варианты» → «ЦТ-2014».\n`); } catch (e) { db.exec('ROLLBACK'); console.error('\n✗ Ошибка записи, откат транзакции:', e.message); process.exitCode = 1; } db.close();