feat(ctmath): seed-скрипт колод флешкарт «Прогрессии» и «Двойные неравенства»
Прогрессии (12 карт) — канонические формулы арифм./геом. (n-й член, суммы, характеристические свойства). Двойные неравенства (9 карт) — оценка a±b, a·b, a/b почленно + ловушки строгости и запрет почленного вычитания/деления (источник: Кедр «Операции с двойными неравенствами»). KaTeX inline $…$, идемпотентно, DRY-RUN по умолчанию, запись только с --apply. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,115 @@
|
|||||||
|
'use strict';
|
||||||
|
/* ───────────────────────────────────────────────────────────────────────────
|
||||||
|
seed_ctmath_flashcards_p3.js
|
||||||
|
Ещё две колоды карточек для подготовки к ЦЭ/ЦТ (интервальное повторение):
|
||||||
|
|
||||||
|
1. «ЦТ · Прогрессии — формулы» — арифметическая + геометрическая
|
||||||
|
2. «ЦТ · Двойные неравенства» — оценка a±b, a·b, a/b почленно (+ловушки)
|
||||||
|
|
||||||
|
Источники:
|
||||||
|
• Прогрессии — канонический набор формул ЦТ (отдельной шпоры Кедр нет).
|
||||||
|
• Двойные неравенства — Кедр «Операции_с_двойными_неравенствами.pdf»
|
||||||
|
(сложение/умножение/вычитание/деление двойных неравенств; ловушки строгости
|
||||||
|
и запрет почленного вычитания/деления).
|
||||||
|
|
||||||
|
Математика — KaTeX inline $…$ (страница флешкарт рендерит \( \), \[ \], $ $; НЕ $$).
|
||||||
|
Те же владелец/таблицы/стиль, что seed_ctmath_flashcards.js / _p2.js.
|
||||||
|
|
||||||
|
Идемпотентность: колода ищется по (user_id, title). Если уже есть и наполнена —
|
||||||
|
пропуск (не клобберит SR-прогресс). Пустую/новую — наполняет.
|
||||||
|
|
||||||
|
Запуск:
|
||||||
|
node backend/scripts/seed_ctmath_flashcards_p3.js # DRY-RUN (по умолчанию)
|
||||||
|
node backend/scripts/seed_ctmath_flashcards_p3.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: '#06D6A0',
|
||||||
|
descr: 'Арифметическая и геометрическая прогрессии: n-й член, суммы, характеристические свойства.',
|
||||||
|
cards: [
|
||||||
|
// ── Арифметическая ───────────────────────────────────────────────────
|
||||||
|
['Арифметическая прогрессия — $n$-й член', '$a_n=a_1+(n-1)d$'],
|
||||||
|
['Разность арифметической прогрессии', '$d=a_{n+1}-a_n$ (постоянная)'],
|
||||||
|
['Характеристическое свойство арифм. прогрессии', '$a_n=\\dfrac{a_{n-1}+a_{n+1}}{2}$ — каждый член есть среднее арифметическое соседних'],
|
||||||
|
['Сумма $n$ членов арифм. прогрессии', '$S_n=\\dfrac{a_1+a_n}{2}\\cdot n$'],
|
||||||
|
['Сумма арифм. прогрессии через $d$', '$S_n=\\dfrac{2a_1+(n-1)d}{2}\\cdot n$'],
|
||||||
|
['Связь двух членов арифм. прогрессии', '$a_n=a_k+(n-k)d$'],
|
||||||
|
// ── Геометрическая ───────────────────────────────────────────────────
|
||||||
|
['Геометрическая прогрессия — $n$-й член', '$b_n=b_1\\,q^{\\,n-1}$'],
|
||||||
|
['Знаменатель геометрической прогрессии', '$q=\\dfrac{b_{n+1}}{b_n}$ (постоянный, $q\\neq0$)'],
|
||||||
|
['Характеристическое свойство геом. прогрессии', '$b_n^2=b_{n-1}\\cdot b_{n+1}$'],
|
||||||
|
['Сумма $n$ членов геом. прогрессии ($q\\neq1$)', '$S_n=\\dfrac{b_1(q^{\\,n}-1)}{q-1}$'],
|
||||||
|
['Сумма бесконечной убывающей геом. прогрессии ($|q|<1$)', '$S=\\dfrac{b_1}{1-q}$'],
|
||||||
|
['Связь двух членов геом. прогрессии', '$b_n=b_k\\cdot q^{\\,n-k}$'],
|
||||||
|
]},
|
||||||
|
|
||||||
|
{ title: 'ЦТ · Двойные неравенства', color: '#EF476F',
|
||||||
|
descr: 'Оценка суммы, разности, произведения и частного через двойные неравенства. Ловушки вычитания и деления.',
|
||||||
|
cards: [
|
||||||
|
['Сложение неравенств', 'Складываем почленно ТОЛЬКО одинаково направленные. $5\\le a\\le6$, $7\\le b\\le9$ $\\Rightarrow$ $12\\le a+b\\le15$'],
|
||||||
|
['Умножение неравенств', 'Перемножаем почленно (все части положительны). $5\\le a\\le6$, $7\\le b\\le9$ $\\Rightarrow$ $35\\le ab\\le54$'],
|
||||||
|
['Ловушка строгости', 'Если хоть одно исходное неравенство строгое, результат строгий ($<$). Напр. $5\\le a<6$, $7<b<9$ $\\Rightarrow$ $12<a+b<15$'],
|
||||||
|
['Оценка разности $a-b$ — приём', '$a-b=a+(-b)$: неравенство для $b$ умножаем на $-1$ (переворот): $7<b<9$ $\\Rightarrow$ $-9<-b<-7$, затем складываем с $a$'],
|
||||||
|
['Пример: оценка $a-b$', '$5<a<6$, $7<b<9$: $(5<a<6)+(-9<-b<-7)$ $\\Rightarrow$ $-4<a-b<-1$'],
|
||||||
|
['Почему нельзя вычитать неравенства почленно', 'Почленно складывать/умножать можно только одинаково направленные. Прямое $5-9<a-b<6-7$ даёт $-2<a-b<-3$ — бессмыслица'],
|
||||||
|
['Оценка частного $\\dfrac{a}{b}$ — приём', '$\\dfrac{a}{b}=a\\cdot\\dfrac{1}{b}$: для $b>0$ берём обратные с переворотом: $7<b<9$ $\\Rightarrow$ $\\dfrac{1}{9}<\\dfrac{1}{b}<\\dfrac{1}{7}$, затем умножаем на $a$'],
|
||||||
|
['Пример: оценка $\\dfrac{a}{b}$', '$5<a<6$, $7<b<9$: $(5<a<6)\\cdot\\left(\\dfrac{1}{9}<\\dfrac{1}{b}<\\dfrac{1}{7}\\right)$ $\\Rightarrow$ $\\dfrac{5}{9}<\\dfrac{a}{b}<\\dfrac{6}{7}$'],
|
||||||
|
['Условие почленного умножения/деления', 'Все части неравенств положительны. Для отрицательных частей знаки переворачиваются — оценивать осторожно'],
|
||||||
|
]},
|
||||||
|
];
|
||||||
|
|
||||||
|
/* ── 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_p3 (${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_p3.js --apply\n');
|
||||||
|
else console.log('Готово. Колоды добавлены (владелец — admin; раздать классу — через доступ к колоде).\n');
|
||||||
Reference in New Issue
Block a user