feat(chemistry7): Phase 1 Волна 3 — Глава 1, §§7–9
§7 Химическая формула (разбор формулы на состав, индекс/коэффициент), §8 Относительная молекулярная масса (калькулятор M_r через Chem8.molarMass), §9 Валентность (конструктор формулы по валентности через НОК индексов). Теория, тренажёры задач. Тест: 9/9 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -235,9 +235,73 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Волна 3 ── */
|
||||
|
||||
/* §7 — разбор химической формулы на состав */
|
||||
function mount_p7() {
|
||||
var inp = $('p7-in'), out = $('p7-out'), go = $('p7-go'); if (!inp || inp._built) return; inp._built = 1;
|
||||
function calc() {
|
||||
var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null;
|
||||
if (!cnt || !Object.keys(cnt).length) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу. Проверь символы элементов (например, H2SO4).'; return; }
|
||||
var els = Object.keys(cnt), tot = els.reduce(function (s, e) { return s + cnt[e]; }, 0);
|
||||
out.className = 'out ok';
|
||||
out.innerHTML = '<span class="bd"><b>' + (C().formula ? C().formula(f) : f) + '</b><br>'
|
||||
+ 'Элементов: <b>' + els.length + '</b> (' + (els.length === 1 ? 'простое' : 'сложное') + ' вещество)<br>'
|
||||
+ els.map(function (e) { return e + ': ' + cnt[e] + ' ' + (cnt[e] === 1 ? 'атом' : 'атома(ов)'); }).join('<br>')
|
||||
+ '<br>Всего атомов в формуле: <b>' + tot + '</b></span>';
|
||||
}
|
||||
go.addEventListener('click', calc);
|
||||
inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); });
|
||||
document.querySelectorAll('.p7-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); });
|
||||
calc();
|
||||
}
|
||||
|
||||
/* §8 — калькулятор относительной молекулярной массы M_r */
|
||||
function mount_p8() {
|
||||
var inp = $('p8-in'), out = $('p8-out'), go = $('p8-go'); if (!inp || inp._built) return; inp._built = 1;
|
||||
function calc() {
|
||||
var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null, mr = C().molarMass ? C().molarMass(f) : NaN;
|
||||
if (!cnt || isNaN(mr)) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу.'; return; }
|
||||
out.className = 'out ok';
|
||||
out.innerHTML = '<span class="bd"><b>M_r(' + f + ') = ' + C().fmt(mr) + '</b><br>'
|
||||
+ Object.keys(cnt).map(function (e) { return e + ': A_r=' + (C().arOf ? C().arOf(e) : '?') + ' × ' + cnt[e]; }).join(' | ')
|
||||
+ '<br>Σ = ' + Object.keys(cnt).map(function (e) { return (C().arOf ? C().arOf(e) : '?') + '·' + cnt[e]; }).join(' + ') + ' = ' + C().fmt(mr) + '</span>';
|
||||
}
|
||||
go.addEventListener('click', calc);
|
||||
inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); });
|
||||
document.querySelectorAll('.p8-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); });
|
||||
calc();
|
||||
}
|
||||
|
||||
/* §9 — конструктор формулы по валентности (НОК индексов) */
|
||||
function gcd(a, b) { return b ? gcd(b, a % b) : a; }
|
||||
var VA = [ ['Na', 1], ['K', 1], ['H', 1], ['Mg', 2], ['Ca', 2], ['Zn', 2], ['Cu', 2], ['Al', 3], ['C', 4] ];
|
||||
var VB = [ ['O', 2], ['Cl', 1], ['S', 2] ];
|
||||
function mount_p9() {
|
||||
var m = $('p9-bld'); if (!m || m._built) return; m._built = 1;
|
||||
function optA(){ return VA.map(function(e,i){ return '<option value="'+i+'"'+(e[0]==='Al'?' selected':'')+'>'+e[0]+' (валентность '+'I'.repeat(e[1]).replace('IIII','IV')+')</option>'; }).join(''); }
|
||||
function optB(){ return VB.map(function(e,i){ return '<option value="'+i+'">'+e[0]+' (валентность '+'I'.repeat(e[1])+')</option>'; }).join(''); }
|
||||
m.innerHTML = '<div class="fld"><label>Элемент A</label><select id="p9-a">'+optA()+'</select>'
|
||||
+'<label>Элемент B</label><select id="p9-b">'+optB()+'</select></div><div class="out" id="p9-bout"></div>';
|
||||
function upd() {
|
||||
var a = VA[+$('p9-a').value], b = VB[+$('p9-b').value];
|
||||
var lcm = a[1] * b[1] / gcd(a[1], b[1]);
|
||||
var ia = lcm / a[1], ib = lcm / b[1];
|
||||
var raw = a[0] + (ia > 1 ? ia : '') + b[0] + (ib > 1 ? ib : '');
|
||||
var out = $('p9-bout'); out.className = 'out ok';
|
||||
out.innerHTML = '<span class="bd">Валентности: ' + a[0] + ' = ' + 'I'.repeat(a[1]).replace('IIII','IV') + ', ' + b[0] + ' = ' + 'I'.repeat(b[1]) + '<br>'
|
||||
+ 'Наименьшее общее кратное валентностей = <b>' + lcm + '</b><br>'
|
||||
+ 'Индексы: ' + a[0] + ' → ' + ia + ', ' + b[0] + ' → ' + ib + '<br>'
|
||||
+ 'Формула: <b style="font-size:1.15rem">' + (C().formula ? C().formula(raw) : raw) + '</b><br>'
|
||||
+ 'Проверка: ' + ia + '·' + a[1] + ' = ' + ib + '·' + b[1] + ' = ' + lcm + ' единиц валентности — совпало.</span>';
|
||||
}
|
||||
$('p9-a').addEventListener('change', upd); $('p9-b').addEventListener('change', upd); upd();
|
||||
}
|
||||
|
||||
W.CHEM8_WIDGETS = Object.assign(W.CHEM8_WIDGETS || {}, {
|
||||
p1: mount_p1, p2: mount_p2, pr1: mount_pr1, p3: mount_p3,
|
||||
p4: mount_p4, p5: mount_p5, p6: mount_p6
|
||||
p4: mount_p4, p5: mount_p5, p6: mount_p6,
|
||||
p7: mount_p7, p8: mount_p8, p9: mount_p9
|
||||
});
|
||||
W.FLAG_MOUNTS = Object.assign(W.FLAG_MOUNTS || {}, {});
|
||||
})(window);
|
||||
|
||||
Reference in New Issue
Block a user