diff --git a/backend/tests/math6-page.test.js b/backend/tests/math6-page.test.js index 23207e5..cd38b8b 100644 --- a/backend/tests/math6-page.test.js +++ b/backend/tests/math6-page.test.js @@ -85,6 +85,23 @@ test('ch2: проценты и пропорции — интерактивы + assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | ')); }); +test('ch3: множество — интерактивы + финал', async () => { + const { doc, errors } = await loadDom('math_6_ch3.html'); + const win = doc.defaultView; + assert.ok(doc.querySelectorAll('#p1-iv1 [data-v]').length === 2 && doc.querySelector('#p1-cq'), '∈/∉ и счёт §1'); + win.goTo('p2'); await wait(80); + assert.ok(doc.querySelector('#p2-opts') && doc.querySelectorAll('#p2-iv2 [data-v]').length === 2, 'способы задания §2'); + win.goTo('p3'); await wait(80); + assert.ok(doc.querySelector('#p3-fig svg circle') && doc.querySelectorAll('#p3-iv1 [data-op]').length === 2, 'круги Эйлера/операции §3'); + win.goTo('p4'); await wait(80); + assert.ok(doc.querySelector('#p4-fig svg') && doc.querySelector('#p4-fq'), 'задача с кругами Эйлера §4'); + win.goTo('final'); await wait(80); + assert.ok(doc.querySelector('#fin-go'), 'арена боссов §3'); + win.bumpProgress('final', 100); await wait(20); + assert.ok(win.M6STATE.achievements.has('ch3_done'), 'достижение «Глава 3 пройдена»'); + assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | ')); +}); + test('ch5: координатная плоскость — интерактивы §1–§3 + финал', async () => { const { doc, errors } = await loadDom('math_6_ch5.html'); const win = doc.defaultView; diff --git a/frontend/js/math6_svg.js b/frontend/js/math6_svg.js index 76a5551..7e3b97b 100644 --- a/frontend/js/math6_svg.js +++ b/frontend/js/math6_svg.js @@ -177,4 +177,36 @@ M.pie = function (segs, opts) { return M.box(S, S, s, { maxw: opts.maxw || S }); }; +/* === КРУГИ ЭЙЛЕРА / ДИАГРАММА ВЕННА (два множества) === + * opts: {a,b (подписи), shade:'inter'|'union'|'a'|'b'|'none', shadeColor, + * regions:{aOnly,inter,bOnly,outside}} — числа/текст в областях. + */ +M.venn = function (opts) { + opts = opts || {}; + var W = 300, H = 190, cA = { x: 115, y: 100 }, cB = { x: 185, y: 100 }, r = 66; + var sc = opts.shadeColor || '#7c3aed'; + var s = ''; + var cir = function (c, fill, op) { return ''; }; + if (opts.shade === 'union') { s += cir(cA, sc, 0.22) + cir(cB, sc, 0.22); } + else if (opts.shade === 'inter') { s += '' + cir(cB, sc, 0.4) + ''; } + else if (opts.shade === 'a') { s += cir(cA, sc, 0.3) + '' + cir(cB, 'var(--card,#fff)', 1) + ''; } + else if (opts.shade === 'b') { s += cir(cB, sc, 0.3) + '' + cir(cB, 'var(--card,#fff)', 1) + '' + '' + cir(cB, sc, 0.3) + ''; } + /* контуры */ + s += ''; + s += ''; + /* подписи множеств */ + s += '' + (opts.a || 'A') + ''; + s += '' + (opts.b || 'B') + ''; + /* числа/текст в областях */ + var rg = opts.regions; + if (rg) { + function lab(x, y, t, col) { if (t == null || t === '') return ''; return '' + t + ''; } + s += lab(cA.x - 34, cA.y, rg.aOnly); + s += lab((cA.x + cB.x) / 2, cA.y, rg.inter); + s += lab(cB.x + 34, cB.y, rg.bOnly); + if (rg.outside != null) s += lab(W - 22, H - 14, rg.outside, 'var(--muted,#64748b)'); + } + return M.box(W, H, s, { maxw: opts.maxw || W }); +}; + })(); diff --git a/frontend/textbooks/math_6_ch3.html b/frontend/textbooks/math_6_ch3.html index 62208cc..d71d0f1 100644 --- a/frontend/textbooks/math_6_ch3.html +++ b/frontend/textbooks/math_6_ch3.html @@ -90,6 +90,292 @@ window.M6 = { sidebars: {}, tips: [], glossary: [], builders: {}, footer: 'Интерактивный учебник «Математика 6» · Глава 3 · Множество · LearnSpace' }; + +/* ===================== ВСПОМОГАТЕЛЬНОЕ ===================== */ +function _ri(a,b){ return a + Math.floor(Math.random()*(b-a+1)); } +function _pick(a){ return a[_ri(0,a.length-1)]; } +function _setStr(arr){ return '{' + arr.join(', ') + '}'; } +function _distinct(n,lo,hi){ var s=[],seen={}; while(s.length=0; }); } +function _union(A,B){ var u=A.slice(); B.forEach(function(x){ if(u.indexOf(x)<0)u.push(x); }); return u; } + +/* ===================== § 1. МНОЖЕСТВО. ЭЛЕМЕНТЫ. ПУСТОЕ МНОЖЕСТВО ===================== */ +function buildP1(){ + var box=document.getElementById('p1-body'); var h=''; + h+=makeCard('theory','Множество и его элементы','1.1', + '

Множество — это набор различных объектов, объединённых общим признаком. Объекты множества — его элементы. Множества обозначают большими буквами, элементы перечисляют в фигурных скобках: $A=\\{2;4;6;8\\}$.

' + +'

Запись $3\\in A$ читается «$3$ принадлежит $A$», $5\\notin A$ — «$5$ не принадлежит $A$».

'); + h+=makeCard('rule','Пустое множество','1.2', + '

Пустое множество $\\varnothing$ не содержит ни одного элемента (например, множество натуральных решений уравнения $x+1=0$).

' + +'

Множества равны, если состоят из одних и тех же элементов; порядок и повторы не важны: $\\{1;2;3\\}=\\{3;1;2\\}$.

'); + h+='
Интерактив 1
Принадлежит или нет?
' + +'
Определи, принадлежит ли элемент данному множеству.
' + +'
Вопрос 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+='
Интерактив 2
Сколько элементов?
' + +'
Сосчитай число элементов множества (у пустого — ноль).
' + +'
Вопрос 1 / 5Очки: 0 / 5
' + +'
' + +'
' + +'
'; + h+=secNav(null,'p2')+readBtn('p1'); + box.innerHTML=h; renderMath(box); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ var A=_distinct(_ri(3,5),1,9), inside=_pick([true,false]); var e; if(inside)e=_pick(A); else { do{e=_ri(1,9);}while(A.indexOf(e)>=0); } cur={A:A,e:e,in:A.indexOf(e)>=0}; } + function show(){ if(i>=6){ document.getElementById('p1-q').innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p1-iv1');bumpProgress('p1',30);}else if(score>=3){addXp(8,'p1-iv1');bumpProgress('p1',16);} return; } + gen(); document.getElementById('p1-i').textContent=i+1; document.getElementById('p1-q').innerHTML='$A = '+_setStr(cur.A)+'$. Верно ли, что $'+cur.e+' \\in A$?'; renderMath(document.getElementById('p1-q')); + document.getElementById('p1-fb').style.display='none'; } + function ans(v){ if(i>=6)return; var fb=document.getElementById('p1-fb'), correct=cur.in?1:0; + if(v===correct){ score++; feedback(fb,true,'✓ Верно: $'+cur.e+(cur.in?' \\in ':' \\notin ')+'A$.'); } else feedback(fb,false,'✗ Нет: $'+cur.e+(cur.in?' \\in ':' \\notin ')+'A$.'); + document.getElementById('p1-s').textContent=score; i++; setTimeout(show,1300); } + document.querySelectorAll('#p1-iv1 [data-v]').forEach(function(b){ b.addEventListener('click',function(){ ans(+b.getAttribute('data-v')); }); }); show(); + })(); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ if(_ri(1,6)===1){ cur={str:'\\varnothing', n:0}; } else { var A=_distinct(_ri(2,6),1,12); cur={str:_setStr(A), n:A.length}; } } + function show(){ if(i>=5){ document.getElementById('p1-cq').innerHTML='Готово! '+score+' / 5'; if(score>=4){addXp(15,'p1-iv2');bumpProgress('p1',30);}else if(score>=2){addXp(8,'p1-iv2');bumpProgress('p1',16);} return; } + gen(); document.getElementById('p1-ci').textContent=i+1; document.getElementById('p1-cq').innerHTML='Сколько элементов в множестве $'+cur.str+'$?'; renderMath(document.getElementById('p1-cq')); + document.getElementById('p1-ca').value=''; document.getElementById('p1-cfb').style.display='none'; } + function go(){ if(i>=5)return; var fb=document.getElementById('p1-cfb'), v=parseInt(document.getElementById('p1-ca').value,10); + if(isNaN(v)){ feedback(fb,false,'Введи число.'); return; } + if(v===cur.n){ score++; feedback(fb,true,'✓ Верно: '+cur.n+'.'); } else feedback(fb,false,'✗ Нет. Элементов: '+cur.n+'.'); + document.getElementById('p1-cs').textContent=score; i++; setTimeout(show,1200); } + document.getElementById('p1-cgo').addEventListener('click',go); + document.getElementById('p1-ca').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); show(); + })(); +} + +/* ===================== § 2. СПОСОБЫ ЗАДАНИЯ МНОЖЕСТВ ===================== */ +function buildP2(){ + var box=document.getElementById('p2-body'); var h=''; + h+=makeCard('theory','Два способа задания','2.1', + '

Перечислением — выписывают все элементы: $A=\\{2;4;6;8\\}$.

' + +'

Характеристическим свойством — указывают признак: $A=\\{x \\mid x$ — чётное, $0'); + h+='

Интерактив 1
Свойство → множество
' + +'
Выбери множество, заданное перечислением, которое соответствует описанию.
' + +'
Вопрос 1 / 5Очки: 0 / 5
' + +'
' + +'
'; + h+='
Интерактив 2
Принадлежит ли свойству?
' + +'
Принадлежит ли число множеству, заданному характеристическим свойством?
' + +'
Вопрос 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+=secNav('p1','p3')+readBtn('p2'); + box.innerHTML=h; renderMath(box); + + (function(){ + var Q=[ + {d:'натуральные числа меньше 5', set:'\\{1;2;3;4\\}', wrong:['\\{0;1;2;3;4;5\\}','\\{1;2;3;4;5\\}']}, + {d:'чётные числа от 1 до 10', set:'\\{2;4;6;8;10\\}', wrong:['\\{1;3;5;7;9\\}','\\{2;4;6;8\\}']}, + {d:'делители числа 12', set:'\\{1;2;3;4;6;12\\}', wrong:['\\{1;2;3;4;6\\}','\\{2;3;4;6;12\\}']}, + {d:'однозначные числа, кратные 3', set:'\\{3;6;9\\}', wrong:['\\{0;3;6;9\\}','\\{3;6;9;12\\}']}, + {d:'нечётные числа от 1 до 7', set:'\\{1;3;5;7\\}', wrong:['\\{1;3;5\\}','\\{2;4;6\\}']} + ]; + var order=Q.map(function(_,k){return k;}); for(var j=order.length-1;j>0;j--){var k=_ri(0,j),t=order[j];order[j]=order[k];order[k]=t;} + var i=0,score=0,cur=null; + function show(){ if(i>=5){ document.getElementById('p2-q').innerHTML='Готово! '+score+' / 5'; document.getElementById('p2-opts').innerHTML=''; if(score>=4){addXp(15,'p2-iv1');bumpProgress('p2',30);}else if(score>=2){addXp(8,'p2-iv1');bumpProgress('p2',16);} return; } + cur=Q[order[i]]; document.getElementById('p2-i').textContent=i+1; + document.getElementById('p2-q').innerHTML='Какое множество — это «'+cur.d+'»?'; + var opts=[cur.set,cur.wrong[0],cur.wrong[1]]; for(var j=opts.length-1;j>0;j--){var k=_ri(0,j),t=opts[j];opts[j]=opts[k];opts[k]=t;} + document.getElementById('p2-opts').innerHTML=opts.map(function(o){ return ''; }).join(''); + document.querySelectorAll('#p2-opts [data-o]').forEach(function(b){ b.addEventListener('click',function(){ ans(b.getAttribute('data-o')); }); }); renderMath(document.getElementById('p2-opts')); renderMath(document.getElementById('p2-q')); + document.getElementById('p2-fb').style.display='none'; } + function ans(o){ if(i>=5)return; var fb=document.getElementById('p2-fb'); + if(o===cur.set){ score++; feedback(fb,true,'✓ Верно: $'+cur.set+'$.'); } else feedback(fb,false,'✗ Нет. Правильно: $'+cur.set+'$.'); + document.getElementById('p2-s').textContent=score; i++; setTimeout(show,1400); } + show(); + })(); + + (function(){ + var PROPS=[ + {t:'чётное число',f:function(n){return n%2===0;}}, + {t:'число, кратное 3',f:function(n){return n%3===0;}}, + {t:'число, большее 5',f:function(n){return n>5;}}, + {t:'делитель числа 12',f:function(n){return 12%n===0;}}, + {t:'нечётное число',f:function(n){return n%2===1;}} + ]; + var i=0,score=0,cur=null; + function gen(){ var p=_pick(PROPS), n=_ri(1,12); cur={p:p,n:n,ok:p.f(n)}; } + function show(){ if(i>=6){ document.getElementById('p2-vq').innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p2-iv2');bumpProgress('p2',30);}else if(score>=3){addXp(8,'p2-iv2');bumpProgress('p2',16);} return; } + gen(); document.getElementById('p2-vi').textContent=i+1; document.getElementById('p2-vq').innerHTML='Принадлежит ли $'+cur.n+'$ множеству $\\{x \\mid x$ — '+cur.p.t+'$\\}$?'; renderMath(document.getElementById('p2-vq')); + document.getElementById('p2-vfb').style.display='none'; } + function ans(v){ if(i>=6)return; var fb=document.getElementById('p2-vfb'), correct=cur.ok?1:0; + if(v===correct){ score++; feedback(fb,true,'✓ Верно!'); } else feedback(fb,false,'✗ Нет. $'+cur.n+'$ '+(cur.ok?'принадлежит':'не принадлежит')+'.'); + document.getElementById('p2-vs').textContent=score; i++; setTimeout(show,1300); } + document.querySelectorAll('#p2-iv2 [data-v]').forEach(function(b){ b.addEventListener('click',function(){ ans(+b.getAttribute('data-v')); }); }); show(); + })(); +} + +/* ===================== § 3. ОПЕРАЦИИ НАД МНОЖЕСТВАМИ ===================== */ +function buildP3(){ + var box=document.getElementById('p3-body'); var h=''; + h+=makeCard('theory','Пересечение и объединение','3.1', + '

Пересечение $A\\cap B$ — множество элементов, принадлежащих обоим множествам сразу.

' + +'

Объединение $A\\cup B$ — множество элементов, принадлежащих хотя бы одному из множеств.

' + +'

$A=\\{1;2;3;4\\}$, $B=\\{3;4;5;6\\}$: $A\\cap B=\\{3;4\\}$, $A\\cup B=\\{1;2;3;4;5;6\\}$.

'); + h+='
Интерактив 1
Операции наглядно
' + +'
Нажми операцию — увидишь закрашенную область и результат для $A=\\{1;2;3;4\\}$, $B=\\{3;4;5;6\\}$.
' + +'
' + +'
'; + h+='
Интерактив 2
Сосчитай результат
' + +'
Сколько элементов в указанном множестве?
' + +'
Вопрос 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+=secNav('p2','p4')+readBtn('p3'); + box.innerHTML=h; renderMath(box); + + (function(){ + var A=[1,2,3,4], B=[3,4,5,6], fig=document.getElementById('p3-fig'), out=document.getElementById('p3-out'); + function render(op){ var regions={aOnly:'1, 2', inter:'3, 4', bOnly:'5, 6'}; + fig.innerHTML=Math6.venn({a:'A',b:'B',shade:op,regions:regions}); + if(op==='inter') out.innerHTML='
$A\\cap B = \\{3;4\\}$ — общие элементы
'; + else out.innerHTML='
$A\\cup B = \\{1;2;3;4;5;6\\}$ — все элементы
'; + renderMath(out); } + document.querySelectorAll('#p3-iv1 [data-op]').forEach(function(b){ b.addEventListener('click',function(){ document.querySelectorAll('#p3-iv1 [data-op]').forEach(function(x){x.classList.remove('primary');}); b.classList.add('primary'); render(b.getAttribute('data-op')); }); }); + render('inter'); + })(); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ var A=_distinct(_ri(3,5),1,8), B=_distinct(_ri(3,5),1,8), op=_pick(['inter','union']); var r=op==='inter'?_inter(A,B):_union(A,B); cur={A:A,B:B,op:op,n:r.length}; } + function show(){ if(i>=6){ document.getElementById('p3-q').innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p3-iv2');bumpProgress('p3',30);}else if(score>=3){addXp(8,'p3-iv2');bumpProgress('p3',16);} return; } + gen(); document.getElementById('p3-i').textContent=i+1; + document.getElementById('p3-q').innerHTML='$A='+_setStr(cur.A)+'$, $B='+_setStr(cur.B)+'$.
Сколько элементов в $A'+(cur.op==='inter'?'\\cap':'\\cup')+'B$?'; renderMath(document.getElementById('p3-q')); + document.getElementById('p3-a').value=''; document.getElementById('p3-fb').style.display='none'; } + function go(){ if(i>=6)return; var fb=document.getElementById('p3-fb'), v=parseInt(document.getElementById('p3-a').value,10); + if(isNaN(v)){ feedback(fb,false,'Введи число.'); return; } + var r=cur.op==='inter'?_inter(cur.A,cur.B):_union(cur.A,cur.B); + if(v===cur.n){ score++; feedback(fb,true,'✓ Верно: '+_setStr(r)+' — '+cur.n+' элем.'); } else feedback(fb,false,'✗ Нет. '+(cur.op==='inter'?'A\\cap B':'A\\cup B')+' = '+_setStr(r)+' ('+cur.n+').'); + document.getElementById('p3-s').textContent=score; i++; setTimeout(show,1500); } + document.getElementById('p3-go').addEventListener('click',go); + document.getElementById('p3-a').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); show(); + })(); +} + +/* ===================== § 4. КРУГИ ЭЙЛЕРА ===================== */ +function buildP4(){ + var box=document.getElementById('p4-body'); var h=''; + h+=makeCard('theory','Круги Эйлера','4.1', + '

Множества удобно изображать кругами (круги Эйлера). Пересекающиеся круги показывают общую часть. Если в $A$ — $a$ элементов, в $B$ — $b$, а в пересечении — $c$, то в объединении: $|A\\cup B| = a + b - c$ (общие посчитаны дважды — вычитаем один раз).

'); + h+='
Интерактив 1
Задача с кругами Эйлера
' + +'
Разнеси данные по кругам и ответь на вопрос.
' + +'
Задача 1 / 5Очки: 0 / 5
' + +'
' + +'
' + +'
'; + h+='
Интерактив 2
Формула объединения
' + +'
Используй $|A\\cup B| = |A| + |B| - |A\\cap B|$.
' + +'
Задача 1 / 5Очки: 0 / 5
' + +'
' + +'
' + +'
'; + h+=secNav('p3','final')+readBtn('p4'); + box.innerHTML=h; renderMath(box); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ var c=_ri(3,8), aOnly=_ri(4,12), bOnly=_ri(4,12), neither=_ri(0,6); var a=aOnly+c, b=bOnly+c, T=a+b-c+neither; + var ask=_pick(['aOnly','bOnly','neither']); cur={a:a,b:b,c:c,aOnly:aOnly,bOnly:bOnly,neither:neither,T:T,ask:ask}; } + function show(){ if(i>=5){ document.getElementById('p4-fig').innerHTML=''; document.getElementById('p4-q').innerHTML='Готово! '+score+' / 5'; if(score>=4){addXp(15,'p4-iv1');bumpProgress('p4',30);}else if(score>=2){addXp(8,'p4-iv1');bumpProgress('p4',16);} return; } + gen(); document.getElementById('p4-i').textContent=i+1; + document.getElementById('p4-fig').innerHTML=Math6.venn({a:'Матем.',b:'Физика',shade:'none',regions:{aOnly:cur.aOnly,inter:cur.c,bOnly:cur.bOnly,outside:cur.neither}}); + var qq={aOnly:'Сколько любят только математику?', bOnly:'Сколько любят только физику?', neither:'Сколько не любят ни то, ни другое?'}; + document.getElementById('p4-q').innerHTML='В классе '+cur.T+' учеников: '+cur.a+' любят математику, '+cur.b+' — физику, '+cur.c+' — оба предмета. '+qq[cur.ask]; + document.getElementById('p4-a').value=''; document.getElementById('p4-fb').style.display='none'; } + function go(){ if(i>=5)return; var fb=document.getElementById('p4-fb'), v=parseInt(document.getElementById('p4-a').value,10), ans=cur[cur.ask]; + if(isNaN(v)){ feedback(fb,false,'Введи число.'); return; } + if(v===ans){ score++; feedback(fb,true,'✓ Верно: '+ans+'.'); } else feedback(fb,false,'✗ Нет. Правильно: '+ans+' (см. круги).'); + document.getElementById('p4-s').textContent=score; i++; setTimeout(show,1600); } + document.getElementById('p4-go').addEventListener('click',go); + document.getElementById('p4-a').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); show(); + })(); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ var c=_ri(2,8), a=c+_ri(2,10), b=c+_ri(2,10); cur={a:a,b:b,c:c,ans:a+b-c}; } + function show(){ if(i>=5){ document.getElementById('p4-fq').innerHTML='Готово! '+score+' / 5'; if(score>=4){addXp(15,'p4-iv2');bumpProgress('p4',30);}else if(score>=2){addXp(8,'p4-iv2');bumpProgress('p4',16);} return; } + gen(); document.getElementById('p4-fi').textContent=i+1; document.getElementById('p4-fq').innerHTML='$|A|='+cur.a+'$, $|B|='+cur.b+'$, $|A\\cap B|='+cur.c+'$. Найди $|A\\cup B|$.'; renderMath(document.getElementById('p4-fq')); + document.getElementById('p4-fa').value=''; document.getElementById('p4-ffb').style.display='none'; } + function go(){ if(i>=5)return; var fb=document.getElementById('p4-ffb'), v=parseInt(document.getElementById('p4-fa').value,10); + if(isNaN(v)){ feedback(fb,false,'Введи число.'); return; } + if(v===cur.ans){ score++; feedback(fb,true,'✓ Верно: '+cur.a+'+'+cur.b+'−'+cur.c+'='+cur.ans+'.'); } else feedback(fb,false,'✗ Нет. '+cur.a+'+'+cur.b+'−'+cur.c+'='+cur.ans+'.'); + document.getElementById('p4-fs').textContent=score; i++; setTimeout(show,1500); } + document.getElementById('p4-fgo').addEventListener('click',go); + document.getElementById('p4-fa').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); show(); + })(); +} + +/* ===================== ФИНАЛ ГЛАВЫ — БОССЫ ===================== */ +function buildFinal(){ + var box=document.getElementById('final-body'); var h=''; + h+=makeCard('theory','Финал главы 3','★','

Пять боссов проверят множества, операции и круги Эйлера. Победи всех!

'); + h+='
Боссы
Сразись с главой 3
' + +'
' + +'
Босс 1 / 5Побеждено: 0 / 5
' + +'
' + +'
' + +'
' + +'
'; + h+=secNav('p4',null)+readBtn('final','Завершить главу 3 (+10 XP)'); + box.innerHTML=h; renderMath(box); + + (function(){ + var bosses=[ + function(){ var A=_distinct(_ri(4,6),1,9); return {name:'Счётчик', q:'Сколько элементов в множестве $'+_setStr(A)+'$?', ans:A.length}; }, + function(){ var A=_distinct(4,1,8),B=_distinct(4,1,8); return {name:'Пересечение', q:'$A='+_setStr(A)+'$, $B='+_setStr(B)+'$. Сколько элементов в $A\\cap B$?', ans:_inter(A,B).length}; }, + function(){ var A=_distinct(4,1,8),B=_distinct(4,1,8); return {name:'Объединение', q:'$A='+_setStr(A)+'$, $B='+_setStr(B)+'$. Сколько элементов в $A\\cup B$?', ans:_union(A,B).length}; }, + function(){ var c=_ri(2,7),a=c+_ri(2,9),b=c+_ri(2,9); return {name:'Эйлер', q:'$|A|='+a+'$, $|B|='+b+'$, $|A\\cap B|='+c+'$. Найди $|A\\cup B|$.', ans:a+b-c}; }, + function(){ var c=_ri(3,7),aOnly=_ri(5,12),bOnly=_ri(5,12),nei=_ri(1,5); var a=aOnly+c,b=bOnly+c,T=a+b-c+nei; return {name:'Класс', q:'В классе '+T+' человек: '+a+' играют в шахматы, '+b+' — в шашки, '+c+' — в обе игры. Сколько не играют ни в одну?', ans:nei}; } + ]; + var i=0,score=0,cur=null,done=false; + function show(){ if(i>=5){ done=true; document.getElementById('fin-name').textContent=''; document.getElementById('fin-q').innerHTML=(score>=4?'Победа! Глава 3 пройдена. ':'Бой окончен. ')+'Побеждено боссов: '+score+' / 5.'; document.getElementById('fin-hp').style.width=(score>=4?0:40)+'%'; + if(score>=4){ addXp(40,'final'); bumpProgress('final',100); if(window.confetti)try{confetti();}catch(e){} } else bumpProgress('final',60); return; } + cur=bosses[i](); document.getElementById('fin-i').textContent=i+1; document.getElementById('fin-s').textContent=score; + document.getElementById('fin-name').textContent='Босс '+(i+1)+': '+cur.name; document.getElementById('fin-hp').style.width=(100-i*20)+'%'; + document.getElementById('fin-q').innerHTML=cur.q; renderMath(document.getElementById('fin-q')); + document.getElementById('fin-a').value=''; document.getElementById('fin-fb').style.display='none'; } + function go(){ if(done||i>=5)return; var fb=document.getElementById('fin-fb'), v=parseInt(document.getElementById('fin-a').value,10); + if(isNaN(v)){ feedback(fb,false,'Введи число.'); return; } + if(v===cur.ans){ score++; feedback(fb,true,'✓ Босс повержен! Ответ '+cur.ans+'.'); } else feedback(fb,false,'✗ Босс устоял. Верно: '+cur.ans+'.'); + document.getElementById('fin-s').textContent=score; i++; setTimeout(show,1400); } + document.getElementById('fin-go').addEventListener('click',go); + document.getElementById('fin-a').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); show(); + })(); +} + +/* ===================== ДАННЫЕ ===================== */ +var SIDEBARS = { + p1:{ title:'Шпаргалка § 1', rows:[ ['Множество','набор различных элементов'], ['$\\in$','принадлежит'], ['$\\notin$','не принадлежит'], ['$\\varnothing$','пустое множество'], ['Равенство','одни и те же элементы'] ]}, + p2:{ title:'Шпаргалка § 2', rows:[ ['Перечисление','$\\{2;4;6\\}$'], ['Свойство','$\\{x\\mid x$ чётное$\\}$'], ['Читается','«$x$ такие, что …»'] ]}, + p3:{ title:'Шпаргалка § 3', rows:[ ['$A\\cap B$','общие элементы (и в A, и в B)'], ['$A\\cup B$','все элементы (хотя бы в одном)'], ['Пример','$\\{1;2;3;4\\}\\cap\\{3;4;5\\}=\\{3;4\\}$'] ]}, + p4:{ title:'Шпаргалка § 4', rows:[ ['Круги Эйлера','наглядное изображение множеств'], ['Объединение','$|A\\cup B|=|A|+|B|-|A\\cap B|$'], ['Только A','$|A|-|A\\cap B|$'] ]}, + final:{ title:'Финал главы 3', rows:[ ['5 боссов','множества, операции, круги Эйлера'], ['Победа','4 из 5 и больше'], ['Награда','+40 XP и достижение «Глава 3 пройдена»'] ]} +}; +var TIPS = [ + { sec:'p1', html:'В множестве элементы различны и порядок не важен: $\\{1;2;3\\}=\\{3;2;1\\}$, а повтор не добавляет нового элемента.' }, + { sec:'p2', html:'Характеристическое свойство $\\{x\\mid \\ldots\\}$ читается «множество всех $x$ таких, что …». Проверь признак для каждого числа.' }, + { sec:'p3', html:'Пересечение — «И» (элемент в обоих). Объединение — «ИЛИ» (хотя бы в одном). При объединении общие элементы пишут один раз.' }, + { sec:'p4', html:'Начинай с пересечения (центр). «Только A» = всё A минус пересечение. Не забывай тех, кто вне обоих кругов.' } +]; +var GLOSSARY = [ + { term:'множество', def:'Набор различных объектов (элементов), объединённых признаком.', sec:'p1', aliases:['множество','множества','множеств','множестве','множеству'] }, + { term:'элемент', def:'Объект, входящий в множество. $a\\in A$ — $a$ принадлежит $A$.', sec:'p1', aliases:['элемент','элемента','элементы','элементов'] }, + { term:'пустое множество', def:'Множество без элементов, обозначается $\\varnothing$.', sec:'p1', aliases:['пустое множество','пустого множества','пустым множеством'] }, + { term:'пересечение', def:'$A\\cap B$ — элементы, принадлежащие обоим множествам.', sec:'p3', aliases:['пересечение','пересечения','пересечении'] }, + { term:'объединение', def:'$A\\cup B$ — элементы, принадлежащие хотя бы одному множеству.', sec:'p3', aliases:['объединение','объединения','объединении'] }, + { term:'круги Эйлера', def:'Изображение множеств кругами; пересечение — общая область.', sec:'p4', aliases:['круги эйлера','кругов эйлера','кругами эйлера','круги Эйлера'] } +]; +var BUILDERS = { p1:buildP1, p2:buildP2, p3:buildP3, p4:buildP4, final:buildFinal }; +Object.assign(window.M6, { sidebars:SIDEBARS, tips:TIPS, glossary:GLOSSARY, builders:BUILDERS });