From 494023fba7bb877b99471f86bb0ebc9535bf19b9 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 19 Jun 2026 10:25:10 +0300 Subject: [PATCH] =?UTF-8?q?feat(ctmath):=20=D0=BF=D1=80=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=B8=D0=BA=20=D0=A0=D0=A2-2023/24=20=D1=8D=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=20III=20(=D0=B2=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=20106)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 30 заданий А1–А10 + В1–В20, перенабор по PDF РИКЗ. 8 mc + 21 open + 1 long; геометрия — текстом, В1 (чтение графика) — inline-SVG в figure_html (как у math9). Метка 106 уже в VARIANT_LABEL. Идемпотентный seed, --apply — пользователь. Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/scripts/seed_ctmath_rt2324_e3v1.js | 388 +++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 backend/scripts/seed_ctmath_rt2324_e3v1.js diff --git a/backend/scripts/seed_ctmath_rt2324_e3v1.js b/backend/scripts/seed_ctmath_rt2324_e3v1.js new file mode 100644 index 0000000..b2d7dac --- /dev/null +++ b/backend/scripts/seed_ctmath_rt2324_e3v1.js @@ -0,0 +1,388 @@ +'use strict'; +/* ─────────────────────────────────────────────────────────────────────────── + seed_ctmath_rt2324_e3v1.js + Чистый вариант-пробник для трека exam-prep `ctmath`. + + Источник: РТ–2023/2024, Этап III, Вариант 1 (РИКЗ, «Тематическое + консультирование по математике»). 30 заданий: А1–А10 + В1–В20. + Перенабрано вручную в KaTeX по PDF (визуальное чтение, НЕ OCR): + F:\!Рабочие\ЦТ\Математика\Математика\РТ\2023-2024\МАТ РТ-3 23_24 В1.pdf + + variant=106 — Этап III РТ-2023/24 (этап I — 104, этап II — 105). + Геометрия закодирована текстом (стандартная разметка фигур / углы словами). + Исключение — В1 (чтение графика): кусочно-линейная нечётная функция + воспроизведена inline-SVG в figure_html (как у math9-заданий); все 6 + утверждений и ответ (145) согласованы с реконструкцией. + + Идемпотентность: upsert по UNIQUE(exam_key, variant, task_idx). + Запуск: + node backend/scripts/seed_ctmath_rt2324_e3v1.js # DRY-RUN (по умолчанию) + node backend/scripts/seed_ctmath_rt2324_e3v1.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 = 106; +const PROV = 'РТ–2023/2024, Этап III, Вариант 1'; +const R = String.raw; + +/* opts: метки кириллица а–д (как в существующих строках ctmath; checkAnswerServer + имеет ветку /^[а-д]$/). РТ-варианты 1..5 → а..д. */ +const L = ['а', 'б', 'в', 'г', 'д']; +const mc = (...html) => html.map((h, i) => [L[i], h]); + +/* ── SVG-график для В1: нечётная кусочно-линейная функция на [-6;6] через + точки (-6,-3),(-4,1),(4,-1),(6,3). f(0)=0; возрастает на [-6;-4] и [4;6], + убывает на [-4;4]. Цвета — только в SVG-стоки (как у math9-фигур). */ +const FIG_B1 = ` + + + + + + + + + + x + y + O + 1 + 1 + y=f(x) +`; + +/* ── 30 заданий ─────────────────────────────────────────────────────────── */ +const TASKS = [ + // ── Часть A: А1–А10 ────────────────────────────────────────────────────── + { idx: 1, type: 'mc', topic: 'functions', subtopic: 'fn-graphs', diff: 1, + text: R`На координатной плоскости отмечены точки $A(2;-1)$, $B(1;2)$, $C(-2;-2)$, $D(-1;1)$, $E(0;-2)$. Выберите ту из них, сумма координат которой равна $-4$.`, + opts: mc('$A$', '$B$', '$C$', '$D$', '$E$'), + answer: 'в', + sol: R`Сумма координат: для $A$ это $2+(-1)=1$, для $B$ это $1+2=3$, для $C$ это $-2+(-2)=-4$, для $D$ это $-1+1=0$, для $E$ это $0+(-2)=-2$. Сумме $-4$ соответствует точка $C$.`, + ref: 'Герасимов «Математика, 6 кл.», гл. 5, § 1' }, + + { idx: 2, type: 'mc', topic: 'stereometry', subtopic: 'ster-basics', diff: 3, + text: R`Дан куб $ABCDA_1B_1C_1D_1$. Точка $K$ — середина диагонали $A_1D$. Среди отрезков $A_1B_1$, $B_1D_1$, $C_1K$, $BB_1$, $A_1C_1$ укажите отрезок, по которому плоскость, заданная прямой $DC_1$ и точкой $K$, пересекает плоскость грани $A_1B_1C_1D_1$.`, + opts: mc('$A_1B_1$', '$B_1D_1$', '$C_1K$', '$BB_1$', '$A_1C_1$'), + answer: 'д', + sol: R`Секущая плоскость, заданная прямой $DC_1$ и точкой $K$, содержит точку $C_1$ (она на $DC_1$) и точку $A_1$ (так как $K$ — середина $A_1D$, прямая $DC_1$ и точка $K$ задают плоскость диагонального сечения, проходящую через $A_1$). Точки $A_1$ и $C_1$ принадлежат и грани $A_1B_1C_1D_1$, поэтому пересечение плоскостей — отрезок $A_1C_1$.`, + ref: 'Латотин «Геометрия, 10 кл.», разд. 1, § 2–3' }, + + { idx: 3, type: 'mc', topic: 'numbers', subtopic: 'num-real', diff: 2, + text: R`Расположите числа $\log_3 27$, $\ 3^{-1}$, $\ \sqrt{64}$ в порядке возрастания.`, + opts: mc('$\sqrt{64};\ \log_3 27;\ 3^{-1}$', '$3^{-1};\ \sqrt{64};\ \log_3 27$', '$\sqrt{64};\ 3^{-1};\ \log_3 27$', '$3^{-1};\ \log_3 27;\ \sqrt{64}$', '$\log_3 27;\ \sqrt{64};\ 3^{-1}$'), + answer: 'г', + sol: R`$\log_3 27=\log_3 3^{3}=3$; $\ 3^{-1}=\dfrac13$; $\ \sqrt{64}=8$. Так как $\dfrac13<3<8$, числа в порядке возрастания: $3^{-1};\ \log_3 27;\ \sqrt{64}$.`, + ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 1–4; гл. 11 кл., § 3' }, + + { idx: 4, type: 'mc', topic: 'expressions', subtopic: 'expr-polynomials', diff: 1, + text: R`Укажите номер выражения, тождественно равного выражению $a^{3}$.`, + opts: mc('$a:a^{3}$', '$a\cdot a^{2}$', '$\left(a^{2}\right)^{2}$', '$3a$', '$a^{-3}$'), + answer: 'б', + sol: R`По свойству степеней $a\cdot a^{2}=a^{1+2}=a^{3}$. (Остальные: $a:a^{3}=a^{-2}$; $\left(a^{2}\right)^{2}=a^{4}$; $3a$ и $a^{-3}$ не равны $a^{3}$.)`, + ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 5' }, + + { idx: 5, type: 'mc', topic: 'expressions', subtopic: 'expr-polynomials', diff: 1, + text: R`Результат разложения многочлена $4b^{2}+4bc-4b$ на множители имеет вид:`, + opts: mc('$4b(b+c)$', '$4b(bc-1)$', '$4b(1+c)$', '$(4b-1)(b+c)$', '$4b(b+c-1)$'), + answer: 'д', + sol: R`Общий множитель членов многочлена $4b^{2}+4bc-4b$ — одночлен $4b$. Тогда $4b^{2}+4bc-4b=4b(b+c-1)$.`, + ref: 'Арефьева «Алгебра, 7 кл.», гл. 2, § 14' }, + + { idx: 6, type: 'open', topic: 'expressions', subtopic: 'expr-powers-roots', diff: 2, + text: R`Среди чисел $10$, $99$, $0$, $-10$, $100$ укажите номера тех, которые не входят в область определения выражения $\dfrac{1}{10-\sqrt{x}}$.
1) $10$; 2) $99$; 3) $0$; 4) $-10$; 5) $100$.
Ответ запишите цифрами в порядке возрастания, без пробелов.`, + answer: '45', ansShow: '4, 5', + sol: R`Выражение $\dfrac{1}{10-\sqrt{x}}$ имеет смысл при $x\ge0$ и $10-\sqrt{x}\ne0$, то есть $x\ge0$, $x\ne100$. Область определения $[0;100)\cup(100;+\infty)$. Из данных чисел ей не принадлежат $-10$ (так как $-10<0$) и $100$ (исключено). Это числа под номерами 4 и 5.`, + ref: 'Арефьева «Алгебра, 8 кл.», гл. 1, § 1' }, + + { idx: 7, type: 'mc', topic: 'word-sequences', subtopic: 'word-problems', diff: 2, + text: R`За три четверти учебного года Петя использовал $\dfrac25$ купленных в начале учебного года тетрадей, после чего у него осталось $48$ тетрадей. Сколько тетрадей купил Петя в начале учебного года?`, + opts: mc('$80$', '$96$', '$120$', '$74$', '$116$'), + answer: 'а', + sol: R`Числу $48$ соответствует дробь $1-\dfrac25=\dfrac35$ всех тетрадей. Тогда куплено $48:\dfrac35=\dfrac{48\cdot5}{3}=80$ тетрадей.`, + ref: 'Герасимов «Математика, 5 кл.», ч. 2, гл. 3, § 10' }, + + { idx: 8, type: 'mc', topic: 'trigonometry', subtopic: 'trig-identities', diff: 2, + text: R`Найдите значение выражения $\operatorname{tg}(-120^\circ)+\left|-\sqrt3\right|$.`, + opts: mc('$0$', '$\dfrac{4\sqrt3}{3}$', '$1-\sqrt3$', '$2\sqrt3$', '$-\dfrac{2\sqrt3}{3}$'), + answer: 'г', + sol: R`$\operatorname{tg}(-120^\circ)=-\operatorname{tg}120^\circ=-\operatorname{tg}(180^\circ-60^\circ)=\operatorname{tg}60^\circ=\sqrt3$. Тогда $\operatorname{tg}(-120^\circ)+\left|-\sqrt3\right|=\sqrt3+\sqrt3=2\sqrt3.$`, + ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 3; § 9' }, + + { idx: 9, type: 'mc', topic: 'stereometry', subtopic: 'ster-rotation', diff: 2, + text: R`Сечение сферы плоскостью, отстоящей от её центра на расстоянии $3$, имеет радиус $3\sqrt2$. Найдите радиус сферы.`, + opts: mc('$9\sqrt2$', '$3\sqrt3$', '$6$', '$12$', '$4\sqrt3$'), + answer: 'б', + sol: R`Радиус сферы $R$ — гипотенуза прямоугольного треугольника с катетами $3$ (расстояние до плоскости) и $3\sqrt2$ (радиус сечения). По теореме Пифагора $R^{2}=3^{2}+\left(3\sqrt2\right)^{2}=9+18=27$, поэтому $R=3\sqrt3$.`, + ref: 'Латотин «Геометрия, 11 кл.», разд. 3, § 5' }, + + { idx: 10, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 2, + text: R`Укажите номера функций, которые принимают только положительные значения на промежутке $(4;+\infty)$.
1) $f(x)=-4x$;
2) $f(x)=\sqrt{x-4}$;
3) $f(x)=x^{3}-4$;
4) $f(x)=\log_{\frac14}x$;
5) $f(x)=-x^{2}-4$.
Ответ запишите цифрами в порядке возрастания, без пробелов.`, + answer: '23', ansShow: '2, 3', + sol: R`$1)$ $-4x$ при $x>4$ отрицательна. $\ 2)$ $\sqrt{x-4}$ при $x>4$ положительна. $\ 3)$ $x^{3}-4$ положительна при $x>\sqrt[3]{4}$, а $(4;+\infty)\subset(\sqrt[3]{4};+\infty)$ — положительна. $\ 4)$ $\log_{\frac14}x$ положительна только на $(0;1)$. $\ 5)$ $-x^{2}-4$ отрицательна при всех $x$. Подходят функции 2 и 3.`, + ref: 'Арефьева «Алгебра, 8 кл.», гл. 3, § 13–14' }, + + // ── Часть B: В1–В20 ────────────────────────────────────────────────────── + { idx: 11, type: 'open', topic: 'functions', subtopic: 'fn-properties', diff: 3, + fig: FIG_B1, + text: R`На рисунке изображён график функции $y=f(x)$, определённой на промежутке $[-6;6]$. Выберите верные утверждения.
1) функция является нечётной;
2) $f(3)>0$;
3) график функции симметричен относительно оси ординат;
4) $f(-5)>f(-6)$;
5) функция убывает на промежутке $[-4;4]$;
6) график функции $y=f(x)+3$ проходит через точку $(0;2)$.
Ответ запишите цифрами в порядке возрастания, без пробелов.`, + answer: '145', ansShow: '1, 4, 5', + sol: R`$1)$ верно: график симметричен относительно начала координат, поэтому функция нечётная. $\ 2)$ неверно: по графику $f(3)<0$. $\ 3)$ неверно: график нечётной функции симметричен относительно начала координат, а не оси ординат. $\ 4)$ верно: на промежутке $[-6;-4]$ функция возрастает, поэтому $f(-5)>f(-6)$. $\ 5)$ верно: на отрезке $[-4;4]$ при увеличении $x$ значения функции уменьшаются. $\ 6)$ неверно: $f(0)=0$, поэтому график $y=f(x)+3$ проходит через точку $(0;3)$, а не $(0;2)$.`, + ref: 'Арефьева «Алгебра, 9 кл.», гл. 2, § 6–9' }, + + { idx: 12, type: 'long', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 3, + text: R`$ABCDA_1B_1C_1D_1$ — куб. Точки $M$ и $K$ — середины рёбер $A_1D_1$ и $AA_1$ соответственно. Для начала каждого из предложений А–В подберите его окончание 1–6 так, чтобы получилось верное утверждение.
Начало:
А) Величина угла между прямыми $A_1B_1$ и $KM$ равна …
Б) Величина угла между прямыми $B_1C_1$ и $KM$ равна …
В) Величина угла между прямыми $BD$ и $KM$ равна …
Окончание:
1) $30^\circ$; 2) $0^\circ$; 3) $60^\circ$; 4) $90^\circ$; 5) $120^\circ$; 6) $45^\circ$.
Ответ запишите сочетанием букв и цифр, например: А1Б1В4.`, + answer: 'А4Б6В3', ansShow: 'А4Б6В3', + sol: R`А) Прямая $A_1B_1$ перпендикулярна плоскости грани $AA_1D_1D$, а $KM$ лежит в этой плоскости, поэтому $A_1B_1\perp KM$ — угол $90^\circ$ (окончание 4). Б) $B_1C_1\parallel A_1D_1$, поэтому угол между $B_1C_1$ и $KM$ равен углу $A_1MK$; в равнобедренном прямоугольном треугольнике $KA_1M$ ($A_1K=A_1M$) он равен $45^\circ$ (окончание 6). В) Через середину $P$ ребра проведём $MP\parallel B_1D_1$; треугольник $PMK$ равносторонний, поэтому угол между $BD$ и $KM$ равен $60^\circ$ (окончание 3).`, + ref: 'Латотин «Геометрия, 10 кл.», разд. 2, § 4' }, + + { idx: 13, type: 'open', topic: 'numbers', subtopic: 'num-divisibility', diff: 2, + text: R`Найдите сумму всех натуральных делителей числа $95$.`, + answer: '120', + sol: R`Число $95=5\cdot19$ имеет четыре натуральных делителя: $1$, $5$, $19$ и $95$. Их сумма равна $1+5+19+95=120$.`, + ref: 'Герасимов «Математика, 5 кл.», ч. 1, гл. 1, § 12' }, + + { idx: 14, type: 'open', topic: 'equations', subtopic: 'eq-linear', diff: 2, + text: R`Найдите произведение наименьшего и наибольшего целых решений двойного неравенства $-51\dfrac13<-3x<4\sqrt2$.`, + answer: '-17', + sol: R`Разделим все части на $-3$ (знаки неравенства меняются на противоположные): $-\dfrac{4\sqrt2}{3}1$ решений не имеет. Из $\sin3x=0$: $3x=180^\circ n$, $x=60^\circ n$. Промежутку $[-270^\circ;-135^\circ]$ принадлежат $-180^\circ$ ($n=-3$) и $-240^\circ$ ($n=-4$); их сумма равна $-420^\circ$.`, + ref: 'Арефьева «Алгебра, 10 кл.», гл. 1, § 8; § 12' }, + + { idx: 29, type: 'open', topic: 'equations', subtopic: 'eq-logarithmic', diff: 4, + text: R`Найдите сумму всех целых решений неравенства $\log_{0{,}7}\left(x^{2}-7x+18\right)-\log_{0{,}7}(x-1)<\log_{0{,}7}2$ на промежутке $(-10;10)$.`, + answer: '35', + sol: R`Неравенство приводится к виду $\log_{0{,}7}\left(x^{2}-7x+18\right)<\log_{0{,}7}\bigl(2(x-1)\bigr)$. Основание $0{,}7<1$ (функция убывает), поэтому равносильна система $\begin{cases}x^{2}-7x+18>2x-2,\\2x-2>0.\end{cases}$ Первое: $x^{2}-9x+20>0\Rightarrow x<4$ или $x>5$; второе: $x>1$. Решение $(1;4)\cup(5;+\infty)$. Пересечение с $(-10;10)$: $(1;4)\cup(5;10)$; целые $2,3,6,7,8,9$, их сумма $35$.`, + ref: 'Арефьева «Алгебра, 11 кл.», гл. 3, § 10' }, + + { idx: 30, type: 'open', topic: 'stereometry', subtopic: 'ster-angles-distances', diff: 5, + text: R`Сторона $AB$ треугольника $ABC$, у которого $AB=BC=12$, $AC=8$, лежит в плоскости $\alpha$, а длины проекций двух других сторон треугольника $ABC$ на эту плоскость относятся как $1:3$. Найдите значение выражения $\dfrac{13}{\cos^{2}\beta}$, где $\beta$ — угол между плоскостью треугольника $ABC$ и плоскостью $\alpha$.`, + answer: '256', + sol: R`Пусть $CO$ — перпендикуляр к $\alpha$, $AO:BO=1:3$, $AO=x$, $BO=3x$. Из $CO^{2}=BC^{2}-BO^{2}=AC^{2}-AO^{2}$: $144-9x^{2}=64-x^{2}$, $8x^{2}=80$, $x=\sqrt{10}$, $CO=3\sqrt6$. Высота $CK$ треугольника $ABC$ к $AB$: по формуле Герона $S=32\sqrt2$, откуда $CK=\dfrac{2S}{AB}=\dfrac{64\sqrt2}{12}=\dfrac{16\sqrt2}{3}$. Тогда $OK=\sqrt{CK^{2}-CO^{2}}=\sqrt{\dfrac{512}{9}-54}=\dfrac{\sqrt{26}}{3}$, а $\cos\beta=\dfrac{OK}{CK}=\dfrac{\sqrt{13}}{16}$. Значит, $\dfrac{13}{\cos^{2}\beta}=\dfrac{13\cdot256}{13}=256$.`, + ref: 'Латотин «Геометрия, 10 кл.», разд. 3, § 10' }, +]; + +/* ── Сборка 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_rt2324_e3v1 (${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), ' | с фигурой:', TASKS.filter(t => t.fig).length, '\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_rt2324_e3v1.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 → «Варианты» → «РТ-2023/24 · этап III».\n`); +} catch (e) { + db.exec('ROLLBACK'); + console.error('\n✗ Ошибка записи, откат транзакции:', e.message); + process.exitCode = 1; +} +db.close();