'use strict'; /* ─────────────────────────────────────────────────────────────────────────── seed_ctmath_ct2015_v1.js Чистый вариант-пробник для трека exam-prep `ctmath`. Источник: Централизованное тестирование (ЦТ) по математике, 2015, Вариант 1. Формат ЦТ тех лет: Часть А = А1–А18 (закрытые, 5 вариантов), Часть В = В1–В12 (открытые). Всего 30 заданий. Перенабрано вручную в KaTeX по PDF: F:\!Рабочие\ЦТ\Математика\Математика\ЦТ-ЦЭ\ЦТ 2015.pdf (10 изоморфных вариантов; таблица ответов — стр. 35). ⚠️ Ответы. В таблице ответов колонка «Вариант 1» затемнена (часть ячеек нечитаема). Поэтому ответы получены РЕШЕНИЕМ каждого задания и сверены: (1) с читаемыми ячейками столбца В1 (B2=-15, B3=7, B7=147, B8=-6 — совпали); (2) со структурно-изоморфными вариантами 2–10 (их столбцы читаемы). variant=112 (после ЦЭ-2024 = 111). Адаптации заданий-«с-картинкой» (смысл/ответ сохранены, авто-проверка): • А4 (выбор рисунка с центрально-симметричными фигурами) → эквивалентный MC о центральной симметрии точки относительно начала координат; • А6 (выбор рисунка с множеством решений системы) → та же система неравенств, но спрашивается само множество решений (интервал); • А11 (столбчатая диаграмма) → те же данные приведены таблицей в figure_html; • А12 (выбор эскиза параболы) → верное утверждение о вершине/направлении ветвей параболы $y=1-(x+3)^2$; • А15 (треугольник по узлам сетки) → координаты вершин заданы в тексте ($\cos\angle ABC=-\tfrac{5}{13}$ сохранён); • В11 (громоздкое лог-выражение, неразборчиво в скане) → эквивалентная задача на $2^{A}$ с сохранённым ответом $225=15^{2}$ (пэттерн столбца В11: $n^2$). Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx). Запуск: node backend/scripts/seed_ctmath_ct2015_v1.js # DRY-RUN (по умолчанию) node backend/scripts/seed_ctmath_ct2015_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 = 112; const PROV = 'ЦТ–2015, Вариант 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`На координатной прямой точки расположены слева направо в порядке $O,C,B,A,F,D$. Точка $O$ имеет координату $0$, а соседние отмеченные точки находятся на равных расстояниях $\dfrac17$ друг от друга. Если координата точки $A$ равна $\dfrac97$, то числу $1$ соответствует точка:`, opts: mc('$C$', '$B$', '$D$', '$F$', '$O$'), answer: 'а', sol: R`Шаг между соседними точками равен $\dfrac17$, поэтому $B=\dfrac87$, $C=\dfrac77=1$. Числу $1$ соответствует точка $C$.`, ref: 'Математика, 6 класс, гл. 5' }, { idx: 2, type: 'mc', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 1, text: R`Запишите $\left(11^{x}\right)^{y}$ в виде степени с основанием $11$.`, opts: mc('$11^{x/y}$', '$11^{x+y}$', '$11^{2x+2y}$', '$11^{2xy}$', '$11^{xy}$'), answer: 'д', sol: R`По свойству степени $\left(11^{x}\right)^{y}=11^{xy}$.`, ref: 'Алгебра, 7 класс, гл. 1, § 4' }, { idx: 3, type: 'mc', topic: 'word-sequences', subtopic: 'seq-progressions', diff: 1, text: R`Арифметическая прогрессия $(a_n)$ задана формулой $n$-го члена $a_n=5n-2$. Найдите разность этой прогрессии.`, opts: mc('$3$', '$-7$', '$5$', '$7$', '$-5$'), answer: 'в', sol: R`$d=a_{n+1}-a_n=\bigl(5(n+1)-2\bigr)-(5n-2)=5$.`, ref: 'Алгебра, 9 класс, гл. 4' }, { idx: 4, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 1, text: R`Точка $K(5;-2)$ симметрична точке $L$ относительно точки $O$ — начала координат. Укажите координаты точки $L$.`, opts: mc('$(-5;2)$', '$(5;2)$', '$(-5;-2)$', '$(2;-5)$', '$(-2;5)$'), answer: 'а', sol: R`При центральной симметрии относительно начала координат обе координаты меняют знак: $L(-5;2)$.`, ref: 'Математика, 6 класс, гл. 5' }, { idx: 5, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 1, text: R`Вычислите $\dfrac{3732\cdot0{,}01-5}{0{,}47+1{,}13}$.`, opts: mc('$20{,}2$', '$2{,}2$', '$202$', '$22$', '$2{,}02$'), answer: 'а', sol: R`$\dfrac{37{,}32-5}{1{,}6}=\dfrac{32{,}32}{1{,}6}=20{,}2$.`, ref: 'Математика, 6 класс, гл. 4' }, { idx: 6, type: 'mc', topic: 'equations', subtopic: 'eq-rational', diff: 2, text: R`Укажите множество решений системы неравенств $\begin{cases}x\le-1{,}6,\\ 1-2x<9.\end{cases}$`, opts: mc('$(-4;-1{,}6]$', '$[-1{,}6;+\infty)$', '$(-\infty;-4)$', '$[-4;-1{,}6)$', '$(-1{,}6;4)$'), answer: 'а', sol: R`Из $1-2x<9$ следует $-2x<8$, то есть $x>-4$. Вместе с $x\le-1{,}6$ получаем $-4ДеньВсе покупателиПо акциипонедельник44001600вторник55002600среда34001800четверг47002200пятница65001800`, opts: mc('понедельник', 'вторник', 'среда', 'четверг', 'пятница'), answer: 'д', sol: R`Доля покупателей по акции: пн — $\dfrac{1600}{4400}\approx0{,}36$; вт — $\dfrac{2600}{5500}\approx0{,}47$; ср — $\dfrac{1800}{3400}\approx0{,}53$; чт — $\dfrac{2200}{4700}\approx0{,}47$; пт — $\dfrac{1800}{6500}\approx0{,}28$. Менее $0{,}3$ — только в пятницу.`, ref: 'Математика, 6 класс, гл. 2' }, { idx: 12, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 2, text: R`Графиком функции $y=1-(x+3)^{2}$ является парабола. Укажите верное утверждение о её расположении.`, opts: mc('ветви вверх, вершина $(3;1)$', 'ветви вниз, вершина $(-3;1)$', 'ветви вниз, вершина $(3;1)$', 'ветви вверх, вершина $(-3;-1)$', 'ветви вниз, вершина $(-3;-1)$'), answer: 'б', sol: R`$y=-(x+3)^{2}+1$: коэффициент при квадрате отрицателен (ветви направлены вниз), вершина в точке $(-3;1)$.`, ref: 'Алгебра, 8 класс, гл. 3' }, { idx: 13, type: 'mc', topic: 'equations', subtopic: 'eq-exponential', diff: 2, text: R`Уравнение $\dfrac{4x-9}{5}+2=x-\dfrac{11-x}{5}$ равносильно уравнению:`, opts: mc('$6^{x}=1$', '$6^{x}=6$', '$2^{x}=32$', '$2^{x}=64$', '$5^{x}=25$'), answer: 'г', sol: R`Умножив на $5$: $4x-9+10=5x-(11-x)$, то есть $4x+1=6x-11$, откуда $x=6$. Этому корню равносильно уравнение $2^{x}=64$ (ведь $2^{6}=64$).`, ref: 'Алгебра, 11 класс, гл. 2' }, { idx: 14, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2, text: R`Собственная скорость катера в $9$ раз больше скорости течения реки. Расстояние по реке от пункта $A$ до пункта $B$ плот проплыл за время $t_1$, а катер — за время $t_2$. Тогда верна формула:`, opts: mc('$t_1=10t_2$', '$t_1=9t_2$', '$t_1=9{,}5t_2$', '$t_1=10{,}5t_2$', '$t_1=11t_2$'), answer: 'а', sol: R`Пусть скорость течения $v$. Плот плывёт со скоростью течения: $t_1=\dfrac{S}{v}$. Катер по течению имеет скорость $9v+v=10v$: $t_2=\dfrac{S}{10v}$. Значит $t_1=10t_2$.`, ref: 'Алгебра, 7 класс, гл. 3' }, { idx: 15, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 3, text: R`На координатной плоскости дан тупоугольный треугольник $ABC$ с вершинами $A(2;3)$, $B(0;0)$, $C(2;-3)$. Найдите $\cos\angle ABC$.`, opts: mc('$\dfrac{5}{12}$', '$\dfrac{5}{13}$', '$-\dfrac{5}{13}$', '$-\dfrac{12}{13}$', '$\dfrac{12}{13}$'), answer: 'в', sol: R`$\vec{BA}=(2;3)$, $\vec{BC}=(2;-3)$. $\cos\angle ABC=\dfrac{\vec{BA}\cdot\vec{BC}}{|\vec{BA}|\,|\vec{BC}|}=\dfrac{2\cdot2+3\cdot(-3)}{\sqrt{13}\cdot\sqrt{13}}=-\dfrac{5}{13}$.`, ref: 'Геометрия, 9 класс, гл. 3' }, { idx: 16, type: 'mc', topic: 'stereometry', subtopic: 'ster-rotation', diff: 2, text: R`Из полного бокала, имеющего форму конуса высотой $9$, отлили треть (по объёму) жидкости. Вычислите $\dfrac12 h^{3}$, где $h$ — высота оставшейся жидкости.`, opts: mc('$324$', '$182$', '$27$', '$243$', '$81$'), answer: 'г', sol: R`Оставшаяся жидкость составляет $\tfrac23$ объёма и образует подобный конус высотой $h$: $\left(\dfrac{h}{9}\right)^{3}=\dfrac23$, откуда $h^{3}=729\cdot\dfrac23=486$. Тогда $\dfrac12 h^{3}=243$.`, ref: 'Геометрия, 11 класс, разд. 2' }, { idx: 17, type: 'mc', topic: 'functions', subtopic: 'fn-properties', diff: 2, text: R`График функции, заданной формулой $y=kx+b$, симметричен относительно оси $Oy$ и проходит через точку $A\left(\tfrac13;6\right)$. Значение выражения $k+b$ равно:`, opts: mc('$-5\tfrac23$', '$6\tfrac13$', '$6$', '$2$', '$18$'), answer: 'в', sol: R`Симметрия относительно оси $Oy$ означает чётность функции: $-kx+b=kx+b$ при всех $x$, откуда $k=0$. Тогда $y=b$, и из прохождения через $A$ получаем $b=6$. Значит $k+b=6$.`, ref: 'Алгебра, 8 класс, гл. 3' }, { idx: 18, type: 'mc', topic: 'planimetry', subtopic: 'plan-triangles', diff: 3, text: R`Высоты остроугольного равнобедренного треугольника $ABC$ ($AB=BC$) пересекаются в точке $O$. Если высота $AD=15$ и $AO=10$, то длина стороны $AC$ равна:`, opts: mc('$17$', '$7\sqrt6$', '$5\sqrt3$', '$10\sqrt3$', '$5\sqrt{13}$'), answer: 'г', sol: R`Поместим $A(-a;0)$, $C(a;0)$, $B(0;h)$. Ортоцентр $O\left(0;\dfrac{a^{2}}{h}\right)$. Тогда $AO=\dfrac{a\sqrt{a^{2}+h^{2}}}{h}=10$, а высота $AD=\dfrac{2ah}{\sqrt{a^{2}+h^{2}}}=15$. Отсюда $a^{2}=75$, $h=15$, поэтому $AC=2a=10\sqrt3$.`, ref: 'Геометрия, 9 класс, гл. 3' }, // ── Часть B: В1–В12 ────────────────────────────────────────────────────── { idx: 19, type: 'open', topic: 'word-sequences', subtopic: 'word-problems', diff: 2, text: R`Витя купил в магазине некоторое количество тетрадей, заплатив за них $24$ тысячи рублей. Затем он обнаружил, что в другом магазине тетрадь стоит на $1$ тысячу рублей меньше, поэтому, заплатив такую же сумму, он мог бы купить на $2$ тетради больше. Сколько тетрадей купил Витя?`, answer: '6', sol: R`Пусть цена тетради $p$ (тыс. руб.), куплено $n=\dfrac{24}{p}$ тетрадей. Тогда $\dfrac{24}{p-1}=\dfrac{24}{p}+2$, откуда $p(p-1)=12$, $p=4$. Значит $n=\dfrac{24}{4}=6$.`, ref: 'Алгебра, 8 класс, гл. 2' }, { idx: 20, type: 'open', topic: 'equations', subtopic: 'eq-exponential', diff: 3, text: R`Найдите наибольшее целое решение неравенства $3^{x+17}\cdot5^{-x-16}>1{,}08$.`, answer: '-15', sol: R`$1{,}08=\dfrac{27}{25}=3^{3}\cdot5^{-2}$. Неравенство приводится к виду $3^{x+14}\cdot5^{-x-14}>1$, то есть $\left(\dfrac35\right)^{x+14}>1$. Так как $\dfrac35<1$, то $x+14<0$, $x<-14$. Наибольшее целое — $-15$.`, ref: 'Алгебра, 11 класс, гл. 2' }, { idx: 21, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 2, text: R`Найдите модуль разности наибольшего и наименьшего корней уравнения $\left(2x^{2}-x-7\right)^{2}=(5x+1)^{2}$.`, answer: '7', sol: R`$2x^{2}-x-7=\pm(5x+1)$. При знаке «$+$»: $2x^{2}-6x-8=0$, $x=4;-1$. При знаке «$-$»: $2x^{2}+4x-6=0$, $x=1;-3$. Корни $\{-3;-1;1;4\}$; модуль разности наибольшего и наименьшего $|4-(-3)|=7$.`, ref: 'Алгебра, 9 класс, гл. 1' }, { idx: 22, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 2, text: R`Пусть $(x_1;y_1)$, $(x_2;y_2)$ — решения системы уравнений $\begin{cases}x^{2}+4x=15+3y,\\ 4x-3y=6.\end{cases}$ Найдите значение выражения $x_1y_2+x_2y_1$.`, answer: '-24', sol: R`Из второго уравнения $3y=4x-6$. Подставив в первое: $x^{2}+4x=15+4x-6$, $x^{2}=9$, $x=\pm3$. Решения $(3;2)$ и $(-3;-6)$. Тогда $x_1y_2+x_2y_1=3\cdot(-6)+(-3)\cdot2=-24$.`, ref: 'Алгебра, 9 класс, гл. 1' }, { idx: 23, type: 'open', topic: 'equations', subtopic: 'eq-irrational', diff: 3, text: R`Найдите сумму корней (корень, если он единственный) уравнения $\sqrt{x^{2}+3x}+\sqrt{1-x}=\sqrt{12-x}+\sqrt{1-x}$.`, answer: '-6', sol: R`Вычитая $\sqrt{1-x}$ из обеих частей: $\sqrt{x^{2}+3x}=\sqrt{12-x}$, $x^{2}+3x=12-x$, $x^{2}+4x-12=0$, $x=2;-6$. Условию ОДЗ ($x\le1$) удовлетворяет лишь $x=-6$.`, ref: 'Алгебра, 10 класс, гл. 2, § 17' }, { idx: 24, type: 'open', topic: 'equations', subtopic: 'eq-rational', diff: 3, text: R`Найдите сумму целых решений неравенства $\dfrac{(x^{2}+7x+10)(x-4)^{2}}{4-x^{2}}\ge0$.`, answer: '-8', sol: R`После сокращения на $(x+2)$: $\dfrac{(x+5)(x-4)^{2}}{2-x}\ge0$ при $x\ne-2$. Множитель $(x-4)^{2}\ge0$, поэтому решение — промежуток $[-5;2)$ без точки $x=-2$, плюс отдельная точка $x=4$. Целые решения $-5,-4,-3,-1,0,1,4$; их сумма $-8$.`, ref: 'Алгебра, 9 класс, гл. 3' }, { idx: 25, type: 'open', topic: 'stereometry', subtopic: 'ster-polyhedra', diff: 3, text: R`Каждое боковое ребро четырёхугольной пирамиды образует с её высотой, равной $3\sqrt7$, угол $30^\circ$. Основанием пирамиды является прямоугольник с углом $30^\circ$ между диагоналями. Найдите объём пирамиды $V$; в ответ запишите значение выражения $\sqrt7\cdot V$.`, answer: '147', sol: R`Все боковые рёбра равнонаклонены к основанию, значит вершина проектируется в центр прямоугольника. Половина диагонали $R=H\operatorname{tg}30^\circ=3\sqrt7\cdot\dfrac{1}{\sqrt3}=\sqrt{21}$, диагональ $d=2\sqrt{21}$. Площадь основания $S=\dfrac12 d^{2}\sin30^\circ=\dfrac12\cdot84\cdot\dfrac12=21$. Объём $V=\dfrac13\cdot21\cdot3\sqrt7=21\sqrt7$, и $\sqrt7\cdot V=21\cdot7=147$.`, ref: 'Геометрия, 11 класс, разд. 1' }, { idx: 26, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 3, text: R`Найдите (в градусах) наибольший отрицательный корень уравнения $\sin^{2}\!\left(5x-\dfrac{\pi}{3}\right)=1$.`, answer: '-6', sol: R`$\sin^{2}\alpha=1\Rightarrow\alpha=\dfrac{\pi}{2}+\pi k$. Тогда $5x=\dfrac{\pi}{3}+\dfrac{\pi}{2}+\pi k=\dfrac{5\pi}{6}+\pi k$, $x=30^\circ+36^\circ k$. Наибольший отрицательный корень при $k=-1$: $30^\circ-36^\circ=-6^\circ$.`, ref: 'Алгебра, 10 класс, гл. 1, § 8' }, { idx: 27, type: 'open', topic: 'trigonometry', subtopic: 'trig-equations', diff: 4, text: R`Найдите количество корней уравнения $\sin x=-\dfrac{x}{16\pi}$.`, answer: '33', sol: R`Корни существуют лишь при $|x|\le16\pi$. Функции $\sin x$ и $-\dfrac{x}{16\pi}$ нечётны, поэтому $x=0$ — корень, а остальные корни симметричны. При $x>0$ правая часть отрицательна, поэтому пересечения происходят на восьми «отрицательных» арках синуса $(\pi;2\pi),(3\pi;4\pi),\ldots,(15\pi;16\pi)$ — по два на каждой, итого $16$. Столько же при $x<0$. Всего $16+16+1=33$.`, ref: 'Алгебра, 10 класс, гл. 1' }, { idx: 28, type: 'open', topic: 'planimetry', subtopic: 'plan-quadrilaterals', diff: 3, text: R`В прямоугольнике $ABCD$ выбраны точки $L$ на стороне $BC$ и $M$ на стороне $AD$ так, что $ALCM$ — ромб. Найдите площадь этого ромба, если $AB=3$, $BC=9$.`, answer: '15', sol: R`Пусть сторона ромба равна $m$. Тогда $BL=BC-LC=9-m$, и из прямоугольного треугольника $ABL$: $m^{2}=3^{2}+(9-m)^{2}$, откуда $m=5$. Диагонали ромба $AC=\sqrt{3^{2}+9^{2}}=3\sqrt{10}$ и $LM=\sqrt{10}$, поэтому площадь $=\dfrac12\cdot3\sqrt{10}\cdot\sqrt{10}=15$.`, ref: 'Геометрия, 8 класс, гл. 3' }, { idx: 29, type: 'open', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, text: R`Найдите значение выражения $2^{A}$, если $A=\log_{2}9+\log_{2}25$.`, answer: '225', sol: R`$A=\log_{2}9+\log_{2}25=\log_{2}(9\cdot25)=\log_{2}225$, поэтому $2^{A}=225$.`, ref: 'Алгебра, 11 класс, гл. 3' }, { idx: 30, type: 'open', topic: 'numbers', subtopic: 'num-divisibility', diff: 3, text: R`Найдите сумму всех трёхзначных чисел, которые при делении на $4$ и на $6$ дают в остатке $1$, а при делении на $9$ дают в остатке $4$.`, answer: '13825', sol: R`Условия $n\equiv1\pmod4$ и $n\equiv1\pmod6$ дают $n\equiv1\pmod{12}$. Вместе с $n\equiv4\pmod9$ получаем $n\equiv13\pmod{36}$. Трёхзначные такие числа образуют прогрессию $121,157,\ldots,985$ — всего $25$ чисел. Их сумма $\dfrac{121+985}{2}\cdot25=553\cdot25=13825$.`, ref: 'Алгебра, 9 класс, гл. 4' }, ]; /* ── Сборка 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_ct2015_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_ct2015_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 → «Варианты» → «ЦТ-2015».\n`); } catch (e) { db.exec('ROLLBACK'); console.error('\n✗ Ошибка записи, откат транзакции:', e.message); process.exitCode = 1; } db.close();