feat(biochem): Фаза 5.2 — живая поэлементная проверка баланса в задании
По мере ввода коэффициентов в balance-задании — счётчик атомов каждого элемента слева=справа с ✓/✗ и бейджем «сбалансировано» (BIO.parseFormula). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+35
-3
@@ -1925,21 +1925,53 @@ function renderBalanceChallenge(data) {
|
||||
wrap.style.display = '';
|
||||
const reactants = data.reactants || [];
|
||||
const products = data.products || [];
|
||||
const count = reactants.length + products.length;
|
||||
wrap._reactants = reactants;
|
||||
wrap._products = products;
|
||||
let html = '<div class="balance-eq">';
|
||||
reactants.forEach((f,i) => {
|
||||
if (i > 0) html += '<span class="bal-op">+</span>';
|
||||
html += `<input type="number" class="bal-coef" min="1" max="99" value="1" placeholder="?">`;
|
||||
html += `<input type="number" class="bal-coef" min="1" max="99" value="1" placeholder="?" oninput="updateBalanceFeedback()">`;
|
||||
html += `<span class="bal-formula">${escHtml(f)}</span>`;
|
||||
});
|
||||
html += '<span class="bal-arrow"><svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg></span>';
|
||||
products.forEach((f,i) => {
|
||||
if (i > 0) html += '<span class="bal-op">+</span>';
|
||||
html += `<input type="number" class="bal-coef" min="1" max="99" value="1" placeholder="?">`;
|
||||
html += `<input type="number" class="bal-coef" min="1" max="99" value="1" placeholder="?" oninput="updateBalanceFeedback()">`;
|
||||
html += `<span class="bal-formula">${escHtml(f)}</span>`;
|
||||
});
|
||||
html += '</div>';
|
||||
// живая поэлементная проверка сохранения атомов
|
||||
html += '<div id="bal-feedback" style="display:flex;flex-wrap:wrap;gap:5px;margin-top:2px"></div>';
|
||||
wrap.innerHTML = html;
|
||||
updateBalanceFeedback();
|
||||
}
|
||||
|
||||
// Живой счётчик атомов слева/справа по каждому элементу (через BIO.parseFormula)
|
||||
function updateBalanceFeedback() {
|
||||
const wrap = document.getElementById('bp-chal-balance');
|
||||
const fb = document.getElementById('bal-feedback');
|
||||
if (!wrap || !fb || !window.BIO) return;
|
||||
const reactants = wrap._reactants || [], products = wrap._products || [];
|
||||
const coefs = Array.from(wrap.querySelectorAll('.bal-coef')).map(i => parseInt(i.value) || 0);
|
||||
const sideCounts = (formulas, offset) => {
|
||||
const tot = {};
|
||||
formulas.forEach((f, i) => {
|
||||
const k = coefs[offset + i] || 0;
|
||||
const c = BIO.parseFormula(f);
|
||||
for (const el in c) tot[el] = (tot[el] || 0) + c[el] * k;
|
||||
});
|
||||
return tot;
|
||||
};
|
||||
const L = sideCounts(reactants, 0);
|
||||
const R = sideCounts(products, reactants.length);
|
||||
const els = [...new Set([...Object.keys(L), ...Object.keys(R)])].sort();
|
||||
let allOk = els.length > 0;
|
||||
fb.innerHTML = els.map(el => {
|
||||
const l = L[el] || 0, r = R[el] || 0, ok = l === r;
|
||||
if (!ok) allOk = false;
|
||||
const col = ok ? '#4ade80' : '#f87171';
|
||||
return `<span style="font-size:.66rem;font-weight:700;padding:2px 7px;border-radius:999px;border:1px solid ${col}40;color:${col}">${el}: ${l}=${r} ${ok ? '✓' : '✗'}</span>`;
|
||||
}).join('') + (allOk ? '<span style="font-size:.66rem;font-weight:700;padding:2px 7px;border-radius:999px;background:rgba(74,222,128,.14);color:#4ade80">сбалансировано</span>' : '');
|
||||
}
|
||||
|
||||
// Keyboard shortcuts
|
||||
|
||||
Reference in New Issue
Block a user