'use strict'; /* ─────────────────────────────────────────────────────────────────────────── seed_ctmath_ct2011_v1.js Чистый вариант-пробник для трека exam-prep `ctmath`. Источник: Централизованное тестирование (ЦТ) по математике, 2011, Вариант 1. Формат: Часть А = А1–А18, Часть В = В1–В12 (все В — числовые). Всего 30 заданий. Перенабрано вручную в KaTeX по PDF: F:\!Рабочие\ЦТ\Математика\Математика\ЦТ-ЦЭ\2011\ЦТ 2011 В1-В10.pdf (несмотря на имя «В1-В10», тест полный: А1–А18 + В1–В12; ответы — «Ответы 2011.pdf», столбец 1). ⚠️ ВСЕ 30 ответов решены самостоятельно и СВЕРЕНЫ с официальной таблицей — полное совпадение, включая B2=150, B8=16, B10=10, B12=26. variant=121. Прогнан через дедуп-гейт (check_variant_dups.js) — без повторов с видимым пулом. Уточнения по таблице (скан неоднозначен по степеням/индексам): • А6: степень $3x+4$ → $2^{3x+4}-2^{3x}=15\cdot2^{3x}$; • А9: $3^{-12}\cdot(3^{-2})^{-5}=3^{-2}=\tfrac19$; • А7: корень уравнения с радикалом = $-3$ (корень линейного множителя вне ОДЗ отброшен); • А10: осевое сечение $=10$ → боковая $=10\pi$. Реконструкции «с-картинкой» (смысл/ответ сохранены, авто-проверка): • А1 (tg не определена) → точки в тексте, ровно одна вида $\tfrac{\pi}{2}+\pi k$ ($-\tfrac{5\pi}{2}$); • А2 (параллелограмм на сетке) → основание/высота числами ($5\times4=20$); • B6 (парабола+прямая) → парабола $y=x^2-6x+9$ и прямая $y=1{,}25$ заданы явно ($4x_1x_2=31$). Без авторских ссылок (политика «все учебники наши»). Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx). Запуск: node backend/scripts/seed_ctmath_ct2011_v1.js # DRY-RUN (по умолчанию) node backend/scripts/seed_ctmath_ct2011_v1.js --apply # запись в БД ⚠️ Массовую запись в БД запускает ПОЛЬЗОВАТЕЛЬ вручную. Без --apply ничего не пишется. ─────────────────────────────────────────────────────────────────────────── */ const { DatabaseSync } = require('node:sqlite'); const path = require('path'); const APPLY = process.argv.includes('--apply'); const EXAM = 'ctmath'; const VARIANT = 121; const N_TASKS = 30; const PROV = 'ЦТ–2011, Вариант 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: 'trigonometry', subtopic: 'trig-circle', diff: 1, text: R`Функция $y=\operatorname{tg}x$ не определена в точке:`, opts: mc('$2\pi$', '$-\dfrac{5\pi}{2}$', '$\dfrac{2\pi}{5}$', '$\dfrac{\pi}{4}$', '$-3\pi$'), answer: 'б', sol: R`$\operatorname{tg}x$ не определён при $x=\dfrac{\pi}{2}+\pi k$. Из перечисленных таково $-\dfrac{5\pi}{2}=\dfrac{\pi}{2}-3\pi$.` }, { idx: 2, type: 'mc', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 1, text: R`Параллелограмм изображён на клетчатой бумаге с клетками $1\times1$ см: его основание равно $5$ см, а высота, проведённая к этому основанию, равна $4$ см. Найдите площадь параллелограмма (в квадратных сантиметрах).`, opts: mc('$10$', '$25$', '$15$', '$20$', '$18$'), answer: 'г', sol: R`Площадь параллелограмма $=$ основание $\times$ высоту $=5\cdot4=20$ см².` }, { idx: 3, type: 'mc', topic: 'numbers', subtopic: 'num-fractions', diff: 2, text: R`Если $7\tfrac29:x=4\tfrac13:3\tfrac35$ — верная пропорция, то число $x$ равно:`, opts: mc('$\dfrac23$', '$6$', '$\dfrac54$', '$\dfrac49$', '$1{,}5$'), answer: 'б', sol: R`$x=\dfrac{7\tfrac29\cdot3\tfrac35}{4\tfrac13}=\dfrac{\tfrac{65}{9}\cdot\tfrac{18}{5}}{\tfrac{13}{3}}=\dfrac{26}{\tfrac{13}{3}}=6$.` }, { idx: 4, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 1, text: R`Если $15\%$ некоторого числа равны $33$, то $20\%$ этого числа равны:`, opts: mc('$44$', '$46$', '$55$', '$56$', '$66$'), answer: 'а', sol: R`Число $=\dfrac{33}{0{,}15}=220$, тогда $20\%=0{,}2\cdot220=44$.` }, { idx: 5, type: 'mc', topic: 'equations', subtopic: 'eq-linear', diff: 1, text: R`Если $9x-24=0$, то $18x-31$ равно:`, opts: mc('$13$', '$-17$', '$17$', '$21$', '$-19$'), answer: 'в', sol: R`$x=\dfrac{24}{9}=\dfrac83$, поэтому $18x=48$ и $18x-31=17$.` }, { idx: 6, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, text: R`Для любого числа $x$ выражение $2^{3x+4}-2^{3x}$ равно:`, opts: mc('$15\cdot2^{3x}$', '$16$', '$2^{6x+1}$', '$\dfrac23\cdot2^{3x}$', '$2^{3x}$'), answer: 'а', sol: R`$2^{3x+4}-2^{3x}=2^{3x}\left(2^{4}-1\right)=15\cdot2^{3x}$.` }, { idx: 7, type: 'mc', topic: 'equations', subtopic: 'eq-irrational', diff: 2, text: R`Сумма корней (корень, если он один) уравнения $(x+5)\sqrt{x+3}=0$ равна:`, opts: mc('$-1$', '$3$', '$1$', '$-3$', '$-2$'), answer: 'г', sol: R`ОДЗ: $x\ge-3$. Корень $x=-5$ не входит в ОДЗ, остаётся $x=-3$ (из $\sqrt{x+3}=0$). Единственный корень $-3$.` }, { idx: 8, type: 'mc', topic: 'equations', subtopic: 'eq-quadratic', diff: 2, text: R`От листа жести, имеющего форму квадрата, отрезали прямоугольную полосу шириной $7$ дм, после чего площадь оставшейся части листа оказалась равной $30$ дм². Длина стороны квадратного листа (в дециметрах) была равна:`, opts: mc('$11$', '$12$', '$3$', '$9$', '$10$'), answer: 'д', sol: R`Если сторона квадрата $a$, то $a(a-7)=30$, $a^{2}-7a-30=0$, $a=10$ (второй корень $-3$ отброшен).` }, { idx: 9, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, text: R`Значение выражения $3^{-12}\cdot\left(3^{-2}\right)^{-5}$ равно:`, opts: mc('$81$', '$3^{-22}$', '$9$', '$3^{-12}$', '$\dfrac19$'), answer: 'д', sol: R`$\left(3^{-2}\right)^{-5}=3^{10}$, поэтому $3^{-12}\cdot3^{10}=3^{-2}=\dfrac19$.` }, { idx: 10, type: 'mc', topic: 'stereometry', subtopic: 'ster-rotation', diff: 2, text: R`Площадь осевого сечения цилиндра равна $10$. Площадь его боковой поверхности равна:`, opts: mc('$5\pi$', '$10\pi$', '$20\pi$', '$100\pi$', '$10$'), answer: 'б', sol: R`Осевое сечение — прямоугольник $2r\times h$ площадью $2rh=10$. Боковая поверхность $=2\pi rh=\pi\cdot2rh=10\pi$.` }, { idx: 11, type: 'mc', topic: 'numbers', subtopic: 'num-fractions', diff: 2, text: R`Найдите значение выражения $230\cdot\dfrac29-\left(\dfrac29+\dfrac1{10}\right):\dfrac1{230}$.`, opts: mc('$0{,}1$', '$43\tfrac49$', '$-0{,}1$', '$-23$', '$23$'), answer: 'г', sol: R`$230\cdot\dfrac29=\dfrac{460}{9}$; $\left(\dfrac{29}{90}\right)\cdot230=\dfrac{667}{9}$. Разность $\dfrac{460-667}{9}=-\dfrac{207}{9}=-23$.` }, { idx: 12, type: 'mc', topic: 'expressions', subtopic: 'expr-fractions', diff: 2, text: R`Упростите выражение $\dfrac{x^{2}-22x+121}{x^{2}-11x}:\dfrac{x^{2}-121}{x^{3}}$.`, opts: mc('$\dfrac{x}{x+11}$', '$\dfrac{(x-11)^{2}}{x^{4}}$', '$\dfrac{x-11}{x+11}$', '$\dfrac{x^{2}}{x-11}$', '$\dfrac{x^{2}}{x+11}$'), answer: 'д', sol: R`$\dfrac{(x-11)^{2}}{x(x-11)}\cdot\dfrac{x^{3}}{(x-11)(x+11)}=\dfrac{x^{2}}{x+11}$.` }, { idx: 13, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 2, text: R`Параллельно стороне треугольника, равной $5$, проведена прямая. Длина отрезка этой прямой, заключённого между сторонами треугольника, равна $2$. Найдите отношение площади полученной трапеции к площади исходного треугольника.`, opts: mc('$\dfrac25$', '$0{,}6$', '$\dfrac{21}{25}$', '$\dfrac{4}{25}$', '$\dfrac{3}{25}$'), answer: 'в', sol: R`Отсечённый треугольник подобен исходному с коэффициентом $\dfrac25$, его площадь составляет $\dfrac{4}{25}$. Трапеция: $1-\dfrac{4}{25}=\dfrac{21}{25}$.` }, { idx: 14, type: 'mc', topic: 'equations', subtopic: 'eq-rational', diff: 2, text: R`Сумма координат точки пересечения прямых, заданных уравнениями $2x+5y=11$ и $x+y=2(5-y)$, равна:`, opts: mc('$8$', '$-8$', '$10$', '$-10$', '$6$'), answer: 'б', sol: R`Второе уравнение: $x+3y=10$. Из системы $y=9$, $x=-17$. Сумма координат $-17+9=-8$.` }, { idx: 15, type: 'mc', topic: 'equations', subtopic: 'eq-rational', diff: 3, text: R`Количество целых решений неравенства $\dfrac{(x+3)^{2}-6x-18}{(x-5)^{2}}>0$ на промежутке $[-4;5]$ равно:`, opts: mc('$2$', '$7$', '$4$', '$5$', '$3$'), answer: 'а', sol: R`Числитель $(x+3)^{2}-6x-18=x^{2}-9$. При $x\ne5$ знаменатель положителен, поэтому неравенство равносильно $x^{2}-9>0$, то есть $x<-3$ или $x>3$. На $[-4;5]$ это $x=-4$ и $x=4$ — $2$ решения.` }, { idx: 16, type: 'mc', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 3, text: R`В ромб площадью $18\sqrt5$ вписан круг площадью $5\pi$. Сторона ромба равна:`, opts: mc('$8$', '$18$', '$\dfrac{9\sqrt5}{5}$', '$\dfrac{18\sqrt5}{5}$', '$9$'), answer: 'д', sol: R`Радиус вписанного круга: $\pi r^{2}=5\pi$, $r=\sqrt5$; высота ромба $h=2r=2\sqrt5$. Площадь $=a\cdot h$: $18\sqrt5=a\cdot2\sqrt5$, $a=9$.` }, { idx: 17, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 2, text: R`Расположите числа $\sqrt[12]{80}$; $\sqrt[3]{3}$; $\sqrt[4]{4}$ в порядке возрастания.`, opts: mc('$\sqrt[4]{4};\ \sqrt[3]{3};\ \sqrt[12]{80}$', '$\sqrt[3]{3};\ \sqrt[4]{4};\ \sqrt[12]{80}$', '$\sqrt[3]{3};\ \sqrt[12]{80};\ \sqrt[4]{4}$', '$\sqrt[4]{4};\ \sqrt[12]{80};\ \sqrt[3]{3}$', '$\sqrt[12]{80};\ \sqrt[3]{3};\ \sqrt[4]{4}$'), answer: 'г', sol: R`Возведём в $12$-ю степень: $\left(\sqrt[12]{80}\right)^{12}=80$, $\left(\sqrt[3]{3}\right)^{12}=81$, $\left(\sqrt[4]{4}\right)^{12}=64$. Так как $64<80<81$, порядок: $\sqrt[4]{4};\ \sqrt[12]{80};\ \sqrt[3]{3}$.` }, { idx: 18, type: 'mc', topic: 'trigonometry', subtopic: 'trig-equations', diff: 3, text: R`Найдите наименьший положительный корень уравнения $4\sin^{2}x+12\cos x-9=0$.`, opts: mc('$\dfrac{2\pi}{3}$', '$\arccos\dfrac52$', '$\dfrac{\pi}{3}$', '$\dfrac{\pi}{6}$', '$\pi-\arccos\dfrac52$'), answer: 'в', sol: R`$4(1-\cos^{2}x)+12\cos x-9=0$, то есть $4\cos^{2}x-12\cos x+5=0$, $\cos x=\dfrac12$ (второй корень $\dfrac52$ невозможен). Наименьший положительный корень $\dfrac{\pi}{3}$.` }, // ── Часть B: В1–В12 (все числовые) ─────────────────────────────────────── { idx: 19, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 3, text: R`Найдите произведение корней уравнения $\dfrac{3}{x+1}+1=\dfrac{10}{x^{2}+2x+1}$.`, answer: '-6', sol: R`Пусть $u=x+1$: $\dfrac3u+1=\dfrac{10}{u^{2}}$, $u^{2}+3u-10=0$, $u=2$ или $u=-5$. Тогда $x=1$ или $x=-6$, произведение $-6$.` }, { idx: 20, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 4, text: R`Диагонали трапеции равны $15$ и $20$. Найдите площадь трапеции, если её средняя линия равна $12{,}5$.`, answer: '150', sol: R`Площадь трапеции равна площади треугольника со сторонами, равными диагоналям ($15$ и $20$), и основанием, равным сумме оснований $=2\cdot12{,}5=25$. Так как $15^{2}+20^{2}=25^{2}$, треугольник прямоугольный: площадь $=\tfrac12\cdot15\cdot20=150$.` }, { idx: 21, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 4, text: R`Найдите сумму корней (или корень, если он один) уравнения $2\cdot6^{\log_7 x}=108-x^{\log_7 6}$.`, answer: '49', sol: R`Так как $x^{\log_7 6}=6^{\log_7 x}$, обозначим $t=6^{\log_7 x}$: $2t=108-t$, $t=36=6^{2}$. Тогда $\log_7 x=2$, $x=49$ — единственный корень.` }, { idx: 22, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 4, text: R`Найдите сумму целых решений неравенства $2^{3x+4}-10\cdot4^{x}+2^{x}\le0$.`, answer: '-6', sol: R`Пусть $u=2^{x}>0$: $16u^{3}-10u^{2}+u\le0$, $u(16u^{2}-10u+1)\le0$, $\dfrac18\le u\le\dfrac12$. Значит $-3\le x\le-1$; сумма целых $-3-2-1=-6$.` }, { idx: 23, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 4, text: R`По двум перпендикулярным прямым, которые пересекаются в точке $O$, движутся две точки $M_1$ и $M_2$ по направлению к точке $O$ со скоростями $1$ м/с и $2$ м/с соответственно. Достигнув точки $O$, они продолжают своё движение. В первоначальный момент времени $M_1O=5$ м, $M_2O=20$ м. Через сколько секунд расстояние между точками $M_1$ и $M_2$ будет минимальным?`, answer: '9', sol: R`Расстояние: $d^{2}=(5-t)^{2}+(20-2t)^{2}=5t^{2}-90t+425$. Минимум при $t=\dfrac{90}{10}=9$ с.` }, { idx: 24, type: 'open', topic: 'functions', subtopic: 'fn-graphs', diff: 4, text: R`Парабола $y=x^{2}-6x+9$ и горизонтальная прямая $y=1{,}25$ пересекаются в точках с абсциссами $x_1$ и $x_2$. Найдите значение выражения $4x_1\cdot x_2$.`, answer: '31', sol: R`$x^{2}-6x+9=1{,}25$, то есть $x^{2}-6x+7{,}75=0$. По теореме Виета $x_1 x_2=7{,}75$, поэтому $4x_1 x_2=31$.` }, { idx: 25, type: 'open', topic: 'planimetry', subtopic: 'plan-circle', diff: 4, text: R`Четырёхугольник $ABCD$ вписан в окружность. Если $\angle BAC=40^\circ$ и $\angle ABD=75^\circ$, то градусная мера угла между прямыми $AB$ и $CD$ равна … .`, answer: '35', sol: R`$\angle BAC=40^\circ$ опирается на дугу $BC=80^\circ$, $\angle ABD=75^\circ$ — на дугу $AD=150^\circ$. Угол между прямыми $AB$ и $CD$ равен полуразности дуг: $\dfrac{150^\circ-80^\circ}{2}=35^\circ$.` }, { idx: 26, type: 'open', topic: 'trigonometry', subtopic: 'trig-identities', diff: 4, text: R`Найдите значение выражения $\dfrac{\sin^{2}184^\circ}{4\sin^{2}23^\circ\cdot\sin^{2}2^\circ\cdot\sin^{2}44^\circ\cdot\sin^{2}67^\circ}$.`, answer: '16', sol: R`$\sin67^\circ=\cos23^\circ$ и $\sin46^\circ=\cos44^\circ$ дают знаменатель $=\dfrac1{16}\sin^{2}4^\circ$. Числитель $\sin^{2}184^\circ=\sin^{2}4^\circ$. Отношение $=16$.` }, { idx: 27, type: 'open', topic: 'word-sequences', subtopic: 'seq-progressions', diff: 4, text: R`В арифметической прогрессии $130$ членов, их сумма равна $130$, а сумма членов с чётными номерами на $130$ больше суммы членов с нечётными номерами. Найдите сотый член этой прогрессии.`, answer: '70', sol: R`Сумма чётных членов равна $130$, нечётных — $0$. Разность сумм $=65d=130$, поэтому $d=2$. Из общей суммы $a_1=-128$, тогда $a_{100}=a_1+99d=-128+198=70$.` }, { idx: 28, type: 'open', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 5, text: R`В равнобокой трапеции бóльшее основание вдвое больше каждой из остальных сторон и лежит в плоскости $\alpha$. Боковая сторона образует с плоскостью $\alpha$ угол, синус которого равен $\dfrac{5\sqrt3}{18}$. Найдите $36\sin\beta$, где $\beta$ — угол между диагональю трапеции и плоскостью $\alpha$.`, answer: '10', sol: R`Пусть боковая сторона $=b$, тогда основания $b$ и $2b$, высота трапеции $\dfrac{b\sqrt3}{2}$. Из условия $\dfrac{\sqrt3}{2}\sin\theta=\dfrac{5\sqrt3}{18}$ получаем $\sin\theta=\dfrac59$. Длина диагонали $=b\sqrt3$, и $\sin\beta=\dfrac{\sin\theta}{2}=\dfrac{5}{18}$. Значит $36\sin\beta=10$.` }, { idx: 29, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 5, text: R`Количество целых решений неравенства $2^{x+6}+\log_{0{,}5}(6-x)>13$ равно … .`, answer: '7', sol: R`ОДЗ: $x<6$. При $x=-2$ левая часть равна ровно $13$ (не годится), при $x\le-3$ меньше $13$, а при $-1\le x\le5$ — больше $13$. Целые решения: $-1,0,1,2,3,4,5$ — всего $7$.` }, { idx: 30, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 5, text: R`Основанием пирамиды $SABCD$ является ромб со стороной $2\sqrt3$ и углом $BAD$, равным $\arccos\dfrac34$. Ребро $SD$ перпендикулярно основанию, а ребро $SB$ образует с основанием угол $60^\circ$. Найдите радиус $R$ сферы, проходящей через точки $A$, $B$, $C$ и середину ребра $SB$. В ответ запишите $R^{2}$.`, answer: '26', sol: R`Диагональ $BD=\sqrt{2\cdot12\left(1-\tfrac34\right)}=\sqrt6$, $SD=BD\cdot\operatorname{tg}60^\circ=3\sqrt2$. В координатах с центром ромба: $A(0;\tfrac{\sqrt{42}}2;0)$, $B(\tfrac{\sqrt6}2;0;0)$, $C(0;-\tfrac{\sqrt{42}}2;0)$, середина $SB$ $=(0;0;\tfrac{3\sqrt2}2)$. Центр сферы $\left(-\tfrac{3\sqrt6}2;0;-\sqrt2\right)$, $R^{2}=\tfrac{54}{4}+\tfrac{42}{4}+2=26$.` }, ]; /* ── Сборка 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_ct2011_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_ct2011_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 → «Варианты» → «ЦТ-2011».\n`); } catch (e) { db.exec('ROLLBACK'); console.error('\n✗ Ошибка записи, откат транзакции:', e.message); process.exitCode = 1; } db.close();