From 2bdb0ed898b8f7edaef0298c7f322981e549fab5 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 19 Jun 2026 09:12:39 +0300 Subject: [PATCH] =?UTF-8?q?feat(ctmath):=20seed-=D1=81=D0=BA=D1=80=D0=B8?= =?UTF-8?q?=D0=BF=D1=82=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=B4=20=D1=84=D0=BB?= =?UTF-8?q?=D0=B5=D1=88=D0=BA=D0=B0=D1=80=D1=82=20=C2=AB=D0=A1=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D0=B5=D0=BC=D1=8B=20=D1=83=D1=80=D0=B0=D0=B2=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9=C2=BB=20=D0=B8=20=C2=AB=D0=A2=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=B7=D0=B0=D0=B4=D0=B0?= =?UTF-8?q?=D1=87=D0=B8=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Системы (7 карт) — методы подстановки/сложения, домножение коэффициентов, пересечение графиков = система, проверка пары, приём x²−y²=(x+y)(x−y) (источник: Кедр «Материал по системам»). Текстовые задачи (12 карт) — проценты, сплавы/растворы, движение, совместная работа (канонические приёмы). KaTeX inline $…$ (кириллица только вне math), идемпотентно, запись с --apply. Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/scripts/seed_ctmath_flashcards_p4.js | 112 +++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 backend/scripts/seed_ctmath_flashcards_p4.js diff --git a/backend/scripts/seed_ctmath_flashcards_p4.js b/backend/scripts/seed_ctmath_flashcards_p4.js new file mode 100644 index 0000000..d7b3585 --- /dev/null +++ b/backend/scripts/seed_ctmath_flashcards_p4.js @@ -0,0 +1,112 @@ +'use strict'; +/* ─────────────────────────────────────────────────────────────────────────── + seed_ctmath_flashcards_p4.js + Ещё две колоды карточек для подготовки к ЦЭ/ЦТ (интервальное повторение): + + 1. «ЦТ · Системы уравнений» — методы подстановки/сложения, приёмы + 2. «ЦТ · Текстовые задачи» — проценты, сплавы/растворы, движение, работа + + Источники: + • Системы — Кедр «Материал по системам.pdf» (подстановка, сложение с + домножением, пересечение графиков = система, проверка пары, x²−y²=(x+y)(x−y)). + • Текстовые задачи — канонические приёмы ЦТ (отдельная шпора Кедр >20 МБ, + Read не тянет; методы стандартные). + + Математика — KaTeX inline $…$ (страница флешкарт рендерит \( \), \[ \], $ $; НЕ $$). + ⚠️ Кириллица ТОЛЬКО вне $…$ — в math-режиме KaTeX нет кириллических глифов. + Те же владелец/таблицы/стиль, что seed_ctmath_flashcards.js / _p2 / _p3. + + Идемпотентность: колода ищется по (user_id, title). Если уже есть и наполнена — + пропуск (не клобберит SR-прогресс). Пустую/новую — наполняет. + + Запуск: + node backend/scripts/seed_ctmath_flashcards_p4.js # DRY-RUN (по умолчанию) + node backend/scripts/seed_ctmath_flashcards_p4.js --apply # запись в БД + + ⚠️ Массовую запись в БД запускает ПОЛЬЗОВАТЕЛЬ вручную (авто-режим Claude Code + блокирует продакшн-записи). Без --apply ничего не пишется — только сводка. + ─────────────────────────────────────────────────────────────────────────── */ + +const db = require('../src/db/db'); +const APPLY = process.argv.includes('--apply'); + +const owner = (db.prepare("SELECT id FROM users WHERE role='admin' ORDER BY id LIMIT 1").get() + || db.prepare('SELECT id FROM users ORDER BY id LIMIT 1').get()).id; + +const DECKS = [ + { title: 'ЦТ · Системы уравнений', color: '#118AB2', + descr: 'Методы решения систем: подстановка, алгебраическое сложение, пересечение графиков, проверка пары и приёмы.', + cards: [ + ['Метод подстановки', 'Выразить одну переменную из одного уравнения и подставить в другое → останется уравнение с одной переменной; решить и вернуть найденное в первое'], + ['Метод алгебраического сложения', 'Записать уравнения друг под другом; при необходимости домножить, чтобы коэффициенты при одной переменной стали равными или противоположными; сложить/вычесть — одна переменная уходит'], + ['Уравнивание коэффициентов', 'Домножить уравнения на подходящие числа, чтобы перед одной переменной совпали коэффициенты (напр., умножить на $3$ и на $2$, чтобы в обоих стало $6x$), затем сложить или вычесть'], + ['Пересечение графиков = система', 'Точки пересечения двух графиков — это решения системы из их уравнений. Записать оба уравнения в систему и решить'], + ['Приём при известной сумме $x+y$', 'Разложить разность квадратов: $x^2-y^2=(x+y)(x-y)$. Подставить известную сумму, найти разность $x-y$, затем сложить/вычесть с $x+y$'], + ['Проверка: пара — решение системы?', 'Подставить пару в КАЖДОЕ уравнение. Пара — решение только если во ВСЕХ уравнениях получились верные равенства (хотя бы одно неверно → не решение)'], + ['Симметричное выражение через корни', 'Найти обе точки пересечения $(x_1;y_1)$ и $(x_2;y_2)$, затем подставить их в искомое выражение (напр. $x_1 x_2+y_1 y_2$)'], + ]}, + + { title: 'ЦТ · Текстовые задачи', color: '#FF9F1C', + descr: 'Приёмы текстовых задач: проценты, сплавы и растворы, движение, совместная работа.', + cards: [ + ['Процент от числа', '$p\\%$ от числа $a$ равно $\\dfrac{p}{100}\\cdot a$'], + ['Сколько процентов одно число от другого', 'Часть разделить на целое и умножить на $100$: $\\dfrac{a}{b}\\cdot100\\%$'], + ['Увеличить число на $p\\%$', 'Умножить на $\\left(1+\\dfrac{p}{100}\\right)$'], + ['Уменьшить число на $p\\%$', 'Умножить на $\\left(1-\\dfrac{p}{100}\\right)$'], + ['Концентрация вещества в растворе', 'Доля = масса чистого вещества разделить на массу всего раствора'], + ['Масса вещества при концентрации', 'Масса раствора умножить на концентрацию (долю)'], + ['Сплавы и растворы — что складывается', 'Складываются массы веществ и массы растворов (по отдельности); проценты-концентрации НЕ складываются — концентрацию смеси пересчитывают заново'], + ['Равномерное движение', '$S=v\\cdot t$ — путь равен скорости, умноженной на время'], + ['Скорость по течению и против', 'По течению $v+u$; против течения $v-u$ ($v$ — собственная скорость, $u$ — скорость течения)'], + ['Средняя скорость на всём пути', 'Весь путь разделить на всё время — $v=\\dfrac{S}{t}$ (НЕ среднее арифметическое скоростей!)'], + ['Производительность работы', 'Объём работы разделить на время. Весь объём обычно принимают за $1$'], + ['Совместная работа двоих', 'Производительности складываются: если поодиночке за $a$ и $b$ времени, то вместе за $\\dfrac{ab}{a+b}$'], + ]}, +]; + +/* ── self-check: чаще всего KaTeX ломают непарные $ или {} ─────────────────── */ +let bad = 0; +for (const d of DECKS) { + d.cards.forEach(([f, b], i) => { + [['front', f], ['back', b]].forEach(([side, s]) => { + const dollars = (s.match(/\$/g) || []).length; + const braces = (s.match(/\{/g) || []).length - (s.match(/\}/g) || []).length; + if (dollars % 2 !== 0) { console.error(`✗ непарный $ — «${d.title}» #${i + 1} (${side}): ${s}`); bad++; } + if (braces !== 0) { console.error(`✗ непарные {} — «${d.title}» #${i + 1} (${side}): ${s}`); bad++; } + }); + }); +} +if (bad) { console.error(`\nСамопроверка: ${bad} проблем — исправь до записи.\n`); process.exit(1); } + +const findDeck = db.prepare('SELECT id FROM flashcard_decks WHERE user_id=? AND title=?'); +const countCard = db.prepare('SELECT COUNT(*) c FROM flashcard_cards WHERE deck_id=?'); +const insDeck = db.prepare('INSERT INTO flashcard_decks (user_id,title,description,color) VALUES (?,?,?,?)'); +const insCard = db.prepare('INSERT INTO flashcard_cards (deck_id,front,back,order_idx) VALUES (?,?,?,?)'); + +console.log(`\n=== seed_ctmath_flashcards_p4 (${APPLY ? 'APPLY' : 'DRY-RUN'}) ===`); +console.log('владелец user_id =', owner, '\n'); + +let plannedDecks = 0, plannedCards = 0; + +for (const d of DECKS) { + const ex = findDeck.get(owner, d.title); + if (ex) { + const have = countCard.get(ex.id).c; + if (have > 0) { console.log(`• «${d.title}» (id ${ex.id}) — уже наполнена (${have} карт), пропуск`); continue; } + plannedDecks++; plannedCards += d.cards.length; + console.log(`+ «${d.title}» (id ${ex.id}) — пустая, долить ${d.cards.length} карт`); + if (APPLY) d.cards.forEach(([f, b], i) => insCard.run(ex.id, f, b, i)); + continue; + } + plannedDecks++; plannedCards += d.cards.length; + console.log(`+ «${d.title}» — новая колода, ${d.cards.length} карт`); + if (APPLY) { + const did = insDeck.run(owner, d.title, d.descr, d.color).lastInsertRowid; + d.cards.forEach(([f, b], i) => insCard.run(did, f, b, i)); + console.log(` создана id ${did}`); + } +} + +console.log(`\nИтого к ${APPLY ? 'записи' : 'добавлению'}: колод ${plannedDecks}, карт ${plannedCards}.`); +if (!APPLY) console.log('DRY-RUN: ничего не записано. Для записи: node backend/scripts/seed_ctmath_flashcards_p4.js --apply\n'); +else console.log('Готово. Колоды добавлены (владелец — admin; раздать классу — через доступ к колоде).\n');