feat(geom9 ch4 final): Финал Главы 4 (5 боссов + ачивка)
This commit is contained in:
@@ -1645,16 +1645,232 @@ function buildP14(){
|
||||
}
|
||||
|
||||
function buildFinal4(){
|
||||
const body = document.getElementById('final4-body');
|
||||
const box = document.getElementById('final4-body');
|
||||
let html = '';
|
||||
html += makeCard('theory', 'Финал главы 4', '★', `
|
||||
<p>Итоговый раздел главы <b>«Правильные многоугольники»</b> будет добавлен в следующих обновлениях.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 7.</p>`);
|
||||
html += readButton('final4');
|
||||
|
||||
/* Часть А — Шпаргалка главы (4 mini-карточки) */
|
||||
html += `<div class="card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon theory">${ICONS.theory}</span>
|
||||
<span class="card-title">Шпаргалка главы 4</span>
|
||||
<span class="card-num">Итог</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Все ключевые формулы главы <b>«Правильные многоугольники»</b> — в одном месте. Просмотри перед боссами!</p>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-top:10px">
|
||||
<div style="padding:12px 14px;background:var(--acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="var(--pri2)" stroke-width="2" style="width:18px;height:18px"><polygon points="12 2 22 8 22 16 12 22 2 16 2 8"/></svg>
|
||||
<span style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 13 · Правильные многоуг.</span>
|
||||
</div>
|
||||
<div style="font-size:.92rem">Внутренний угол $\\beta = \\dfrac{180°(n-2)}{n}$. Центральный угол $= \\dfrac{360°}{n}$.</div>
|
||||
</div>
|
||||
<div style="padding:12px 14px;background:var(--acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="var(--pri2)" stroke-width="2" style="width:18px;height:18px"><circle cx="12" cy="12" r="9"/><line x1="12" y1="12" x2="20" y2="12"/><line x1="12" y1="12" x2="12" y2="4"/></svg>
|
||||
<span style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 14 · Радиусы</span>
|
||||
</div>
|
||||
<div style="font-size:.92rem">$\\dfrac{a}{2} = R\\sin\\dfrac{180°}{n} = r\\tan\\dfrac{180°}{n}$. $r = R\\cos\\dfrac{180°}{n}$.</div>
|
||||
</div>
|
||||
<div style="padding:12px 14px;background:var(--acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="var(--pri2)" stroke-width="2" style="width:18px;height:18px"><polygon points="3 20 21 20 12 4"/></svg>
|
||||
<span style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 15 · Эталоны $n=3,4,6$</span>
|
||||
</div>
|
||||
<div style="font-size:.92rem">3-уг: $a = R\\sqrt{3}$. 4-уг: $a = R\\sqrt{2}$. 6-уг: $a = R$.</div>
|
||||
</div>
|
||||
<div style="padding:12px 14px;background:var(--acc-soft);border-radius:11px;border-left:3px solid var(--pri)">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="var(--pri2)" stroke-width="2" style="width:18px;height:18px"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="2.5"/></svg>
|
||||
<span style="font-family:'Unbounded',sans-serif;font-weight:700;color:var(--pri2);font-size:.92rem">§ 16 · Окружность и круг</span>
|
||||
</div>
|
||||
<div style="font-size:.92rem">$C = 2\\pi R$, $S = \\pi R^2$. Дуга $\\ell = \\dfrac{\\pi R \\alpha}{180}$, сектор $S = \\dfrac{\\pi R^2 \\alpha}{360}$.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
/* Часть Б — 5 боссов */
|
||||
html += `<div class="card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon rule">${ICONS.rule}</span>
|
||||
<span class="card-title">Боссы главы 4</span>
|
||||
<span class="card-num">5</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>5 интегрированных задач — каждая комбинирует темы главы. За каждого побеждённого босса — <b>+10 XP</b> и +18% к прогрессу. Победишь всех — <b>+50 XP бонус</b> и ачивка «Магистр многоугольников и круга»!</p>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
html += '<div id="ch4G-bosses-container"></div>';
|
||||
|
||||
html += `<div style="margin-top:18px;padding:18px 20px;background:linear-gradient(135deg,var(--pri-soft),var(--acc-soft));border-radius:14px;border:1.5px solid var(--pri);text-align:center" id="ch4G-final-summary">
|
||||
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:var(--pri2);font-size:1.1rem;margin-bottom:6px">Прогресс по боссам</div>
|
||||
<div id="ch4G-boss-overall" style="font-size:.95rem;color:var(--text);margin-bottom:10px">0 / 5 боссов побеждено</div>
|
||||
<div style="height:12px;background:var(--card);border-radius:8px;overflow:hidden;border:1px solid var(--border)">
|
||||
<div id="ch4G-boss-overall-fill" style="height:100%;width:0%;background:linear-gradient(90deg,var(--pri),var(--acc));transition:width .35s"></div>
|
||||
</div>
|
||||
<div id="ch4G-final-reward" style="margin-top:14px;display:none;padding:14px;background:var(--card);border-radius:11px;border:2px solid var(--warn)">
|
||||
<div style="display:flex;align-items:center;justify-content:center;gap:8px;margin-bottom:6px">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="var(--warn)" stroke-width="2.2" style="width:22px;height:22px"><polygon points="12 2 15 9 22 9 17 14 19 22 12 18 5 22 7 14 2 9 9 9"/></svg>
|
||||
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:var(--pri2);font-size:1.05rem">Магистр многоугольников и круга</div>
|
||||
</div>
|
||||
<div style="font-size:.92rem;margin-bottom:10px">Глава 4 пройдена! Все 5 боссов повержены. +50 XP бонус.</div>
|
||||
<div style="margin-top:10px;padding:12px;background:linear-gradient(135deg,var(--acc-soft),var(--pri-soft));border-radius:10px;border:1px solid var(--pri)">
|
||||
<div style="font-family:'Unbounded',sans-serif;font-weight:800;color:var(--pri2);font-size:1.02rem;margin-bottom:6px">Геометрия 9 пройдена!</div>
|
||||
<div style="font-size:.9rem;color:var(--text);margin-bottom:10px">Ты прошёл все 4 главы курса «Геометрия 9». Соотношения, окружности, площади и правильные многоугольники — в твоём арсенале. Возвращайся в хаб, чтобы выбрать следующий учебник!</div>
|
||||
<a class="btn primary" href="/textbook/geometry-9" style="text-decoration:none">К хабу Геометрии 9 <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
html += secNav('p16', null);
|
||||
body.innerHTML = html;
|
||||
wireReadBtn('final4');
|
||||
if(window.renderMathInElement) renderMath(body);
|
||||
|
||||
box.innerHTML = html;
|
||||
renderMath(box);
|
||||
|
||||
/* Боссы */
|
||||
const BOSSES = [
|
||||
{
|
||||
n:1, color:'#10b981',
|
||||
title:'Циклоп Углов',
|
||||
tag:'§ 13',
|
||||
q:'Чему равен <b>внутренний угол правильного 12-угольника</b> (в градусах)?',
|
||||
ans:150, decimal:false,
|
||||
hint:'$\\beta = \\dfrac{180°(n-2)}{n} = \\dfrac{180° \\cdot 10}{12} = 150°$.'
|
||||
},
|
||||
{
|
||||
n:2, color:'#0891b2',
|
||||
title:'Минотавр Сторон',
|
||||
tag:'§ 14 + § 15',
|
||||
q:'В правильный шестиугольник с описанной окружностью радиуса $R = 5$ вписан правильный треугольник (та же окружность). Найди <b>сторону треугольника</b> (округли до сотых).',
|
||||
ans:8.66, decimal:true,
|
||||
hint:'У треугольника та же $R = 5$. По эталону: $a = R\\sqrt{3} = 5\\sqrt{3} \\approx 8{,}66$.'
|
||||
},
|
||||
{
|
||||
n:3, color:'#7c3aed',
|
||||
title:'Гарпия Окружности',
|
||||
tag:'§ 16',
|
||||
q:'Длина окружности равна $C = 31{,}4$ см. Найди <b>радиус</b> (используй $\\pi = 3{,}14$).',
|
||||
ans:5, decimal:false,
|
||||
hint:'$R = \\dfrac{C}{2\\pi} = \\dfrac{31{,}4}{6{,}28} = 5$.'
|
||||
},
|
||||
{
|
||||
n:4, color:'#dc2626',
|
||||
title:'Дракон Сектора',
|
||||
tag:'§ 16 + § 13',
|
||||
q:'Правильный 6-угольник вписан в окружность радиуса $R = 6$. Найди <b>площадь сектора</b>, центральный угол которого равен углу, опирающемуся на одну сторону (используй $\\pi = 3{,}14$, округли до сотых).',
|
||||
ans:18.84, decimal:true,
|
||||
hint:'Центральный угол 6-уг $= \\dfrac{360°}{6} = 60°$. $S = \\dfrac{\\pi R^2 \\cdot 60}{360} = \\dfrac{\\pi \\cdot 36}{6} = 6\\pi \\approx 18{,}84$.'
|
||||
},
|
||||
{
|
||||
n:5, color:'#f59e0b',
|
||||
title:'Мастер Многоугольников',
|
||||
tag:'§§ 13-16 — синтез',
|
||||
q:'В круг радиуса $R = 10$ вписан правильный 4-угольник (квадрат). Найди <b>разницу</b> между площадью круга и площадью квадрата (используй $\\pi = 3{,}14$).',
|
||||
ans:114, decimal:false,
|
||||
hint:'$S_{круга} = \\pi R^2 = 100\\pi = 314$. Для квадрата $a = R\\sqrt{2}$, $S_{кв} = a^2 = 2R^2 = 200$. Разница $= 314 - 200 = 114$.'
|
||||
},
|
||||
];
|
||||
|
||||
const cont = document.getElementById('ch4G-bosses-container');
|
||||
const STATE_KEY = 'geometry9_ch4_bosses';
|
||||
const BOSS_STATE = (function(){
|
||||
try{ const s = localStorage.getItem(STATE_KEY); if(s){ const p = JSON.parse(s); if(Array.isArray(p) && p.length === BOSSES.length) return p; } }catch(e){}
|
||||
return BOSSES.map(()=>({defeated:false}));
|
||||
})();
|
||||
function saveBosses(){ try{ localStorage.setItem(STATE_KEY, JSON.stringify(BOSS_STATE)); }catch(e){} }
|
||||
|
||||
cont.innerHTML = BOSSES.map((b, idx)=>{
|
||||
const stepAttr = b.decimal ? 'step="0.01"' : 'step="1"';
|
||||
const ph = b.decimal ? 'число (можно с запятой)' : 'целое число';
|
||||
return '<div class="boss-card" id="bossG4-'+b.n+'-card" style="padding:16px;background:var(--card);border-radius:12px;border:2px solid '+b.color+';margin-bottom:14px;transition:background .3s,box-shadow .3s">'
|
||||
+'<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap">'
|
||||
+'<svg viewBox="0 0 24 24" fill="none" stroke="'+b.color+'" stroke-width="2.2" style="width:28px;height:28px;flex-shrink:0"><polygon points="12,2 22,20 2,20"/></svg>'
|
||||
+'<div style="font-family:\'Unbounded\',sans-serif;font-weight:800;color:'+b.color+';font-size:1.05rem">Босс '+b.n+': '+b.title+'</div>'
|
||||
+'<div style="margin-left:auto;font-size:.78rem;color:var(--muted);padding:3px 8px;background:var(--acc-soft);border-radius:6px">'+b.tag+'</div>'
|
||||
+'</div>'
|
||||
+'<div id="bossG4-'+b.n+'-q" style="padding:12px 14px;background:var(--acc-soft);border-radius:9px;font-size:1rem;line-height:1.55;margin-bottom:10px">'+b.q+'</div>'
|
||||
+'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">'
|
||||
+'<span style="font-family:\'JetBrains Mono\',monospace;font-size:.92rem">ответ =</span>'
|
||||
+'<input type="number" '+stepAttr+' id="bossG4-'+b.n+'-ans" class="tinp" style="width:150px;text-align:center" placeholder="'+ph+'">'
|
||||
+'<button class="btn primary" id="bossG4-'+b.n+'-go" style="background:'+b.color+';border-color:'+b.color+'">Атаковать</button>'
|
||||
+'<button class="btn" id="bossG4-'+b.n+'-hint">Подсказка</button>'
|
||||
+'</div>'
|
||||
+'<div class="feedback" id="bossG4-'+b.n+'-fb"></div>'
|
||||
+'</div>';
|
||||
}).join('');
|
||||
renderMath(cont);
|
||||
|
||||
function markDefeatedUI(b, idx){
|
||||
const card = document.getElementById('bossG4-'+b.n+'-card');
|
||||
const goBtn = document.getElementById('bossG4-'+b.n+'-go');
|
||||
const ansInp = document.getElementById('bossG4-'+b.n+'-ans');
|
||||
if(!card || !goBtn || !ansInp) return;
|
||||
card.style.background = 'linear-gradient(135deg,var(--acc-soft),var(--pri-soft))';
|
||||
card.style.boxShadow = '0 0 0 2px '+b.color+'33, 0 8px 24px rgba(16,185,129,.12)';
|
||||
goBtn.disabled = true; goBtn.style.opacity = .55;
|
||||
goBtn.innerHTML = '<svg class="ic" viewBox="0 0 24 24" style="margin-right:4px"><polyline points="20 6 9 17 4 12"/></svg> Повержен';
|
||||
ansInp.disabled = true;
|
||||
}
|
||||
|
||||
function refreshOverall(){
|
||||
const won = BOSS_STATE.filter(s => s.defeated).length;
|
||||
const txt = document.getElementById('ch4G-boss-overall');
|
||||
const fill = document.getElementById('ch4G-boss-overall-fill');
|
||||
if(txt) txt.textContent = won + ' / ' + BOSSES.length + ' боссов побеждено';
|
||||
if(fill) fill.style.width = (won * 100 / BOSSES.length) + '%';
|
||||
if(won >= BOSSES.length){
|
||||
const reward = document.getElementById('ch4G-final-reward');
|
||||
if(reward && reward.style.display === 'none'){
|
||||
reward.style.display = 'block';
|
||||
if(!STATE.achievements.has('ch4_done')){
|
||||
achievement('ch4_done','Магистр многоугольников и круга');
|
||||
addXp(50, 'ch4-bonus');
|
||||
bumpProgress('final4', 10);
|
||||
if(window.confetti){ try{ window.confetti(); }catch(e){} }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOSSES.forEach((b, idx)=>{
|
||||
const goBtn = document.getElementById('bossG4-'+b.n+'-go');
|
||||
const hintBtn = document.getElementById('bossG4-'+b.n+'-hint');
|
||||
const ansInp = document.getElementById('bossG4-'+b.n+'-ans');
|
||||
if(BOSS_STATE[idx].defeated) markDefeatedUI(b, idx);
|
||||
goBtn.addEventListener('click', ()=>{
|
||||
if(BOSS_STATE[idx].defeated) return;
|
||||
const fb = document.getElementById('bossG4-'+b.n+'-fb');
|
||||
const raw = (ansInp.value||'').replace(',', '.').trim();
|
||||
const val = parseFloat(raw);
|
||||
if(isNaN(val) || raw === ''){ feedback(fb, false, '✗ Введи число.'); return; }
|
||||
const ok = Math.abs(val - b.ans) < 0.05;
|
||||
if(ok){
|
||||
BOSS_STATE[idx].defeated = true; saveBosses();
|
||||
feedback(fb, true, '✓ Босс '+b.n+' повержен! +10 XP. '+b.hint);
|
||||
addXp(10, 'boss-ch4-'+b.n);
|
||||
bumpProgress('final4', 18);
|
||||
markDefeatedUI(b, idx);
|
||||
refreshOverall();
|
||||
} else {
|
||||
feedback(fb, false, '✗ Промах. Попробуй ещё. Подсказка доступна.');
|
||||
}
|
||||
});
|
||||
hintBtn.addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('bossG4-'+b.n+'-fb');
|
||||
fb.className = 'feedback ok';
|
||||
fb.innerHTML = '<b>Подсказка:</b> '+b.hint;
|
||||
fb.style.display = 'block';
|
||||
fb.style.background = 'var(--warn-bg)';
|
||||
fb.style.color = '#92400e';
|
||||
fb.style.borderLeftColor = 'var(--warn)';
|
||||
renderMath(fb);
|
||||
});
|
||||
ansInp.addEventListener('keydown', e=>{ if(e.key === 'Enter') goBtn.click(); });
|
||||
});
|
||||
|
||||
refreshOverall();
|
||||
}
|
||||
|
||||
/* ===== Search ===== */
|
||||
|
||||
Reference in New Issue
Block a user