feat(math5): Глава 1 — §1 «Как решать задачу», §2 «Чтение и запись. Разряды», финал
§1: 4 шага решения (Пойа) + тренажёр «на каком шаге ученик» + решатель задач. §2: натуральные числа и нуль, классы/разряды, интерактивная разрядная таблица (ввод числа → раскладка по классам единицы/тысячи/миллионы) + тренажёр «цифра в разряде». Финал главы 1 — 5 боссов (разряды/округление/действия/степень). Шпаргалки/типсы/глоссарий для §1/§2/финала. §3–17 пока заглушки движка. Тесты math5: 8/8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,7 +62,7 @@ test('engine: init() вызывается ПОСЛЕ экспортов (общ
|
||||
});
|
||||
|
||||
for (const ch of CHAPTERS) {
|
||||
test(`${ch.file}: SPA без ошибок, ${ch.cards} карточек, активен § 1, заглушка`, async () => {
|
||||
test(`${ch.file}: SPA без ошибок, ${ch.cards} карточек, активен § 1`, async () => {
|
||||
const { doc, errors } = await loadDom(ch.file);
|
||||
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
|
||||
assert.equal(doc.querySelectorAll('#psel-grid .psel-card').length, ch.cards, ch.cards + ' карточек');
|
||||
@@ -70,12 +70,34 @@ for (const ch of CHAPTERS) {
|
||||
assert.ok(active && active.id === 'sec-p1', 'активен sec-p1');
|
||||
const body = doc.querySelector('#p1-body');
|
||||
assert.ok(body && body.children.length > 0, 'тело § 1 заполнено');
|
||||
assert.ok(doc.querySelector('#p1-body .m6-placeholder'), 'заглушка § 1 (нет билдера — ожидаемо в каркасе)');
|
||||
assert.ok(doc.querySelector('#p1-body [data-read]'), 'кнопка прочтения § 1');
|
||||
assert.ok(doc.querySelector('#psel-grid .psel-card.final'), 'есть карточка финала');
|
||||
});
|
||||
}
|
||||
|
||||
test('ch2/ch3: §§ без билдеров — заглушка движка (каркас ждёт наполнения)', async () => {
|
||||
for (const f of ['math_5_ch2.html', 'math_5_ch3.html']) {
|
||||
const { doc } = await loadDom(f);
|
||||
assert.ok(doc.querySelector('#p1-body .m6-placeholder'), f + ': заглушка § 1');
|
||||
}
|
||||
});
|
||||
|
||||
test('ch1: §1 «как решать задачу», §2 «разрядная таблица», финал-боссы', async () => {
|
||||
const { doc, errors } = await loadDom('math_5_ch1.html');
|
||||
const win = doc.defaultView;
|
||||
assert.ok(!doc.querySelector('#p1-body .m6-placeholder'), '§1 наполнен (не заглушка)');
|
||||
assert.equal(doc.querySelectorAll('#p1-iv1 [data-step]').length, 4, '§1: 4 кнопки шагов');
|
||||
assert.ok(doc.querySelector('#p1-iv2 #p1-pa'), '§1: тренажёр-решатель задач');
|
||||
win.goTo('p2'); await wait(80);
|
||||
assert.ok(doc.querySelector('#p2-pv-out table'), '§2: разрядная таблица построена');
|
||||
assert.ok(doc.querySelector('#p2-iv2 #p2-qa'), '§2: тренажёр «цифра в разряде»');
|
||||
win.goTo('final'); await wait(80);
|
||||
assert.ok(doc.querySelector('#fin-go'), 'финал: арена боссов');
|
||||
win.bumpProgress('final', 100); await wait(20);
|
||||
assert.ok(win.M6STATE.achievements.has('ch1_done'), 'достижение «Глава 1 пройдена»');
|
||||
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
|
||||
});
|
||||
|
||||
test('хаб math-5: 3 главы, курсовой финал, ачивка-полоса', async () => {
|
||||
const { doc, errors } = await loadDom('math_5_hub.html');
|
||||
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
|
||||
|
||||
@@ -95,11 +95,273 @@ window.M6 = {
|
||||
{ id:'p17', num:'§ 17', name:'Исторические сведения о числах', sub:'Как считали разные народы', applied:true },
|
||||
{ id:'final', num:'★', name:'Финал главы', sub:'Тест · боссы главы 1', final:true }
|
||||
],
|
||||
achLabels: { final_done:'Глава 1 пройдена!' },
|
||||
achLabels: {
|
||||
start:'Начало главы 1!', p1_done:'Решаю задачи по плану!', p2_done:'Читаю и пишу большие числа!',
|
||||
p3_done:'Сравниваю числа!', p4_done:'Геометрия: точка, прямая, луч!', p5_done:'Измеряю отрезки!',
|
||||
p6_done:'Координатный луч покорён!', p7_done:'Округляю уверенно!', p8_done:'Сложение и вычитание!',
|
||||
p9_done:'Умножение и деление!', p10_done:'Степень числа!', p11_done:'Деление с остатком!',
|
||||
p12_done:'НОД и НОК!', p13_done:'Признаки делимости!', p14_done:'Простые числа!',
|
||||
p15_done:'Математика вокруг нас!', p16_done:'Задачи-головоломки!', p17_done:'Истории о числах!',
|
||||
ch1_done:'Глава 1 «Натуральные числа» пройдена!'
|
||||
},
|
||||
startAch: ['start','Начало главы 1!'],
|
||||
finalAch: ['ch1_done', 'Глава 1 «Натуральные числа» пройдена!'],
|
||||
sidebars: {}, tips: [], glossary: [], searchRows: [], builders: {},
|
||||
footer: 'Интерактивный учебник «Математика 5» · Глава 1 · Натуральные числа · 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 _kf(x){ return String(x).replace('.','{,}'); }
|
||||
function _grp(s){ s=String(s); var o='',c=0; for(var i=s.length-1;i>=0;i--){ o=s[i]+o; if(++c%3===0&&i>0)o='\\,'+o; } return o; }
|
||||
|
||||
/* ===================== § 1. КАК РЕШАТЬ ЗАДАЧУ ===================== */
|
||||
function buildP1(){
|
||||
var box=document.getElementById('p1-body'); var h='';
|
||||
h+=makeCard('oral','Где это в жизни','1.0',
|
||||
'<p>Решать задачи приходится не только на уроке. Распланировать карманные деньги, прикинуть, хватит ли времени дойти до школы, разделить пиццу поровну — всё это задачи. Хороший «решатель» сначала <b>понимает</b>, чего от него хотят, и только потом считает.</p>');
|
||||
h+=makeCard('rule','Четыре шага решения','1.1',
|
||||
'<p>Любую задачу удобно решать по плану из четырёх шагов:</p>'
|
||||
+'<ol style="padding-left:22px;line-height:2">'
|
||||
+'<li><b>Понять условие.</b> Что дано? Что нужно найти? Сделать рисунок или краткую запись.</li>'
|
||||
+'<li><b>Составить план.</b> Какие действия и в каком порядке приведут к ответу?</li>'
|
||||
+'<li><b>Выполнить план.</b> Аккуратно сделать вычисления.</li>'
|
||||
+'<li><b>Проверить.</b> Подходит ли ответ по смыслу? Сошлось ли?</li>'
|
||||
+'</ol>');
|
||||
h+=makeCard('example','Разбор по шагам','1.2',
|
||||
'<p>Задача: в двух коробках $40$ карандашей. В первой на $6$ больше, чем во второй. Сколько карандашей в каждой коробке?</p>'
|
||||
+'<ol style="padding-left:22px;line-height:2">'
|
||||
+'<li><b>Понять.</b> Дано: всего $40$, разница $6$. Найти: сколько в каждой коробке.</li>'
|
||||
+'<li><b>План.</b> Уберём «лишние» $6$ из суммы, разделим остаток поровну, потом вернём $6$ в первую.</li>'
|
||||
+'<li><b>Решение.</b> $(40-6):2=17$ — во второй; $17+6=23$ — в первой.</li>'
|
||||
+'<li><b>Проверка.</b> $17+23=40$ и $23-17=6$. Верно!</li>'
|
||||
+'</ol>');
|
||||
h+=makeCard('theory','А знаешь ли ты?','1.3',
|
||||
'<p>Математик <b>Дьёрдь Пойа</b> в 1945 году написал знаменитую книгу «Как решать задачу». Именно он описал эти четыре шага. Его главный совет: «Если не получается решить задачу — реши сначала более простую похожую задачу».</p>');
|
||||
h+='<div class="wg" id="p1-iv1"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><div class="wg-title">На каком шаге ученик?</div></div>'
|
||||
+'<div class="wg-help">Прочитай фразу ученика и определи, какому из четырёх шагов она соответствует.</div>'
|
||||
+'<div class="score-display"><span>Вопрос <b id="p1-i">1</b> / 5</span><span>Очки: <b id="p1-s">0</b> / 5</span></div>'
|
||||
+'<div id="p1-q" class="qbox" style="font-size:1.05rem"></div>'
|
||||
+'<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap"><button class="btn primary" data-step="1">Понять условие</button><button class="btn primary" data-step="2">Составить план</button><button class="btn primary" data-step="3">Выполнить</button><button class="btn primary" data-step="4">Проверить</button></div>'
|
||||
+'<div class="feedback" id="p1-fb"></div></div>';
|
||||
h+='<div class="wg" id="p1-iv2"><div class="wg-header"><span class="wg-badge">Интерактив 2</span><div class="wg-title">Реши задачу</div></div>'
|
||||
+'<div class="wg-help">Реши задачу по плану и введи ответ числом (без единиц).</div>'
|
||||
+'<div class="score-display"><span>Задача <b id="p1-pi">1</b> / 6</span><span>Очки: <b id="p1-ps">0</b> / 6</span></div>'
|
||||
+'<div id="p1-pq" class="qbox" style="font-size:1rem;text-align:left"></div>'
|
||||
+'<div style="display:flex;gap:10px;justify-content:center;align-items:center;flex-wrap:wrap"><input type="text" id="p1-pa" class="tinp" style="width:120px;text-align:center" placeholder="ответ"><button class="btn primary" id="p1-pgo">Проверить</button></div>'
|
||||
+'<div class="feedback" id="p1-pfb"></div></div>';
|
||||
h+=secNav(null,'p2')+readBtn('p1');
|
||||
box.innerHTML=h; renderMath(box);
|
||||
|
||||
(function(){
|
||||
var Q=[
|
||||
{t:'«Сделаю краткую запись: дано $40$, разница $6$.»', s:1},
|
||||
{t:'«Сначала вычту $6$, потом разделю остаток на $2$.»', s:2},
|
||||
{t:'«$40-6=34$, затем $34:2=17$.»', s:3},
|
||||
{t:'«Проверю: $17+23=40$ — сходится.»', s:4},
|
||||
{t:'«Что именно нужно найти в задаче?»', s:1},
|
||||
{t:'«Запишу ответ и подумаю, разумен ли он.»', s:4},
|
||||
{t:'«Каким действием это решается?»', s:2},
|
||||
{t:'«Аккуратно посчитаю столбиком.»', s:3}
|
||||
];
|
||||
var order=[],i=0,score=0,cur=null;
|
||||
function reorder(){ 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; } }
|
||||
reorder();
|
||||
function show(){ if(i>=5){ document.getElementById('p1-q').innerHTML='<b>Готово!</b> Результат: '+score+' / 5'; if(score>=4){addXp(15,'p1-iv1');bumpProgress('p1',30);}else if(score>=2){addXp(8,'p1-iv1');bumpProgress('p1',16);} return; }
|
||||
cur=Q[order[i]]; document.getElementById('p1-i').textContent=i+1;
|
||||
document.getElementById('p1-q').innerHTML=cur.t; renderMath(document.getElementById('p1-q'));
|
||||
document.getElementById('p1-fb').style.display='none'; }
|
||||
function ans(s){ if(i>=5)return; var names=['','Понять условие','Составить план','Выполнить','Проверить']; var fb=document.getElementById('p1-fb');
|
||||
if(s===cur.s){ score++; feedback(fb,true,'✓ Верно — это шаг «'+names[cur.s]+'».'); } else feedback(fb,false,'✗ Нет. Это шаг «'+names[cur.s]+'».');
|
||||
document.getElementById('p1-s').textContent=score; i++; setTimeout(show,1100); }
|
||||
document.querySelectorAll('#p1-iv1 [data-step]').forEach(function(b){ b.addEventListener('click',function(){ ans(+b.getAttribute('data-step')); }); });
|
||||
show();
|
||||
})();
|
||||
|
||||
(function(){
|
||||
var PROB=[
|
||||
{q:'В двух корзинах $30$ яблок. В первой на $4$ больше, чем во второй. Сколько яблок во второй?',a:13},
|
||||
{q:'Книга стоит $7$ р., тетрадь — на $5$ р. дешевле. Сколько стоит тетрадь?',a:2},
|
||||
{q:'Купили $3$ ручки по $2$ р. Сколько заплатили?',a:6},
|
||||
{q:'У Маши $24$ наклейки, она отдала треть. Сколько наклеек она отдала?',a:8},
|
||||
{q:'В классе $28$ учеников, девочек $15$. Сколько мальчиков?',a:13},
|
||||
{q:'За $5$ дней прочитали $45$ страниц поровну. Сколько страниц в день?',a:9},
|
||||
{q:'Ленту $200$ см разрезали на части по $25$ см. Сколько получилось частей?',a:8},
|
||||
{q:'Было $50$ р., потратили $18$ р. и $12$ р. Сколько осталось?',a:20}
|
||||
];
|
||||
var order=[],i=0,score=0,cur=null;
|
||||
function reorder(){ order=PROB.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; } }
|
||||
reorder();
|
||||
function show(){ if(i>=6){ document.getElementById('p1-pq').innerHTML='<b>Готово!</b> Результат: '+score+' / 6'; if(score>=5){addXp(15,'p1-iv2');bumpProgress('p1',30);}else if(score>=3){addXp(8,'p1-iv2');bumpProgress('p1',16);} return; }
|
||||
cur=PROB[order[i]]; document.getElementById('p1-pi').textContent=i+1;
|
||||
document.getElementById('p1-pq').innerHTML=cur.q; renderMath(document.getElementById('p1-pq'));
|
||||
document.getElementById('p1-pa').value=''; document.getElementById('p1-pfb').style.display='none'; }
|
||||
function go(){ if(i>=6)return; var fb=document.getElementById('p1-pfb'), v=parseFloat(document.getElementById('p1-pa').value.replace(',','.').trim());
|
||||
if(isNaN(v)){ feedback(fb,false,'Введи число.'); return; }
|
||||
if(v===cur.a){ score++; feedback(fb,true,'✓ Верно! Ответ '+cur.a+'.'); } else feedback(fb,false,'✗ Нет. Правильный ответ: '+cur.a+'.');
|
||||
document.getElementById('p1-ps').textContent=score; i++; setTimeout(show,1200); }
|
||||
document.getElementById('p1-pgo').addEventListener('click',go);
|
||||
document.getElementById('p1-pa').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); });
|
||||
show();
|
||||
})();
|
||||
}
|
||||
|
||||
/* ===================== § 2. ЧТЕНИЕ И ЗАПИСЬ. РАЗРЯДЫ ===================== */
|
||||
function buildP2(){
|
||||
var box=document.getElementById('p2-body'); var h='';
|
||||
h+=makeCard('oral','Где это в жизни','2.0',
|
||||
'<p>Большие числа окружают нас: на Земле живёт около $8\\,000\\,000\\,000$ человек, до Луны примерно $384\\,000$ км, а у современного смартфона памяти $128\\,000\\,000\\,000$ байт. Чтобы не запутаться в нулях, числа разбивают на <b>классы</b> по три цифры.</p>');
|
||||
h+=makeCard('theory','Натуральные числа и нуль','2.1',
|
||||
'<p><b>Натуральные числа</b> — это числа, которыми считают предметы: $1, 2, 3, 4, \\dots$ Их ряд бесконечен: какое бы число ни взяли, всегда есть следующее.</p>'
|
||||
+'<p>Число <b>нуль</b> $(0)$ натуральным не считают, но без него не записать, например, число $108$. Множество натуральных чисел обозначают буквой $\\mathbb{N}$.</p>');
|
||||
h+=makeCard('rule','Классы и разряды','2.2',
|
||||
'<p>Запись числа читают <b>справа налево</b> по разрядам и группируют по три — в <b>классы</b>:</p>'
|
||||
+'<table class="tbl"><tr><th colspan="3">Миллионы</th><th colspan="3">Тысячи</th><th colspan="3">Единицы</th></tr>'
|
||||
+'<tr><td>сот</td><td>дес</td><td>ед</td><td>сот</td><td>дес</td><td>ед</td><td>сот</td><td>дес</td><td>ед</td></tr>'
|
||||
+'<tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td></tr></table>'
|
||||
+'<p>Это число $12\\,345\\,678$ — «двенадцать миллионов триста сорок пять тысяч шестьсот семьдесят восемь».</p>');
|
||||
h+=makeCard('example','Читаем число','2.3',
|
||||
'<p>$5\\,204$ — пять тысяч двести четыре. $70\\,030$ — семьдесят тысяч тридцать. $300\\,000$ — триста тысяч.</p>'
|
||||
+'<p>Нуль в разряде означает, что этого разряда «нет»: в числе $70\\,030$ нет ни сотен, ни единиц тысяч, ни единиц.</p>');
|
||||
h+=makeCard('example','Разбор по шагам','2.4',
|
||||
'<p>Запишем цифрами число «двести три тысячи сорок».</p>'
|
||||
+'<ol style="padding-left:22px;line-height:2">'
|
||||
+'<li>Находим классы: «двести три <b>тысячи</b>» — класс тысяч $=203$; «сорок» — класс единиц $=40$.</li>'
|
||||
+'<li>Каждый класс — ровно $3$ цифры: тысячи $\\to 203$, единицы $\\to 040$.</li>'
|
||||
+'<li>Соединяем: $203\\,040$.</li>'
|
||||
+'<li>Проверка: читаем обратно — «двести три тысячи сорок». Верно!</li>'
|
||||
+'</ol>');
|
||||
h+=makeCard('theory','А знаешь ли ты?','2.5',
|
||||
'<p>Число $10^{100}$ (единица со ста нулями) называется <b>гугол</b>. Это слово придумал девятилетний племянник математика Эдварда Каснера. От него же произошло название поисковика Google. А гуголов в одном гуголплексе — гугол!</p>');
|
||||
h+='<div class="wg" id="p2-iv1"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><div class="wg-title">Разрядная таблица</div></div>'
|
||||
+'<div class="wg-help">Введи натуральное число (до 9 цифр) — оно разложится по классам и разрядам.</div>'
|
||||
+'<div style="display:flex;gap:10px;justify-content:center;align-items:center;flex-wrap:wrap;margin-bottom:8px"><input type="text" id="p2-pv-in" class="tinp" style="width:170px;text-align:center" value="12345678" placeholder="например 305040"><button class="btn primary" id="p2-pv-go">Разложить</button></div>'
|
||||
+'<div id="p2-pv-out" style="overflow-x:auto"></div></div>';
|
||||
h+='<div class="wg" id="p2-iv2"><div class="wg-header"><span class="wg-badge">Интерактив 2</span><div class="wg-title">Какая цифра в разряде?</div></div>'
|
||||
+'<div class="wg-help">Назови цифру в указанном разряде данного числа. Введи одну цифру (0–9).</div>'
|
||||
+'<div class="score-display"><span>Вопрос <b id="p2-qi">1</b> / 6</span><span>Очки: <b id="p2-qs">0</b> / 6</span></div>'
|
||||
+'<div id="p2-qq" class="qbox"></div>'
|
||||
+'<div style="display:flex;gap:10px;justify-content:center;align-items:center;flex-wrap:wrap"><input type="number" id="p2-qa" class="tinp" style="width:90px;text-align:center" min="0" max="9"><button class="btn primary" id="p2-qgo">Проверить</button></div>'
|
||||
+'<div class="feedback" id="p2-qfb"></div></div>';
|
||||
h+=secNav('p1','p3')+readBtn('p2');
|
||||
box.innerHTML=h; renderMath(box);
|
||||
|
||||
(function(){
|
||||
var CLS=[['Миллионы','#4f46e5'],['Тысячи','#0d9488'],['Единицы','#e11d48']];
|
||||
var LAB=['сот','дес','ед','сот','дес','ед','сот','дес','ед'];
|
||||
function render(){
|
||||
var raw=(document.getElementById('p2-pv-in').value||'').replace(/\D/g,'');
|
||||
if(!raw)raw='0'; if(raw.length>9)raw=raw.slice(-9);
|
||||
var num=parseInt(raw,10); var s=raw.padStart(9,'0');
|
||||
var firstSig=s.search(/[1-9]/); if(firstSig<0)firstSig=8;
|
||||
var th='<table class="tbl" style="margin:0 auto"><tr>';
|
||||
for(var c=0;c<3;c++) th+='<th colspan="3" style="color:'+CLS[c][1]+'">'+CLS[c][0]+'</th>';
|
||||
th+='</tr><tr>';
|
||||
for(var k=0;k<9;k++) th+='<td style="font-size:.62rem;color:var(--muted)">'+LAB[k]+'</td>';
|
||||
th+='</tr><tr>';
|
||||
for(var d=0;d<9;d++){ var grp=Math.floor(d/3),dim=d<firstSig; th+='<td style="font-size:1.4rem;font-weight:800;color:'+CLS[grp][1]+';opacity:'+(dim?0.18:1)+'">'+s[d]+'</td>'; }
|
||||
th+='</tr></table>';
|
||||
th+='<div style="text-align:center;margin-top:10px;font-size:1.1rem;font-weight:700">$'+_grp(num)+'$</div>';
|
||||
var out=document.getElementById('p2-pv-out'); out.innerHTML=th; renderMath(out);
|
||||
}
|
||||
document.getElementById('p2-pv-go').addEventListener('click',render);
|
||||
document.getElementById('p2-pv-in').addEventListener('keydown',function(e){ if(e.key==='Enter')render(); });
|
||||
render();
|
||||
})();
|
||||
|
||||
(function(){
|
||||
var PL=[['единиц',0],['десятков',1],['сотен',2],['единиц тысяч',3],['десятков тысяч',4],['сотен тысяч',5]];
|
||||
var i=0,score=0,cur=null;
|
||||
function gen(){ var n=_ri(100000,999999), s=String(n), pl=_pick(PL); cur={n:n, s:s, place:pl[0], digit:+s[s.length-1-pl[1]]}; }
|
||||
function show(){ if(i>=6){ document.getElementById('p2-qq').innerHTML='<b>Готово!</b> Результат: '+score+' / 6'; if(score>=5){addXp(15,'p2-iv2');bumpProgress('p2',30);}else if(score>=3){addXp(8,'p2-iv2');bumpProgress('p2',18);} return; }
|
||||
gen(); document.getElementById('p2-qi').textContent=i+1;
|
||||
document.getElementById('p2-qq').innerHTML='Число $'+_grp(cur.n)+'$. Какая цифра в разряде <b>'+cur.place+'</b>?'; renderMath(document.getElementById('p2-qq'));
|
||||
document.getElementById('p2-qa').value=''; document.getElementById('p2-qfb').style.display='none'; }
|
||||
function go(){ if(i>=6)return; var fb=document.getElementById('p2-qfb'), a=parseInt(document.getElementById('p2-qa').value,10);
|
||||
if(isNaN(a)){ feedback(fb,false,'Введи одну цифру 0–9.'); return; }
|
||||
if(a===cur.digit){ score++; feedback(fb,true,'✓ Верно! В разряде '+cur.place+' стоит '+cur.digit+'.'); } else feedback(fb,false,'✗ Нет. Правильный ответ: '+cur.digit+'.');
|
||||
document.getElementById('p2-qs').textContent=score; i++; setTimeout(show,1100); }
|
||||
document.getElementById('p2-qgo').addEventListener('click',go);
|
||||
document.getElementById('p2-qa').addEventListener('keydown',function(e){ if(e.key==='Enter')go(); });
|
||||
show();
|
||||
})();
|
||||
}
|
||||
|
||||
/* ===================== ФИНАЛ ГЛАВЫ ===================== */
|
||||
function buildFinal(){
|
||||
var box=document.getElementById('final-body'); var h='';
|
||||
h+=makeCard('theory','Финал главы 1','★',
|
||||
'<p>Пять боссов проверят владение натуральными числами: разряды, округление, действия и степень. Побей не меньше четырёх — и глава покорена!</p>');
|
||||
h+='<div class="wg" id="fin"><div class="wg-header"><span class="wg-badge">Боссы</span><div class="wg-title">Сразись с главой 1</div></div>'
|
||||
+'<div class="hp-boss"><div class="hp-boss-fill" id="fin-hp" style="width:100%"></div></div>'
|
||||
+'<div class="score-display"><span>Босс <b id="fin-i">1</b> / 5</span><span>Побеждено: <b id="fin-s">0</b> / 5</span></div>'
|
||||
+'<div id="fin-name" style="font-weight:800;color:#b91c1c;text-align:center;margin-bottom:6px"></div>'
|
||||
+'<div id="fin-q" class="boss-q"></div>'
|
||||
+'<div style="display:flex;gap:10px;justify-content:center;align-items:center;flex-wrap:wrap"><input type="text" id="fin-a" class="tinp" style="width:160px;text-align:center" placeholder="ответ"><button class="btn primary" id="fin-go">Удар!</button></div>'
|
||||
+'<div class="feedback" id="fin-fb"></div></div>';
|
||||
h+=secNav('p17',null)+readBtn('final','Завершить главу 1 (+10 XP)');
|
||||
box.innerHTML=h; renderMath(box);
|
||||
|
||||
(function(){
|
||||
var bosses=[
|
||||
function(){ var n=_ri(100000,999999), s=String(n); return {name:'Страж Разрядов', q:'В числе $'+_grp(n)+'$ назови цифру в разряде <b>тысяч</b>.', ans:+s[s.length-4]}; },
|
||||
function(){ var n=_ri(1200,9800); return {name:'Округлитель', q:'Округли $'+_grp(n)+'$ до <b>сотен</b>.', ans:Math.round(n/100)*100}; },
|
||||
function(){ var a=_ri(2400,8600), b=_ri(1100,2300); return {name:'Сумматор', q:'Вычисли $'+_grp(a)+' + '+_grp(b)+'$.', ans:a+b}; },
|
||||
function(){ var a=_ri(13,40), b=_ri(11,30); return {name:'Множитель', q:'Вычисли $'+a+' \\cdot '+b+'$.', ans:a*b}; },
|
||||
function(){ var p=_pick([[2,5,32],[3,4,81],[5,3,125],[2,8,256],[4,3,64],[6,2,36]]); return {name:'Повелитель Степеней', q:'Вычисли $'+p[0]+'^{'+p[1]+'}$.', ans:p[2]}; }
|
||||
];
|
||||
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?'<b>Победа!</b> Глава 1 пройдена. ':'<b>Бой окончен.</b> ')+'Побеждено боссов: '+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=parseFloat(document.getElementById('fin-a').value.replace(',','.').trim());
|
||||
if(isNaN(v)){ feedback(fb,false,'Введи число.'); return; }
|
||||
if(Math.abs(v-cur.ans)<1e-9){ 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:[
|
||||
['Шаг 1','понять условие: что дано, что найти'],
|
||||
['Шаг 2','составить план действий'],
|
||||
['Шаг 3','выполнить вычисления'],
|
||||
['Шаг 4','проверить ответ'] ]},
|
||||
p2:{ title:'Шпаргалка § 2', rows:[
|
||||
['Натуральные','$1,2,3,\\dots$ — для счёта'],
|
||||
['Нуль','не натуральное, но нужно в записи'],
|
||||
['Класс','группа из 3 разрядов'],
|
||||
['Классы','единицы, тысячи, миллионы…'] ]},
|
||||
final:{ title:'Финал главы 1', rows:[
|
||||
['5 боссов','разряды, округление, действия, степень'],
|
||||
['Победа','4 из 5 и больше'],
|
||||
['Награда','+40 XP и достижение «Глава 1 пройдена»'] ]}
|
||||
};
|
||||
var TIPS = [
|
||||
{ sec:'p1', html:'Не бросайся считать сразу. Сначала спроси себя: «что дано?» и «что нужно найти?» — половина дела готова.' },
|
||||
{ sec:'p2', html:'Разбивай длинное число на классы по три цифры справа: $12\\,345\\,678$. Так его легко прочитать.' },
|
||||
{ sec:'final', html:'Перед ударом прикинь ответ в уме. Для степени $a^n$ — это $a$, умноженное само на себя $n$ раз.' }
|
||||
];
|
||||
var GLOSSARY = [
|
||||
{ term:'натуральное число', def:'Число, которым считают предметы: $1,2,3,\\dots$ Нуль натуральным не считают.', sec:'p2', aliases:['натуральное число','натуральные числа','натуральных чисел','натурального числа'] },
|
||||
{ term:'разряд', def:'Место цифры в записи числа: единицы, десятки, сотни и т. д.', sec:'p2', aliases:['разряд','разряда','разряде','разряды','разрядов'] },
|
||||
{ term:'класс', def:'Группа из трёх соседних разрядов: единицы, тысячи, миллионы.', sec:'p2', aliases:['класс','класса','классе','классы','классов'] }
|
||||
];
|
||||
var BUILDERS = { p1:buildP1, p2:buildP2, final:buildFinal };
|
||||
Object.assign(window.M6, { sidebars:SIDEBARS, tips:TIPS, glossary:GLOSSARY, builders:BUILDERS });
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user