+ ${widget('Решатель системы линейных неравенств', 'CALC', 'Введите до 5 неравенств $ax+b$ ≷ $c$. Используйте кнопки «+ Добавить» / «×» для управления строками.', `
+
@@ -4095,14 +4140,69 @@ function buildP6(){
setTimeout(()=>{ initSysSolver(); initDoubleIneq(); initFindInt(); }, 50);
}
-/* ──── Sys Solver ──── */
+/* ──── Sys Solver (multi-row) ──── */
let sysCurMode = 'sys';
+let _sysRows = [];
+let _sysDefaults = [{a:3,b:6,op:'≥',c:0},{a:-2,b:5,op:'>',c:1}];
+
function initSysSolver(){
- ['s1-a','s1-b','s1-c','s1-r','s2-a','s2-b','s2-c','s2-r'].forEach(id=>{
- const e = document.getElementById(id);
- if(e) e.addEventListener('input', sysUpdate);
- if(e && e.tagName === 'SELECT') e.addEventListener('change', sysUpdate);
+ _sysRows = [];
+ _sysDefaults.forEach((d,i) => { _sysRows.push({id:'sr'+(i+1), a:d.a, b:d.b, op:d.op, c:d.c}); });
+ _sysRebuildHTML();
+ sysUpdate();
+}
+
+function sysAddRow(a, b, op, c){
+ if(_sysRows.length >= 5) return;
+ const id = 'sr' + (_sysRows.length + 1);
+ _sysRows.push({id, a:a||1, b:b||0, op:op||'≥', c:c||0});
+ _sysRebuildHTML();
+ sysUpdate();
+}
+
+function _sysRebuildHTML(){
+ const list = document.getElementById('sys-list');
+ if(!list) return;
+ const COLORS = ['var(--pri)','var(--acc)','var(--ok)','var(--warn)','var(--sec-acc,#9333ea)'];
+ list.innerHTML = _sysRows.map((r,i)=>`
+
+ `).join('');
+ _sysRebindHandlers();
+}
+
+function _sysRebindHandlers(){
+ _sysRows.forEach(r => {
+ [r.id+'-a', r.id+'-b', r.id+'-c', r.id+'-r'].forEach(id => {
+ const e = document.getElementById(id);
+ if(e){ e.addEventListener('input', sysUpdate); e.addEventListener('change', sysUpdate); }
+ });
});
+}
+
+function sysRemoveRow(i){
+ if(_sysRows.length <= 1) return;
+ _sysRows.splice(i, 1);
+ // re-assign ids
+ _sysRows = _sysRows.map((r,idx) => ({...r, id:'sr'+(idx+1)}));
+ _sysRebuildHTML();
sysUpdate();
}
function solveLin(a, b, op, c){
@@ -4121,81 +4221,97 @@ function solveLin(a, b, op, c){
return { bound, strict, dir };
}
function sysUpdate(){
- const s1 = solveLin(+document.getElementById('s1-a').value, +document.getElementById('s1-b').value, document.getElementById('s1-r').value, +document.getElementById('s1-c').value);
- const s2 = solveLin(+document.getElementById('s2-a').value, +document.getElementById('s2-b').value, document.getElementById('s2-r').value, +document.getElementById('s2-c').value);
- function describe(s){
- const rel = s.dir + (s.strict ? '' : '=');
- return 'x ' + (s.dir === '>' ? (s.strict ? '>' : '≥') : (s.strict ? '<' : '≤')) + ' ' + s.bound;
+ if(!_sysRows.length) return;
+ function getRowVal(r){
+ const aEl = document.getElementById(r.id+'-a');
+ const bEl = document.getElementById(r.id+'-b');
+ const cEl = document.getElementById(r.id+'-c');
+ const rEl = document.getElementById(r.id+'-r');
+ if(!aEl) return null;
+ const op = rEl ? rEl.value : '≥';
+ // handle < being stored as <
+ const opClean = op === '<' ? '<' : op;
+ return solveLin(+aEl.value||0, +bEl.value||0, opClean, +cEl.value||0);
}
- document.getElementById('s1-out').innerHTML = describe(s1);
- document.getElementById('s2-out').innerHTML = describe(s2);
- // intersect or union
- function toInterval(s){
+ function describe(s){
+ return 'x ' + (s.dir === '>' ? (s.strict ? '>' : '≥') : (s.strict ? '<' : '≤')) + ' ' + (Number.isFinite(s.bound) ? +s.bound.toFixed(4) : s.bound);
+ }
+ function toIntervalSys(s){
if(s.dir === '>') return { l:s.bound, r:Infinity, lOp:s.strict, rOp:true };
else return { l:-Infinity, r:s.bound, lOp:true, rOp:s.strict };
}
- const A = toInterval(s1), B = toInterval(s2);
- // intersection of two intervals
- let inter = null;
- const lo = Math.max(A.l, B.l);
- const hi = Math.min(A.r, B.r);
- const loOp = (A.l > B.l) ? A.lOp : (A.l < B.l) ? B.lOp : (A.lOp || B.lOp);
- const hiOp = (A.r < B.r) ? A.rOp : (A.r > B.r) ? B.rOp : (A.rOp || B.rOp);
- if(lo < hi || (lo === hi && !loOp && !hiOp)) inter = {l:lo, r:hi, lOp:loOp, rOp:hiOp};
+ function intersectTwo(A, B){
+ const lo = Math.max(A.l, B.l);
+ const hi = Math.min(A.r, B.r);
+ const loOp = (A.l > B.l) ? A.lOp : (A.l < B.l) ? B.lOp : (A.lOp || B.lOp);
+ const hiOp = (A.r < B.r) ? A.rOp : (A.r > B.r) ? B.rOp : (A.rOp || B.rOp);
+ if(lo < hi || (lo === hi && !loOp && !hiOp)) return {l:lo, r:hi, lOp:loOp, rOp:hiOp};
+ return null;
+ }
+ const COLORS = ['#e91e63','#03a9f4','#10b981','#f59e0b','#9333ea'];
+ const intervals = [];
+ _sysRows.forEach((r) => {
+ const s = getRowVal(r);
+ if(!s || !Number.isFinite(s.bound)) return;
+ const outEl = document.getElementById(r.id+'-out');
+ if(outEl) outEl.textContent = describe(s);
+ intervals.push(toIntervalSys(s));
+ });
+ let inter = intervals.length ? intervals[0] : null;
+ for(let i = 1; i < intervals.length; i++) inter = inter ? intersectTwo(inter, intervals[i]) : null;
// visualize
const vis = document.getElementById('sys-line');
+ if(!vis) return;
vis.innerHTML='';
const VLO = -8, VHI = 12;
- vis.appendChild(el('div',{style:'position:absolute;top:140px;left:3%;right:3%;height:2px;background:var(--text)'}));
+ const axisY = 20 + _sysRows.length * 25 + 20;
+ vis.style.height = (axisY + 36) + 'px';
+ vis.appendChild(el('div',{style:`position:absolute;top:${axisY}px;left:3%;right:3%;height:2px;background:var(--text)`}));
for(let i = VLO; i <= VHI; i++){
const x = 3 + (i-VLO)/(VHI-VLO)*94;
- vis.appendChild(el('div',{style:`position:absolute;top:152px;left:${x}%;transform:translateX(-50%);font-size:.72rem;color:var(--muted);font-family:'JetBrains Mono',monospace`}, ''+i));
+ vis.appendChild(el('div',{style:`position:absolute;top:${axisY+12}px;left:${x}%;transform:translateX(-50%);font-size:.72rem;color:var(--muted);font-family:'JetBrains Mono',monospace`}, ''+i));
}
function drawInt(y, iv, col, lbl){
if(!iv) return;
const l = iv.l === -Infinity ? VLO : iv.l;
const r = iv.r === Infinity ? VHI : iv.r;
if(l > VHI || r < VLO) return;
- const x1 = 3 + Math.max(VLO, l - VLO) / (VHI-VLO) * 94 - (VLO < 0 ? VLO/(VHI-VLO)*94 : 0);
const xL = 3 + (Math.max(VLO,l) - VLO)/(VHI-VLO)*94;
const xR = 3 + (Math.min(VHI,r) - VLO)/(VHI-VLO)*94;
- vis.appendChild(el('div',{style:`position:absolute;top:${y}px;left:${xL}%;width:${xR-xL}%;height:10px;background:${col};border-radius:5px`}));
+ vis.appendChild(el('div',{style:`position:absolute;top:${y}px;left:${xL}%;width:${Math.max(0,xR-xL)}%;height:10px;background:${col};border-radius:5px`}));
if(iv.l !== -Infinity) vis.appendChild(el('div',{style:`position:absolute;top:${y-2}px;left:${xL}%;width:14px;height:14px;border-radius:50%;background:${iv.lOp?'var(--card)':col};border:2.5px solid ${col};transform:translateX(-50%)`}));
if(iv.r !== Infinity) vis.appendChild(el('div',{style:`position:absolute;top:${y-2}px;left:${xR}%;width:14px;height:14px;border-radius:50%;background:${iv.rOp?'var(--card)':col};border:2.5px solid ${col};transform:translateX(-50%)`}));
vis.appendChild(el('div',{style:`position:absolute;top:${y-2}px;left:3px;font-size:.74rem;font-weight:700;color:${col}`}, lbl));
}
- drawInt(20, A, '#e91e63', '1)');
- drawInt(50, B, '#03a9f4', '2)');
- let ans, lbl, col;
- if(sysCurMode === 'sys'){
- ans = inter; lbl = '∩ Система:'; col = '#10b981';
- } else {
- // union
- if(A.r < B.l || B.r < A.l){ ans = null; lbl = '∪ Совокупность (2 части):'; col = '#10b981'; }
- else { ans = {l:Math.min(A.l,B.l), r:Math.max(A.r,B.r), lOp:Math.min(A.l,B.l)===A.l?A.lOp:B.lOp, rOp:Math.max(A.r,B.r)===A.r?A.rOp:B.rOp}; lbl = '∪ Совокупность:'; col = '#10b981'; }
- }
- if(sysCurMode === 'un' && !ans){
- drawInt(80, A, col, '∪');
- drawInt(110, B, col, '');
- } else {
- drawInt(95, ans, col, lbl);
- }
- // answer
+ intervals.forEach((iv, i) => drawInt(10 + i*25, iv, COLORS[i%COLORS.length], (i+1)+')'));
function fmt(iv){
if(!iv) return '∅';
const lA = iv.lOp ? '(' : '[';
const rA = iv.rOp ? ')' : ']';
- const l = iv.l === -Infinity ? '-∞' : iv.l;
- const r = iv.r === Infinity ? '+∞' : iv.r;
+ const l = iv.l === -Infinity ? '-∞' : +iv.l.toFixed(4);
+ const r = iv.r === Infinity ? '+∞' : +iv.r.toFixed(4);
return lA + l + '; ' + r + (iv.r === Infinity ? ')' : rA);
}
let ansText;
if(sysCurMode === 'sys'){
ansText = inter ? fmt(inter) : '∅';
- } else if(ans){
- ansText = fmt(ans);
+ if(inter) drawInt(axisY - 18, inter, '#10b981', '∩');
} else {
- ansText = fmt(A) + ' ∪ ' + fmt(B);
+ // union: just show all individually in green
+ intervals.forEach(iv => drawInt(axisY - 18, iv, '#10b981', '∪'));
+ if(intervals.length === 2){
+ const A2 = intervals[0], B2 = intervals[1];
+ if(A2.r >= B2.l && B2.r >= A2.l){
+ const merged = {l:Math.min(A2.l,B2.l), r:Math.max(A2.r,B2.r),
+ lOp:Math.min(A2.l,B2.l)===A2.l?A2.lOp:B2.lOp,
+ rOp:Math.max(A2.r,B2.r)===A2.r?A2.rOp:B2.rOp};
+ ansText = fmt(merged);
+ } else {
+ ansText = fmt(A2) + ' ∪ ' + fmt(B2);
+ }
+ } else {
+ ansText = intervals.map(fmt).join(' ∪ ');
+ }
}
document.getElementById('sys-answer').textContent = ansText;
}
@@ -5756,5 +5872,432 @@ function initWave4(){
document.addEventListener('DOMContentLoaded', ()=>setTimeout(initWave4, 200));
+
+