From 9ed89ab0c88fb0bb2ba97380cd29c49b56076468 Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Wed, 3 Jun 2026 09:33:03 +0300 Subject: [PATCH] =?UTF-8?q?feat(math5):=20=D0=93=D0=BB=D0=B0=D0=B2=D0=B0?= =?UTF-8?q?=201=20=C2=A77=E2=80=93=C2=A79=20=E2=80=94=20=D0=BE=D0=BA=D1=80?= =?UTF-8?q?=D1=83=D0=B3=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5,=20=D1=81=D0=BB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5/=D0=B2=D1=8B=D1=87=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D0=B8=D0=B5,=20=D1=83=D0=BC=D0=BD=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5/=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §7 Округление (правило + округление на координатном луче до десятков + до сотен/тысяч). §8 Сложение/вычитание (столбик, свойства + тренажёр + «найди неизвестное» как подготовка к уравнениям). §9 Умножение/деление (прямоугольник из точек a×b как визуал + тренажёр ×/÷). Шпаргалки/типсы §7–9. Тесты math5: 8/8. Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/tests/math5-page.test.js | 6 + frontend/textbooks/math_5_ch1.html | 228 ++++++++++++++++++++++++++++- 2 files changed, 233 insertions(+), 1 deletion(-) diff --git a/backend/tests/math5-page.test.js b/backend/tests/math5-page.test.js index 2c4d696..b166d9e 100644 --- a/backend/tests/math5-page.test.js +++ b/backend/tests/math5-page.test.js @@ -100,6 +100,12 @@ test('ch1: §1 «как решать задачу», §2 «разрядная т assert.ok(doc.querySelector('#p5-fig svg rect'), '§5: линейка'); win.goTo('p6'); await wait(80); assert.ok(doc.querySelector('#p6-fig svg'), '§6: координатный луч'); + win.goTo('p7'); await wait(80); + assert.ok(doc.querySelector('#p7-fig svg'), '§7: округление на луче'); + win.goTo('p8'); await wait(80); + assert.ok(doc.querySelector('#p8-iv2 #p8-xa'), '§8: «найди неизвестное»'); + win.goTo('p9'); await wait(80); + assert.ok(doc.querySelector('#p9-fig svg circle'), '§9: прямоугольник из точек'); win.goTo('final'); await wait(80); assert.ok(doc.querySelector('#fin-go'), 'финал: арена боссов'); win.bumpProgress('final', 100); await wait(20); diff --git a/frontend/textbooks/math_5_ch1.html b/frontend/textbooks/math_5_ch1.html index d4e0439..cf34185 100644 --- a/frontend/textbooks/math_5_ch1.html +++ b/frontend/textbooks/math_5_ch1.html @@ -621,6 +621,217 @@ function buildP6(){ })(); } +/* ===================== § 7. ОКРУГЛЕНИЕ НАТУРАЛЬНЫХ ЧИСЕЛ ===================== */ +function buildP7(){ + var box=document.getElementById('p7-body'); var h=''; + h+=makeCard('oral','Где это в жизни','7.0', + '

Точные числа в новостях встречаются редко: говорят «около $8$ миллиардов человек», «примерно $300$ км до моря», «в зале почти $1000$ зрителей». Это округлённые числа — так их проще воспринимать и запоминать.

'); + h+=makeCard('rule','Правило округления','7.1', + '

Чтобы округлить число до некоторого разряда, смотрят на следующую (младшую) цифру:

' + +'' + +'

Все цифры младших разрядов заменяют нулями. Знак приближённого равенства — $\\approx$.

'); + h+=makeCard('example','Примеры','7.2', + '

$47\\approx 50$ (до десятков).   $432\\approx 400$ (до сотен).   $6\\,500\\approx 7\\,000$ (до тысяч).

'); + h+=makeCard('example','Разбор по шагам','7.3', + '

Округлим $3\\,472$ до сотен.

' + +'
    ' + +'
  1. Разряд сотен — цифра $4$ (в $3\\,\\underline{4}72$).
  2. ' + +'
  3. Следующая цифра — десятки $7$. Так как $7\\ge 5$, сотни увеличиваем: $4\\to 5$.
  4. ' + +'
  5. Младшие разряды — нули: $3\\,500$.
  6. ' + +'
  7. Ответ: $3\\,472\\approx 3\\,500$.
  8. ' + +'
'); + h+=makeCard('theory','А знаешь ли ты?','7.4', + '

Округление помогает быстро прикинуть ответ и проверить себя. Если в магазине $19$ товаров примерно по $50$ копеек, то в уме: $20\\cdot 50=1000$ к. $=10$ руб. — значит, итог должен быть около $10$ рублей.

'); + h+='
Интерактив 1
Округли до десятков
' + +'
Точка показывает число на луче. Округли его до ближайшего десятка.
' + +'
Вопрос 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+='
Интерактив 2
Округли до разряда
' + +'
Округли большое число до указанного разряда.
' + +'
Вопрос 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+=secNav('p6','p8')+readBtn('p7'); + box.innerHTML=h; renderMath(box); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ cur=_ri(11,89); } + function show(){ if(i>=6){ document.getElementById('p7-fig').innerHTML=''; var fb0=document.getElementById('p7-fb'); fb0.className='feedback'; fb0.style.display='block'; fb0.innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p7-iv1');bumpProgress('p7',30);}else if(score>=3){addXp(8,'p7-iv1');bumpProgress('p7',16);} return; } + gen(); document.getElementById('p7-i').textContent=i+1; + document.getElementById('p7-fig').innerHTML=Math6.numberLine({min:0,max:100,minor:10,major:10,width:560,marks:[{v:cur,label:''+cur,color:'#4f46e5'}]}); + document.getElementById('p7-a').value=''; document.getElementById('p7-fb').style.display='none'; } + function go(){ if(i>=6)return; var fb=document.getElementById('p7-fb'), a=parseInt(document.getElementById('p7-a').value,10), correct=Math.round(cur/10)*10; + if(isNaN(a)){ feedback(fb,false,'Введи число.'); return; } + if(a===correct){ score++; feedback(fb,true,'✓ Верно! $'+cur+'\\approx '+correct+'$.'); renderMath(fb); } else { feedback(fb,false,'✗ Нет. $'+cur+'\\approx '+correct+'$.'); renderMath(fb); } + document.getElementById('p7-s').textContent=score; i++; setTimeout(show,1200); } + document.getElementById('p7-go').addEventListener('click',go); + document.getElementById('p7-a').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); + show(); + })(); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ var t=_ri(0,1); if(t===0){ var n=_ri(1050,8950); cur={n:n,pl:'сотен',ans:Math.round(n/100)*100}; } else { var m=_ri(11500,98500); cur={n:m,pl:'тысяч',ans:Math.round(m/1000)*1000}; } } + function show(){ if(i>=6){ document.getElementById('p7-rq').innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p7-iv2');bumpProgress('p7',30);}else if(score>=3){addXp(8,'p7-iv2');bumpProgress('p7',16);} return; } + gen(); document.getElementById('p7-ri').textContent=i+1; + document.getElementById('p7-rq').innerHTML='Округли $'+_grp(cur.n)+'$ до '+cur.pl+'.'; renderMath(document.getElementById('p7-rq')); + document.getElementById('p7-ra').value=''; document.getElementById('p7-rfb').style.display='none'; } + function go(){ if(i>=6)return; var fb=document.getElementById('p7-rfb'), a=parseInt(document.getElementById('p7-ra').value,10); + if(isNaN(a)){ feedback(fb,false,'Введи число.'); return; } + if(a===cur.ans){ score++; feedback(fb,true,'✓ Верно! Ответ '+cur.ans+'.'); } else feedback(fb,false,'✗ Нет. Правильно: '+cur.ans+'.'); + document.getElementById('p7-rs').textContent=score; i++; setTimeout(show,1200); } + document.getElementById('p7-rgo').addEventListener('click',go); + document.getElementById('p7-ra').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); + show(); + })(); +} + +/* ===================== § 8. СЛОЖЕНИЕ И ВЫЧИТАНИЕ ===================== */ +function buildP8(){ + var box=document.getElementById('p8-body'); var h=''; + h+=makeCard('oral','Где это в жизни','8.0', + '

Сложение и вычитание — самые частые действия: сложить стоимость покупок, посчитать сдачу, узнать, на сколько один город больше другого, сколько осталось денег после трат.

'); + h+=makeCard('rule','Сложение и вычитание «в столбик»','8.1', + '

Числа записывают разряд под разрядом (единицы под единицами). Складывают справа налево; если в разряде получилось $10$ или больше — переносят единицу в следующий разряд.

' + +'

При вычитании, если цифр не хватает, занимают единицу у старшего разряда.

'); + h+=makeCard('rule','Полезные свойства','8.2', + '

Переместительное: $a+b=b+a$.   Сочетательное: $(a+b)+c=a+(b+c)$.

' + +'

Ими удобно пользоваться для быстрого счёта: $37+99=37+100-1=136$.

'); + h+=makeCard('example','Разбор по шагам','8.3', + '

Вычислим $3\\,472+1\\,859$.

' + +'
    ' + +'
  1. Единицы: $2+9=11$ — пишем $1$, переносим $1$.
  2. ' + +'
  3. Десятки: $7+5+1=13$ — пишем $3$, переносим $1$.
  4. ' + +'
  5. Сотни: $4+8+1=13$ — пишем $3$, переносим $1$.
  6. ' + +'
  7. Тысячи: $3+1+1=5$. Ответ: $5\\,331$.
  8. ' + +'
'); + h+=makeCard('theory','А знаешь ли ты?','8.4', + '

Знаки $+$ и $-$ впервые напечатал немецкий математик Иоганн Видман в $1489$ году в книге по торговым расчётам. До этого сложение писали словом «et» (по-латыни «и»).

'); + h+='
Интерактив 1
Сложение и вычитание
' + +'
Вычисли значение выражения и введи ответ.
' + +'
Пример 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+='
Интерактив 2
Найди неизвестное
' + +'
Найди число, спрятанное под квадратом. Это подготовка к уравнениям!
' + +'
Вопрос 1 / 5Очки: 0 / 5
' + +'
' + +'
' + +'
'; + h+=secNav('p7','p9')+readBtn('p8'); + box.innerHTML=h; renderMath(box); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ var a=_ri(150,4800), b=_ri(120,3900); if(_ri(0,1)===0)cur={t:'+',a:a,b:b,ans:a+b}; else { if(b>a){var x=a;a=b;b=x;} cur={t:'−',a:a,b:b,ans:a-b}; } } + function show(){ if(i>=6){ document.getElementById('p8-q').innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p8-iv1');bumpProgress('p8',30);}else if(score>=3){addXp(8,'p8-iv1');bumpProgress('p8',16);} return; } + gen(); document.getElementById('p8-i').textContent=i+1; + document.getElementById('p8-q').innerHTML='$'+_grp(cur.a)+' '+cur.t+' '+_grp(cur.b)+'$'; renderMath(document.getElementById('p8-q')); + document.getElementById('p8-a').value=''; document.getElementById('p8-fb').style.display='none'; } + function go(){ if(i>=6)return; var fb=document.getElementById('p8-fb'), a=parseInt(document.getElementById('p8-a').value,10); + if(isNaN(a)){ feedback(fb,false,'Введи число.'); return; } + if(a===cur.ans){ score++; feedback(fb,true,'✓ Верно! Ответ '+cur.ans+'.'); } else feedback(fb,false,'✗ Нет. Правильно: '+cur.ans+'.'); + document.getElementById('p8-s').textContent=score; i++; setTimeout(show,1200); } + document.getElementById('p8-go').addEventListener('click',go); + document.getElementById('p8-a').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); + show(); + })(); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ var a=_ri(12,80), x=_ri(13,90); var t=_ri(0,2); + if(t===0)cur={q:'\\square + '+a+' = '+(a+x),ans:x}; + else if(t===1)cur={q:a+' + \\square = '+(a+x),ans:x}; + else cur={q:'\\square - '+a+' = '+x,ans:a+x}; } + function show(){ if(i>=5){ document.getElementById('p8-xq').innerHTML='Готово! '+score+' / 5'; if(score>=4){addXp(15,'p8-iv2');bumpProgress('p8',30);}else if(score>=2){addXp(8,'p8-iv2');bumpProgress('p8',16);} return; } + gen(); document.getElementById('p8-xi').textContent=i+1; + document.getElementById('p8-xq').innerHTML='$'+cur.q+'$'; renderMath(document.getElementById('p8-xq')); + document.getElementById('p8-xa').value=''; document.getElementById('p8-xfb').style.display='none'; } + function go(){ if(i>=5)return; var fb=document.getElementById('p8-xfb'), a=parseInt(document.getElementById('p8-xa').value,10); + if(isNaN(a)){ feedback(fb,false,'Введи число.'); return; } + if(a===cur.ans){ score++; feedback(fb,true,'✓ Верно! Под квадратом '+cur.ans+'.'); } else feedback(fb,false,'✗ Нет. Правильно: '+cur.ans+'.'); + document.getElementById('p8-xs').textContent=score; i++; setTimeout(show,1200); } + document.getElementById('p8-xgo').addEventListener('click',go); + document.getElementById('p8-xa').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); + show(); + })(); +} + +/* ===================== § 9. УМНОЖЕНИЕ И ДЕЛЕНИЕ ===================== */ +function buildP9(){ + var box=document.getElementById('p9-body'); var h=''; + h+=makeCard('oral','Где это в жизни','9.0', + '

Умножение — это быстрое сложение одинаковых слагаемых: $6$ пачек по $8$ карандашей — это $6\\cdot 8=48$. Деление — обратное действие: $48$ карандашей разложить в $6$ пачек поровну — по $8$.

'); + h+=makeCard('rule','Умножение и деление','9.1', + '

Умножение «в столбик»: умножают на каждую цифру второго множителя, потом складывают со сдвигом.

' + +'

Деление «уголком»: делят старшие разряды, сносят следующие цифры. Проверка: $\\text{частное}\\cdot\\text{делитель}=\\text{делимое}$.

' + +'

Свойства: $a\\cdot b=b\\cdot a$;   $a\\cdot(b+c)=a\\cdot b+a\\cdot c$ (распределительное).

'); + h+=makeCard('example','Разбор по шагам','9.2', + '

Вычислим $156:12$.

' + +'
    ' + +'
  1. $15$ десятков делим на $12$ — по $1$ десятку ($12$), остаток $3$ десятка.
  2. ' + +'
  3. Сносим $6$: получаем $36$ единиц.
  4. ' + +'
  5. $36:12=3$. Записываем рядом.
  6. ' + +'
  7. Ответ: $156:12=13$. Проверка: $13\\cdot 12=156$.
  8. ' + +'
'); + h+=makeCard('theory','А знаешь ли ты?','9.3', + '

Знак умножения «крестиком» $\\times$ ввёл Уильям Отред в $1631$ году, а точку $\\cdot$ предложил Готфрид Лейбниц, чтобы крестик не путали с буквой $x$. Поэтому в алгебре чаще пишут точку.

'); + h+='
Интерактив 1
Умножение как прямоугольник
' + +'
Точки выстроены в прямоугольник: $a$ строк по $b$ точек. Сколько всего?
' + +'
Вопрос 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+='
Интерактив 2
Умножай и дели
' + +'
Вычисли значение выражения.
' + +'
Пример 1 / 6Очки: 0 / 6
' + +'
' + +'
' + +'
'; + h+=secNav('p8','p10')+readBtn('p9'); + box.innerHTML=h; renderMath(box); + + (function(){ + var i=0,score=0,cur=null; + function arrSVG(a,b){ var u=16,x0=14,y0=12,W=x0*2+b*u,H=y0*2+a*u; var s=''; + for(var r=0;r'; } return s+''; } + function gen(){ cur={a:_ri(2,9), b:_ri(2,9)}; cur.ans=cur.a*cur.b; } + function show(){ if(i>=6){ document.getElementById('p9-fig').innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p9-iv1');bumpProgress('p9',30);}else if(score>=3){addXp(8,'p9-iv1');bumpProgress('p9',16);} return; } + gen(); document.getElementById('p9-i').textContent=i+1; + document.getElementById('p9-fig').innerHTML=arrSVG(cur.a,cur.b)+'
'+cur.a+' строк × '+cur.b+' точек
'; + document.getElementById('p9-a').value=''; document.getElementById('p9-fb').style.display='none'; } + function go(){ if(i>=6)return; var fb=document.getElementById('p9-fb'), a=parseInt(document.getElementById('p9-a').value,10); + if(isNaN(a)){ feedback(fb,false,'Введи число.'); return; } + if(a===cur.ans){ score++; feedback(fb,true,'✓ Верно! '+cur.a+'·'+cur.b+'='+cur.ans+'.'); } else feedback(fb,false,'✗ Нет. '+cur.a+'·'+cur.b+'='+cur.ans+'.'); + document.getElementById('p9-s').textContent=score; i++; setTimeout(show,1200); } + document.getElementById('p9-go').addEventListener('click',go); + document.getElementById('p9-a').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); + show(); + })(); + + (function(){ + var i=0,score=0,cur=null; + function gen(){ if(_ri(0,1)===0){ var a=_ri(12,99),b=_ri(11,40); cur={q:a+' \\cdot '+b,ans:a*b}; } else { var q=_ri(11,40),d=_ri(2,12),n=q*d; cur={q:n+' : '+d,ans:q}; } } + function show(){ if(i>=6){ document.getElementById('p9-mq').innerHTML='Готово! '+score+' / 6'; if(score>=5){addXp(15,'p9-iv2');bumpProgress('p9',30);}else if(score>=3){addXp(8,'p9-iv2');bumpProgress('p9',16);} return; } + gen(); document.getElementById('p9-mi').textContent=i+1; + document.getElementById('p9-mq').innerHTML='$'+cur.q+'$'; renderMath(document.getElementById('p9-mq')); + document.getElementById('p9-ma').value=''; document.getElementById('p9-mfb').style.display='none'; } + function go(){ if(i>=6)return; var fb=document.getElementById('p9-mfb'), a=parseInt(document.getElementById('p9-ma').value,10); + if(isNaN(a)){ feedback(fb,false,'Введи число.'); return; } + if(a===cur.ans){ score++; feedback(fb,true,'✓ Верно! Ответ '+cur.ans+'.'); } else feedback(fb,false,'✗ Нет. Правильно: '+cur.ans+'.'); + document.getElementById('p9-ms').textContent=score; i++; setTimeout(show,1200); } + document.getElementById('p9-mgo').addEventListener('click',go); + document.getElementById('p9-ma').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); }); + show(); + })(); +} + /* ===================== ДАННЫЕ САЙДБАРА / ГЛОССАРИЯ ===================== */ var SIDEBARS = { p1:{ title:'Шпаргалка § 1', rows:[ @@ -654,6 +865,21 @@ var SIDEBARS = { ['Единичный отрезок','задаёт «шаг»'], ['Координата','число точки: $A(3)$'], ['Правее','значит больше'] ]}, + p7:{ title:'Шпаргалка § 7', rows:[ + ['Смотрим','на следующую (младшую) цифру'], + ['$<5$','разряд оставляем'], + ['$\\ge 5$','разряд +1'], + ['Младшие','заменяем нулями; знак $\\approx$'] ]}, + p8:{ title:'Шпаргалка § 8', rows:[ + ['Столбик','разряд под разрядом'], + ['$\\ge 10$','переносим в старший разряд'], + ['Не хватает','занимаем у старшего'], + ['$37+99$','$=37+100-1=136$'] ]}, + p9:{ title:'Шпаргалка § 9', rows:[ + ['Умножение','быстрое сложение слагаемых'], + ['Деление','обратно умножению'], + ['Проверка','частное · делитель = делимое'], + ['Распределит.','$a(b+c)=ab+ac$'] ]}, final:{ title:'Финал главы 1', rows:[ ['5 боссов','разряды, округление, действия, степень'], ['Победа','4 из 5 и больше'], @@ -673,7 +899,7 @@ var GLOSSARY = [ { term:'разряд', def:'Место цифры в записи числа: единицы, десятки, сотни и т. д.', sec:'p2', aliases:['разряд','разряда','разряде','разряды','разрядов'] }, { term:'класс', def:'Группа из трёх соседних разрядов: единицы, тысячи, миллионы.', sec:'p2', aliases:['класс','класса','классе','классы','классов'] } ]; -var BUILDERS = { p1:buildP1, p2:buildP2, p3:buildP3, p4:buildP4, p5:buildP5, p6:buildP6, final:buildFinal }; +var BUILDERS = { p1:buildP1, p2:buildP2, p3:buildP3, p4:buildP4, p5:buildP5, p6:buildP6, p7:buildP7, p8:buildP8, p9:buildP9, final:buildFinal }; Object.assign(window.M6, { sidebars:SIDEBARS, tips:TIPS, glossary:GLOSSARY, builders:BUILDERS });