Files
Learn_System/backend/scripts/seed_ctmath_flashcards_p4.js
T
Maxim Dolgolyov 2bdb0ed898 feat(ctmath): seed-скрипт колод флешкарт «Системы уравнений» и «Текстовые задачи»
Системы (7 карт) — методы подстановки/сложения, домножение коэффициентов,
пересечение графиков = система, проверка пары, приём x²−y²=(x+y)(x−y)
(источник: Кедр «Материал по системам»). Текстовые задачи (12 карт) —
проценты, сплавы/растворы, движение, совместная работа (канонические приёмы).
KaTeX inline $…$ (кириллица только вне math), идемпотентно, запись с --apply.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 09:12:39 +03:00

113 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/* ───────────────────────────────────────────────────────────────────────────
seed_ctmath_flashcards_p4.js
Ещё две колоды карточек для подготовки к ЦЭ/ЦТ (интервальное повторение):
1. «ЦТ · Системы уравнений» — методы подстановки/сложения, приёмы
2. «ЦТ · Текстовые задачи» — проценты, сплавы/растворы, движение, работа
Источники:
• Системы — Кедр «Материал по системам.pdf» (подстановка, сложение с
домножением, пересечение графиков = система, проверка пары, x²−y²=(x+y)(xy)).
• Текстовые задачи — канонические приёмы ЦТ (отдельная шпора Кедр >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');