diff --git a/frontend/textbooks/algebra_11_ch1.html b/frontend/textbooks/algebra_11_ch1.html index 0328aa0..d9486a5 100644 --- a/frontend/textbooks/algebra_11_ch1.html +++ b/frontend/textbooks/algebra_11_ch1.html @@ -129,6 +129,26 @@ a{color:inherit;text-decoration:none} .spoiler[open] summary::before{content:'\2212'} .spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6} +.dnd-pool{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;min-height:54px;transition:border-color .18s,background .18s} +.dnd-pool.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid} +.dnd-pool.col{flex-direction:column;align-items:stretch} +.dnd-pool.col .dnd-chip{width:auto} +.dnd-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--card);border:1.5px solid var(--border);border-radius:10px;cursor:grab;user-select:none;font-size:.92rem;line-height:1.4;transition:transform .12s,box-shadow .12s,border-color .12s;touch-action:none;max-width:100%} +.dnd-chip:hover{transform:translateY(-1px);border-color:var(--sec-acc,var(--pri));box-shadow:var(--sh)} +.dnd-chip:active{cursor:grabbing} +.dnd-chip.armed{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));box-shadow:0 0 0 3px rgba(217,119,6,.22);transform:translateY(-1px)} +.dnd-chip.dragging{opacity:.28} +.dnd-chip.placed{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))} +.dnd-chip .dnd-x{padding:0 5px;color:var(--muted);font-weight:700;font-size:1.05rem;border-radius:4px;cursor:pointer} +.dnd-chip .dnd-x:hover{color:var(--bad,var(--fail));background:var(--fail-bg)} +.drop-box{background:var(--card);border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:90px;transition:border-color .15s,background .15s} +.drop-box:hover{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))} +.drop-box h5{font-family:'Unbounded',sans-serif;font-size:.78rem;color:var(--sec-acc-d,var(--pri2));margin-bottom:8px;text-transform:uppercase;letter-spacing:.05em} +.drop-box.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid;transform:scale(1.015)} +.drop-items{display:flex;flex-wrap:wrap;gap:6px;min-height:32px} +.dnd-hint{font-size:.78rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:6px} +.dnd-hint svg{width:14px;height:14px;flex-shrink:0} + .col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto} .sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)} .sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)} @@ -444,6 +464,19 @@ function makeCard(kind, title, num, body){ const labels = {repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно'}; return '
'+ICONS[kind]+'
'+(labels[kind]||'')+(title&&title!==labels[kind]?' \xb7 '+title:'')+'
'+(num?'
'+num+'
':'')+'
'+body+'
'; } +function setupSorter(cfg){ + const placed = {}; const pool = document.getElementById(cfg.poolId); const scope = document.querySelector(cfg.scopeSelector); + if(!pool||!scope) return {placed,render:()=>{},reset:()=>{}}; + pool.classList.add('dnd-pool'); if(cfg.columnLayout) pool.classList.add('col'); + let armed = null; + function buildChip(it,isPlaced){ const e=document.createElement('div'); e.className='dnd-chip'+(isPlaced?' placed':''); e.dataset.id=it.id; e.innerHTML=''+it.html+'\xd7'; attach(e,it.id); return e; } + function attach(elm,itId){ let ghost=null,dragging=false,sx=0,sy=0; elm.addEventListener('pointerdown',ev=>{ if(ev.button!==undefined&&ev.button!==0) return; + ev.preventDefault(); if(ev.target.classList&&ev.target.classList.contains('dnd-x')){ ev.stopPropagation(); if(placed[itId]){delete placed[itId];render();}else if(armed===itId){armed=null;render();} return; } sx=ev.clientX;sy=ev.clientY; const r=elm.getBoundingClientRect(); const ox=ev.clientX-r.left,oy=ev.clientY-r.top; try{elm.setPointerCapture(ev.pointerId);}catch(e){} function onMove(e){ const dx=e.clientX-sx,dy=e.clientY-sy; if(!dragging&&Math.hypot(dx,dy)>8){ dragging=true; ghost=elm.cloneNode(true); ghost.classList.remove('armed'); ghost.style.cssText='position:fixed;z-index:9999;pointer-events:none;opacity:.9;transform:rotate(-2.5deg);box-shadow:0 14px 36px rgba(0,0,0,.32);width:'+r.width+'px;left:'+(e.clientX-ox)+'px;top:'+(e.clientY-oy)+'px'; document.body.appendChild(ghost); elm.classList.add('dragging'); } if(dragging&&ghost){ ghost.style.left=(e.clientX-ox)+'px';ghost.style.top=(e.clientY-oy)+'px'; const under=document.elementsFromPoint(e.clientX,e.clientY); scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); const tgt=under.find(n=>n.classList&&(n.classList.contains('drop-box')||n.classList.contains('dnd-pool'))); if(tgt)tgt.classList.add('over'); } } function onUp(e){ elm.removeEventListener('pointermove',onMove);elm.removeEventListener('pointerup',onUp);elm.removeEventListener('pointercancel',onUp);elm.classList.remove('dragging'); if(ghost){ghost.remove();ghost=null;} scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); if(dragging){ const under=document.elementsFromPoint(e.clientX,e.clientY); const box=under.find(n=>n.classList&&n.classList.contains('drop-box')); const pl=under.find(n=>n.classList&&n.classList.contains('dnd-pool')); if(box){const di=box.querySelector('[data-cat]');if(di){placed[itId]=di.dataset.cat;armed=null;render();return;}}else if(pl){delete placed[itId];armed=null;render();return;} }else{ if(placed[itId]){delete placed[itId];armed=null;render();}else{armed=(armed===itId)?null:itId;render();} } dragging=false; } elm.addEventListener('pointermove',onMove);elm.addEventListener('pointerup',onUp);elm.addEventListener('pointercancel',onUp); }); } + function attachBoxTaps(){ scope.querySelectorAll('.drop-box').forEach(box=>{ box.addEventListener('click',ev=>{ if(!armed)return; if(ev.target.closest('.dnd-chip'))return; const di=box.querySelector('[data-cat]'); if(di){placed[armed]=di.dataset.cat;armed=null;render();} }); }); } + function render(){ pool.innerHTML=''; cfg.items.forEach(it=>{if(placed[it.id])return;const c=buildChip(it,false);if(armed===it.id)c.classList.add('armed');pool.appendChild(c);}); cfg.cats.forEach(cat=>{const box=scope.querySelector('.drop-items[data-cat="'+cat+'"]');if(!box)return;box.innerHTML='';cfg.items.forEach(it=>{if(placed[it.id]!==cat)return;box.appendChild(buildChip(it,true));});}); if(window.renderMathInElement)try{renderMath(scope);}catch(_){} } + attachBoxTaps(); render(); + return {placed,render,reset(){ for(const k in placed)delete placed[k];armed=null;render(); }}; +} /* === SVG-хелперы (axes2D, plotFunc, pointWithDrop, asymptote, snapToValue, геом.) === */ @@ -598,15 +631,292 @@ function wireReadBtn(paraId){ function buildP1(){ const box = document.getElementById('p1-body'); let html = ''; - html += makeCard('theory', 'В разработке', '1.0', ` -

Содержание параграфа Степень с рациональным показателем будет добавлено в Phase 1+.

-

Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.

-

Ключевая формула: $a^{m/n} = \sqrt[n]{a^m}$

- `); - html += secNavFor('p1'); + + html += makeCard('theory', 'Определение степени с дробным показателем', '1.1', ` +

Пусть $a > 0$, $m$ — целое число, $n$ — натуральное число, $n > 1$. Тогда:

+ \\[ a^{m/n} = \\sqrt[n]{a^m} \\] +

В частности, при $m = 1$ получаем $a^{1/n} = \\sqrt[n]{a}$ — это корень $n$-й степени из $a$.

+

Пример. $8^{2/3} = \\sqrt[3]{8^2} = \\sqrt[3]{64} = 4.$

+

Отрицательный показатель: $a^{-m/n} = \\dfrac{1}{a^{m/n}} = \\dfrac{1}{\\sqrt[n]{a^m}}.$

+
Почему $a > 0$?
+ Если $a < 0$, то $\\sqrt[n]{a}$ при чётном $n$ не определён в $\\mathbb{R}$. Кроме того, одно и то же рациональное число может быть записано разными дробями ($\\tfrac{1}{2} = \\tfrac{2}{4}$), и для отрицательной базы значения корней $\\sqrt{a}$ и $\\sqrt[4]{a^2}$ не совпадают. Поэтому для $a < 0$ дробный показатель не определяют.
Для $a = 0$ полагают $0^{m/n} = 0$ при положительном показателе $m/n > 0$. +
`); + + html += makeCard('rule', 'Свойства степени с рациональным показателем', '1.2', ` +

Для $a > 0$, $b > 0$ и любых рациональных $p$, $q$ выполнены те же свойства, что и для целых показателей:

+ \\[ a^p \\cdot a^q = a^{p+q}, \\qquad \\dfrac{a^p}{a^q} = a^{p-q}, \\qquad (a^p)^q = a^{pq} \\] + \\[ (ab)^p = a^p \\cdot b^p, \\qquad \\left(\\dfrac{a}{b}\\right)^p = \\dfrac{a^p}{b^p} \\] +

Это те же самые свойства, что и для натурального показателя — просто теперь $p$ и $q$ могут быть любыми рациональными числами (целыми, дробными, отрицательными).

+

Пример. $3^{1/2} \\cdot 3^{3/2} = 3^{1/2 + 3/2} = 3^2 = 9.$

+

Пример. $\\left(4^{3/4}\\right)^{4/3} = 4^{(3/4) \\cdot (4/3)} = 4^1 = 4.$

`); + + html += makeCard('example', 'Степень с иррациональным и действительным показателем', '1.3', ` +

А что такое $2^{\\sqrt{3}}$? Ведь $\\sqrt{3} \\approx 1{,}732...$ — иррациональное число.

+

Идея: возьмём последовательность рациональных приближений к $\\sqrt{3}$:

+ \\[ r_1 = 1{,}7,\\ \\ r_2 = 1{,}73,\\ \\ r_3 = 1{,}732,\\ \\ r_4 = 1{,}7320,\\ \\ldots \\to \\sqrt{3} \\] +

Каждое $2^{r_n}$ — уже определённая степень с рациональным показателем. Эта последовательность сходится:

+ \\[ 2^{\\sqrt{3}} = \\lim_{n \\to \\infty} 2^{r_n} \\approx 3{,}3219... \\] +

Так определяется степень с любым действительным показателем $a^\\alpha$ при $a > 0$ и $\\alpha \\in \\mathbb{R}$.

+

Все свойства степени сохраняются и для действительных показателей — ими можно пользоваться так же, как привычными свойствами для целых степеней.

`); + + /* INTERACTIVE 1 — конструктор a^(m/n) */ + html += `
+
ИНТЕРАКТИВ 1
Конструктор степени $a^{m/n}$
+
Подвигай ползунки — увидишь, как вычисляется $a^{m/n} = \\sqrt[n]{a^m}$ при разных значениях.
+
+ + + +
+
+
+
`; + + /* INTERACTIVE 2 — калькулятор свойств */ + html += `
+
ИНТЕРАКТИВ 2
Калькулятор свойств степени
+
Введи базу $a$ и две дроби $p = m_1/n_1$, $q = m_2/n_2$. Нажми кнопку свойства — увидишь пошаговое применение.
+
+ $a$ = + + $p$ = + + / + + $q$ = + + / + +
+
+ + + +
+
+
+
`; + + /* INTERACTIVE 3 — DnD: корень или степень */ + html += `
+
ИНТЕРАКТИВ 3
Радикал или степень?
+
Перетащи каждую запись в ящик «через корень» или «через степень».
+
8 записей — 2 ящика
+
+
+
Запись через корень
+
Запись через степень
+
+
+
+
`; + + /* INTERACTIVE 4 — тренажёр упрощения */ + html += `
+
ИНТЕРАКТИВ 4
Тренажёр: упрости степень
+
Вычисли значение и введи число (целое или десятичное до 2 знаков, допуск $\\pm 0{,}05$).
+
Задача 1 / 6Очки: 0 / 6
+
+
+ ответ = + + + +
+
+
`; + + html += secNav(null, 'p2'); html += readButton('p1'); + box.innerHTML = html; renderMath(box); + + /* IV1 — конструктор a^(m/n) */ + (function(){ + const sa = document.getElementById('p1-iv1-sa'); + const sm = document.getElementById('p1-iv1-sm'); + const sn = document.getElementById('p1-iv1-sn'); + const aL = document.getElementById('p1-iv1-a'); + const mL = document.getElementById('p1-iv1-m'); + const nL = document.getElementById('p1-iv1-n'); + const fEl = document.getElementById('p1-iv1-formula'); + const vEl = document.getElementById('p1-iv1-val'); + const seen = new Set(); + function draw(){ + const a = +sa.value, m = +sm.value, n = +sn.value; + aL.textContent = (Number.isInteger(a) ? a : a.toFixed(1)); + mL.textContent = m; + nL.textContent = n; + let formula = ''; + if(m === 0){ + formula = '$a^{0} = 1$ при $a \\ne 0$. Здесь: $' + a + '^{0} = 1$.'; + vEl.innerHTML = 'Значение: $\\mathbf{1}$'; + } else if(m > 0){ + const aPowM = Math.pow(a, m); + const val = Math.pow(a, m/n); + formula = '$' + a + '^{' + m + '/' + n + '} \\;=\\; \\sqrt[' + n + ']{' + a + '^{' + m + '}} \\;=\\; \\sqrt[' + n + ']{' + (+aPowM.toFixed(4)) + '} \\;\\approx\\; ' + (+val.toFixed(4)) + '$'; + vEl.innerHTML = 'Значение: $\\mathbf{' + (+val.toFixed(4)) + '}$'; + } else { + const am = Math.abs(m); + const aPowM = Math.pow(a, am); + const val = 1 / Math.pow(a, am/n); + formula = '$' + a + '^{' + m + '/' + n + '} \\;=\\; \\dfrac{1}{' + a + '^{' + am + '/' + n + '}} \\;=\\; \\dfrac{1}{\\sqrt[' + n + ']{' + (+aPowM.toFixed(4)) + '}} \\;\\approx\\; ' + (+val.toFixed(4)) + '$'; + vEl.innerHTML = 'Значение: $\\mathbf{' + (+val.toFixed(4)) + '}$'; + } + fEl.innerHTML = formula; + renderMath(fEl); renderMath(vEl); + const sig = a + ':' + m + ':' + n; + seen.add(sig); + if(seen.size >= 6 && !seen.has('_done')){ addXp(10,'p1-iv1'); bumpProgress('p1', 15); seen.add('_done'); } + } + sa.addEventListener('input', draw); + sm.addEventListener('input', draw); + sn.addEventListener('input', draw); + draw(); + })(); + + /* IV2 — калькулятор свойств */ + (function(){ + const aI = document.getElementById('p1-iv2-a'); + const pm = document.getElementById('p1-iv2-pm'); + const pn = document.getElementById('p1-iv2-pn'); + const qm = document.getElementById('p1-iv2-qm'); + const qn = document.getElementById('p1-iv2-qn'); + const out = document.getElementById('p1-iv2-out'); + const fb = document.getElementById('p1-iv2-fb'); + const bMul = document.getElementById('p1-iv2-mul'); + const bDiv = document.getElementById('p1-iv2-div'); + const bPow = document.getElementById('p1-iv2-pow'); + const used = new Set(); + + function simplify(num, den){ + if(den < 0){ num = -num; den = -den; } + const g = gcd(Math.abs(num), Math.abs(den)) || 1; + return [num/g, den/g]; + } + function fracStr(num, den){ + if(den === 1) return String(num); + if(num === 0) return '0'; + return '\\dfrac{'+num+'}{'+den+'}'; + } + function getVals(){ + const a = +aI.value; + const pM = parseInt(pm.value,10), pN = parseInt(pn.value,10); + const qM = parseInt(qm.value,10), qN = parseInt(qn.value,10); + if(!isFinite(a) || a <= 0){ feedback(fb,false,'✗ База $a$ должна быть положительной.'); return null; } + if(isNaN(pM)||isNaN(pN)||isNaN(qM)||isNaN(qN)){ feedback(fb,false,'✗ Введи все числа.'); return null; } + if(pN <= 0 || qN <= 0){ feedback(fb,false,'✗ Знаменатели дробей должны быть положительными.'); return null; } + return { a, pM, pN, qM, qN }; + } + function doOp(op){ + const v = getVals(); if(!v) return; + const { a, pM, pN, qM, qN } = v; + const p = pM/pN, q = qM/qN; + let sumNum, sumDen, label, exprBefore, exprAfter, valNum; + if(op === 'mul'){ + sumNum = pM*qN + qM*pN; sumDen = pN*qN; + label = '$a^p \\cdot a^q = a^{p+q}$'; + exprBefore = a+'^{'+fracStr(pM,pN)+'} \\cdot '+a+'^{'+fracStr(qM,qN)+'}'; + valNum = Math.pow(a, p+q); + } else if(op === 'div'){ + sumNum = pM*qN - qM*pN; sumDen = pN*qN; + label = '$\\dfrac{a^p}{a^q} = a^{p-q}$'; + exprBefore = '\\dfrac{'+a+'^{'+fracStr(pM,pN)+'}}{'+a+'^{'+fracStr(qM,qN)+'}}'; + valNum = Math.pow(a, p-q); + } else { + sumNum = pM*qM; sumDen = pN*qN; + label = '$(a^p)^q = a^{pq}$'; + exprBefore = '\\left('+a+'^{'+fracStr(pM,pN)+'}\\right)^{'+fracStr(qM,qN)+'}'; + valNum = Math.pow(a, p*q); + } + const [sn, sd] = simplify(sumNum, sumDen); + const expSimpl = fracStr(sn, sd); + out.innerHTML = '
Свойство: '+label+'
' + + '$'+exprBefore+' \\;=\\; '+a+'^{'+expSimpl+'} \\;\\approx\\; '+ (+valNum.toFixed(4)) +'$'; + renderMath(out); + feedback(fb, true, '✓ Применено свойство.'); + used.add(op); + if(used.size === 3 && !used.has('_done')){ addXp(10,'p1-iv2'); bumpProgress('p1', 15); used.add('_done'); } + } + bMul.addEventListener('click', ()=>doOp('mul')); + bDiv.addEventListener('click', ()=>doOp('div')); + bPow.addEventListener('click', ()=>doOp('pow')); + })(); + + /* IV3 — DnD радикал / степень */ + (function(){ + const items = [ + { id:'r1', cat:'rad', html:'$\\sqrt[3]{a^2}$' }, + { id:'r2', cat:'pow', html:'$a^{1/2}$' }, + { id:'r3', cat:'rad', html:'$\\sqrt{a^3}$' }, + { id:'r4', cat:'pow', html:'$a^{-1/4}$' }, + { id:'r5', cat:'rad', html:'$\\sqrt[5]{a}$' }, + { id:'r6', cat:'pow', html:'$a^{3/7}$' }, + { id:'r7', cat:'rad', html:'$\\dfrac{1}{\\sqrt[4]{a}}$' }, + { id:'r8', cat:'pow', html:'$a^{0{,}5}$' }, + ]; + const sorter = setupSorter({ + poolId:'p1-iv3-pool', + scopeSelector:'#p1-iv3', + items: items, + cats:['rad','pow'], + columnLayout:false, + }); + document.getElementById('p1-iv3-check').addEventListener('click', ()=>{ + const fb = document.getElementById('p1-iv3-fb'); + const placedCount = items.filter(it => sorter.placed[it.id]).length; + const correct = items.filter(it => sorter.placed[it.id] === it.cat).length; + if(placedCount < items.length){ feedback(fb, false, '✗ Размести все 8 записей.'); return; } + if(correct === items.length){ feedback(fb, true, '✓ Все 8 на месте! +15 XP'); addXp(15,'p1-iv3'); bumpProgress('p1', 25); } + else feedback(fb, false, '✗ Правильно ' + correct + ' из 8. Попробуй ещё.'); + }); + document.getElementById('p1-iv3-reset').addEventListener('click', ()=>{ sorter.reset(); document.getElementById('p1-iv3-fb').style.display = 'none'; }); + })(); + + /* IV4 — тренажёр упрощения */ + (function(){ + const Q = [ + { q:'$8^{2/3} = \\;?$', ans:4, hint:'$\\sqrt[3]{8^2} = \\sqrt[3]{64} = 4$' }, + { q:'$16^{3/4} = \\;?$', ans:8, hint:'$\\sqrt[4]{16^3} = \\sqrt[4]{4096} = 8$' }, + { q:'$27^{-1/3} = \\;?$', ans:1/3, hint:'$\\dfrac{1}{\\sqrt[3]{27}} = \\dfrac{1}{3} \\approx 0{,}33$' }, + { q:'$32^{0{,}4} = \\;?$', ans:4, hint:'$0{,}4 = \\tfrac{2}{5}$, $\\sqrt[5]{32^2} = \\sqrt[5]{1024} = 4$' }, + { q:'$\\left(\\dfrac{1}{4}\\right)^{-1/2} = \\;?$', ans:2, hint:'$\\left(\\tfrac{1}{4}\\right)^{-1/2} = 4^{1/2} = \\sqrt{4} = 2$' }, + { q:'$9^{1{,}5} = \\;?$', ans:27, hint:'$9^{3/2} = \\sqrt{9^3} = \\sqrt{729} = 27$' }, + ]; + let i = 0, score = 0; + function show(){ + if(i >= Q.length){ + document.getElementById('p1-iv4-q').innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length; + if(score === Q.length){ addXp(15,'p1-iv4'); bumpProgress('p1', 25); } + else if(score >= 4){ addXp(8,'p1-iv4'); bumpProgress('p1', 15); } + return; + } + document.getElementById('p1-iv4-i').textContent = (i+1); + document.getElementById('p1-iv4-s').textContent = score; + document.getElementById('p1-iv4-q').innerHTML = Q[i].q; + document.getElementById('p1-iv4-ans').value = ''; + renderMath(document.getElementById('p1-iv4-q')); + document.getElementById('p1-iv4-fb').style.display = 'none'; + } + function go(){ + if(i >= Q.length) return; + const fb = document.getElementById('p1-iv4-fb'); + const raw = document.getElementById('p1-iv4-ans').value.replace(',', '.'); + const ans = parseFloat(raw); + if(isNaN(ans)){ feedback(fb, false, '✗ Введи число.'); return; } + if(Math.abs(ans - Q[i].ans) < 0.05){ score++; feedback(fb, true, '✓ Верно! '+Q[i].hint+'. Дальше ▶'); } + else feedback(fb, false, '✗ Неверно. Ответ $\\approx '+(+Q[i].ans.toFixed(2))+'$ ('+Q[i].hint+'). Дальше ▶'); + document.getElementById('p1-iv4-s').textContent = score; + i++; + setTimeout(show, 1300); + } + document.getElementById('p1-iv4-go').addEventListener('click', go); + document.getElementById('p1-iv4-ans').addEventListener('keydown', e=>{ if(e.key === 'Enter') go(); }); + document.getElementById('p1-iv4-start').addEventListener('click', ()=>{ i=0; score=0; show(); }); + show(); + })(); + wireReadBtn('p1'); }