From b6dedfe51625b5528ab871e732caac74e7555d52 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Sat, 30 May 2026 13:58:47 +0300 Subject: [PATCH] =?UTF-8?q?feat(biochem):=20=D0=A4=D0=B0=D0=B7=D0=B0=205.1?= =?UTF-8?q?=20=E2=80=94=20=D1=81=D0=B8=D0=B4=20=D0=B7=D0=B0=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=20balance/m?= =?UTF-8?q?atch/classify/complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backend/scripts/seed_biochem_challenges.js (идемпотентно) добавляет 16 заданий недостающих типов: balance 5, match 3, classify 4, complete 4. Контроллер их уже поддерживал, но данных не было — фильтры в UI пустовали. data_json совпадает с UI редактора и валидацией контроллера; XP начисляется через awardXP. Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/scripts/seed_biochem_challenges.js | 116 +++++++++++++++++++++ plans/BIOCHEM_UPGRADE.md | 11 +- 2 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 backend/scripts/seed_biochem_challenges.js diff --git a/backend/scripts/seed_biochem_challenges.js b/backend/scripts/seed_biochem_challenges.js new file mode 100644 index 0000000..52887f5 --- /dev/null +++ b/backend/scripts/seed_biochem_challenges.js @@ -0,0 +1,116 @@ +'use strict'; +/* + * Сид недостающих типов биохим-заданий: balance / match / classify / complete. + * Контроллер biochemController.js эти типы уже поддерживает, а данных в БД не было + * (фильтры в UI были пустыми). Идемпотентно: пропускает уже существующие по title. + * + * Запуск: node backend/scripts/seed_biochem_challenges.js + */ +const db = require('../src/db/db'); + +const getMaxOrder = db.prepare('SELECT MAX(order_n) AS m FROM bio_challenges'); +const existsByTitle = db.prepare('SELECT 1 FROM bio_challenges WHERE title = ?'); +const insert = db.prepare(`INSERT INTO bio_challenges + (title, description, type, target_formula, hint, xp_reward, difficulty, topic_tag, order_n, data_json) + VALUES (@title, @description, @type, @target_formula, @hint, @xp_reward, @difficulty, @topic_tag, @order_n, @data_json)`); + +// data_json-схемы (совпадают с UI biochem.html и контроллером): +// balance: { reactants:[...], products:[...], coefficients:[...] } (порядок: реагенты, затем продукты) +// match: { pairs:[{left, right}, ...] } +// classify: { target, choices:[...], answer } +// complete: { equation, choices:[...], answer } +const CHALLENGES = [ + // ── balance ────────────────────────────────────────────────────────────── + { type: 'balance', difficulty: 1, xp: 40, title: 'Баланс: синтез воды', + desc: 'Расставь коэффициенты в уравнении образования воды.', + data: { reactants: ['H2', 'O2'], products: ['H2O'], coefficients: [2, 1, 2] } }, + { type: 'balance', difficulty: 2, xp: 50, title: 'Баланс: горение метана', + desc: 'Сбалансируй уравнение полного сгорания метана.', + data: { reactants: ['CH4', 'O2'], products: ['CO2', 'H2O'], coefficients: [1, 2, 1, 2] } }, + { type: 'balance', difficulty: 2, xp: 50, title: 'Баланс: синтез аммиака', + desc: 'Процесс Габера — расставь коэффициенты.', + data: { reactants: ['N2', 'H2'], products: ['NH3'], coefficients: [1, 3, 2] } }, + { type: 'balance', difficulty: 3, xp: 60, title: 'Баланс: горение этана', + desc: 'Сбалансируй сгорание этана (дробные множители убери).', + data: { reactants: ['C2H6', 'O2'], products: ['CO2', 'H2O'], coefficients: [2, 7, 4, 6] } }, + { type: 'balance', difficulty: 2, xp: 50, title: 'Баланс: ржавление железа', + desc: 'Окисление железа кислородом.', + data: { reactants: ['Fe', 'O2'], products: ['Fe2O3'], coefficients: [4, 3, 2] } }, + + // ── match ──────────────────────────────────────────────────────────────── + { type: 'match', difficulty: 1, xp: 40, title: 'Сопоставь: простые молекулы', + desc: 'Совмести формулу с названием.', + data: { pairs: [ + { left: 'H2O', right: 'Вода' }, { left: 'CO2', right: 'Углекислый газ' }, + { left: 'NH3', right: 'Аммиак' }, { left: 'CH4', right: 'Метан' } ] } }, + { type: 'match', difficulty: 2, xp: 50, title: 'Сопоставь: органические вещества', + desc: 'Совмести формулу с названием.', + data: { pairs: [ + { left: 'C2H5OH', right: 'Этанол' }, { left: 'CH3COOH', right: 'Уксусная кислота' }, + { left: 'C6H6', right: 'Бензол' }, { left: 'C2H4', right: 'Этилен' } ] } }, + { type: 'match', difficulty: 2, xp: 50, title: 'Сопоставь: кислоты и основания', + desc: 'Совмести формулу с названием.', + data: { pairs: [ + { left: 'HCl', right: 'Соляная кислота' }, { left: 'H2SO4', right: 'Серная кислота' }, + { left: 'NaOH', right: 'Гидроксид натрия' }, { left: 'HNO3', right: 'Азотная кислота' } ] } }, + + // ── classify ───────────────────────────────────────────────────────────── + { type: 'classify', difficulty: 1, xp: 40, title: 'Класс: метан', target: 'CH4', + desc: 'К какому классу относится CH₄?', + data: { target: 'CH4', choices: ['Алкан', 'Алкен', 'Алкин', 'Арен'], answer: 'Алкан' } }, + { type: 'classify', difficulty: 2, xp: 45, title: 'Класс: этанол', target: 'C2H5OH', + desc: 'К какому классу относится C₂H₅OH?', + data: { target: 'C2H5OH', choices: ['Спирт', 'Карбоновая кислота', 'Альдегид', 'Кетон'], answer: 'Спирт' } }, + { type: 'classify', difficulty: 2, xp: 45, title: 'Класс: уксусная кислота', target: 'CH3COOH', + desc: 'К какому классу относится CH₃COOH?', + data: { target: 'CH3COOH', choices: ['Карбоновая кислота', 'Спирт', 'Сложный эфир', 'Альдегид'], answer: 'Карбоновая кислота' } }, + { type: 'classify', difficulty: 2, xp: 45, title: 'Класс: бензол', target: 'C6H6', + desc: 'К какому классу относится C₆H₆?', + data: { target: 'C6H6', choices: ['Ароматическое', 'Алкан', 'Алкен', 'Спирт'], answer: 'Ароматическое' } }, + + // ── complete ───────────────────────────────────────────────────────────── + { type: 'complete', difficulty: 1, xp: 40, title: 'Заверши: образование воды', + desc: 'Какого реагента не хватает?', + data: { equation: '2H₂ + ? → 2H₂O', choices: ['O2', 'CO2', 'N2', 'H2'], answer: 'O2' } }, + { type: 'complete', difficulty: 2, xp: 45, title: 'Заверши: горение метана', + desc: 'Какого продукта не хватает?', + data: { equation: 'CH₄ + 2O₂ → CO₂ + ?', choices: ['H2O', 'H2', 'O2', 'CO'], answer: 'H2O' } }, + { type: 'complete', difficulty: 2, xp: 45, title: 'Заверши: синтез аммиака', + desc: 'Какой продукт образуется?', + data: { equation: 'N₂ + 3H₂ → ?', choices: ['2NH3', 'NH3', 'N2H4', '2NO'], answer: '2NH3' } }, + { type: 'complete', difficulty: 1, xp: 40, title: 'Заверши: горение углерода', + desc: 'Какой продукт образуется при избытке кислорода?', + data: { equation: 'C + O₂ → ?', choices: ['CO2', 'CO', 'C2O', 'O3'], answer: 'CO2' } }, +]; + +let order = (getMaxOrder.get().m || 0); +let added = 0, skipped = 0; + +db.exec('BEGIN'); +try { + for (const c of CHALLENGES) { + if (existsByTitle.get(c.title)) { skipped++; continue; } + order++; + insert.run({ + title: c.title, + description: c.desc || '', + type: c.type, + target_formula: c.target || '', + hint: c.hint || null, + xp_reward: c.xp || 40, + difficulty: c.difficulty || 1, + topic_tag: c.type, + order_n: order, + data_json: JSON.stringify(c.data), + }); + added++; + } + db.exec('COMMIT'); +} catch (e) { + db.exec('ROLLBACK'); + throw e; +} + +console.log(`biochem challenges seed: добавлено ${added}, пропущено ${skipped} (уже были).`); +console.log('типы теперь:', db.prepare('SELECT type, COUNT(*) c FROM bio_challenges GROUP BY type ORDER BY type').all() + .map(r => `${r.type}:${r.c}`).join(' ')); diff --git a/plans/BIOCHEM_UPGRADE.md b/plans/BIOCHEM_UPGRADE.md index 3a05601..0e4c342 100644 --- a/plans/BIOCHEM_UPGRADE.md +++ b/plans/BIOCHEM_UPGRADE.md @@ -114,11 +114,18 @@ --- -## Фаза 5 — Challenges и геймификация — [ ] +## Фаза 5 — Challenges и геймификация — [~] + +> Сделано: `backend/scripts/seed_biochem_challenges.js` (идемпотентно) засидировал +> 16 заданий недостающих типов — **balance 5, match 3, classify 4, complete 4**. +> Все 7 фильтров в UI редактора теперь с данными; контроллер их уже валидирует, +> XP начисляется. data_json совпадает с UI (balance: reactants/products/coefficients; +> match: pairs; classify/complete: target/equation/choices/answer). +> Осталось: drag-and-drop (5.2), 3D-build (5.3), адаптивность (5.4), ачивки bc_* (5.5). Слоты ачивок `bc_5_challenges`/`bc_20_challenges` уже есть в `_shared.js` — довести до конца и расширить вызовы. -- [ ] 5.1 Реально засидировать недостающие типы challenge: balance (drag-коэффициенты), match, classify, complete (контроллер их уже поддерживает, данных в БД нет). +- [x] 5.1 Засидированы типы challenge: balance, match, classify, complete (16 заданий, идемпотентный сидер). - [ ] 5.2 UI drag-and-drop для balance/match (сейчас только выбор/ввод). - [ ] 5.3 3D-build challenge: собрать молекулу и проверить не только формулу, но и связность/геометрию. - [ ] 5.4 Адаптивная сложность + «задача дня»; streak по биохимии.