660e7e2747
Until now the 'gamification' feature flag did nothing: it had no row in
app_settings, the admin couldn't toggle it, awardXP/awardCoins ignored
it, and the CSS only hid three dashboard widgets — XP bars in textbooks
stayed visible regardless.
Phase 1 closes every hole.
Backend (source of truth):
• migration 029 seeds feature_gamification_enabled=1
• new isGamificationEnabled() helper in gamification/_shared.js with a
30s cache + invalidateGamificationCache() for instant admin toggles
• awardXP / awardCoins / updateStreak / unlockAchievement /
checkAchievements all bail out when the flag is off
• /api/gamification/* and /api/shop/* (user routes) return 404 when
disabled; admin routes remain open so the switch itself is reachable
• adminController.updateFeatures gains 'gamification' in the allow-list
and invalidates the cache on flip
Frontend:
• LS.isGamificationEnabled() (synchronous, populated by loadFeatures)
so xp.js + applyCosmetics can bail without a round-trip
• xp.js load/add/flush become no-ops when the flag is off
• applyCosmetics skips the round-trip when off
• CSS .no-gamification rule expanded to cover .hero-xp-badge, .po-xp,
.xp-card, .xp-bar, #frames-section, and a universal [data-gamified]
hook for future blocks
Textbooks (Variant 2 of the plan):
• backend/scripts/wrap_textbook_xp.py — idempotent script that adds
data-gamified to 167 XP tags across 63 textbook files (chapters +
hubs, all subjects/grades). Single CSS rule now hides everything.
Verified end-to-end: with the flag off, awardXP/awardCoins write nothing;
flipping back restores normal behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1525 lines
105 KiB
HTML
1525 lines
105 KiB
HTML
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||
<meta http-equiv="Pragma" content="no-cache">
|
||
<meta http-equiv="Expires" content="0">
|
||
<title>Алгебра 10 · Глава 2 · Корень n-й степени</title>
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
|
||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
|
||
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
|
||
<script src="/js/api.js" defer></script>
|
||
<script src="/js/xp.js" defer></script>
|
||
<script src="/js/alg10_svg.js?v=1" defer></script>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{
|
||
--bg:#faf5ff; --card:#fff; --card-soft:#f8f5ff; --text:#1a0f1f; --muted:#6b5b7c;
|
||
--border:#ede9fe; --sh:0 1px 3px rgba(0,0,0,.06); --sh2:0 4px 14px rgba(0,0,0,.08);
|
||
--pri:#7c3aed; --pri2:#6d28d9; --pri-soft:#ede9fe;
|
||
--acc:#a855f7; --acc2:#9333ea; --acc-soft:#e9d5ff;
|
||
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
|
||
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
|
||
}
|
||
.dark{--bg:#160a1d; --card:#1f1029; --card-soft:#281338; --text:#f3e8ff; --muted:#a08bb5; --border:#321e42}
|
||
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
|
||
html,body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.55;font-size:15px}
|
||
button,input,select,textarea{font-family:inherit;font-size:inherit}
|
||
button{cursor:pointer;border:0;background:transparent;color:inherit}
|
||
a{color:inherit;text-decoration:none}
|
||
.ic{width:16px;height:16px;display:inline-block;flex-shrink:0;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;vertical-align:middle}
|
||
|
||
.hdr{position:relative;background:linear-gradient(110deg,#3b0764 0%,#7c3aed 55%,#c4b5fd 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(237,233,254,.2);min-height:130px}
|
||
.hdr::before{content:'ГЛАВА 2';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(5rem,15vw,11rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(237,233,254,.12);line-height:1;pointer-events:none;z-index:0}
|
||
.hdr-row{position:relative;z-index:1;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
|
||
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:900;letter-spacing:-.01em;line-height:1.3;padding-top:4px}
|
||
.hdr-sub{font-size:.85rem;opacity:.88;margin-top:6px;font-weight:500;line-height:1.4}
|
||
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
||
.hdr-btn{padding:7px 12px;border-radius:9px;background:rgba(255,255,255,.14);color:#fff;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;text-decoration:none}
|
||
.hdr-btn:hover{background:rgba(255,255,255,.24)}
|
||
|
||
.main{max-width:1240px;margin:0 auto;padding:22px;width:100%;display:grid;grid-template-columns:1fr 280px;gap:24px}
|
||
@media(max-width:980px){.main{grid-template-columns:1fr;padding:14px}}
|
||
.col-main{min-width:0}
|
||
|
||
.hero{background:linear-gradient(135deg,var(--pri-soft) 0%,var(--acc-soft) 50%,var(--pri-soft) 100%);background-size:200% 200%;animation:heroShift 12s ease-in-out infinite;border:1px solid var(--border);border-radius:18px;padding:24px 22px;margin-bottom:24px;position:relative;overflow:hidden}
|
||
@keyframes heroShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
|
||
.hero::before{content:'ⁿ√';position:absolute;right:-10px;top:-20px;font-size:clamp(2rem,8vw,5.5rem);font-weight:900;color:var(--pri);opacity:.10;line-height:1;pointer-events:none;font-family:'Unbounded',sans-serif}
|
||
.hero h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px}
|
||
.hero p{font-size:.95rem;color:var(--text);opacity:.88;margin-bottom:14px;max-width:640px}
|
||
.hero-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
|
||
.btn-primary{padding:11px 22px;background:linear-gradient(135deg,var(--pri),var(--pri2));color:#fff;border-radius:11px;font-weight:700;font-size:.92rem;display:inline-flex;align-items:center;gap:8px;box-shadow:var(--sh2)}
|
||
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(124,58,237,.32)}
|
||
.hero-progress{flex:1;min-width:200px;max-width:280px}
|
||
.hp-label{font-size:.74rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;display:block;margin-bottom:5px}
|
||
.hp-bar{height:8px;background:rgba(124,58,237,.18);border-radius:5px;overflow:hidden}
|
||
.hp-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:5px;width:0%;transition:width .6s cubic-bezier(.16,1,.3,1)}
|
||
.hp-text{font-size:.78rem;color:var(--muted);font-weight:700;margin-top:4px;display:block}
|
||
.hero-xp-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:linear-gradient(135deg,var(--warn,#f59e0b),var(--pri));color:#fff;border-radius:99px;font-size:.82rem;font-weight:800;font-family:'Unbounded',sans-serif}
|
||
|
||
.psel{margin-bottom:24px}
|
||
.psel-title{font-size:.72rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:10px}
|
||
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:10px}
|
||
.psel-card{background:var(--card);border:1.5px solid var(--border);border-radius:13px;padding:14px;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s;text-align:left;position:relative}
|
||
.psel-card:hover{transform:translateY(-3px);box-shadow:var(--sh2);border-color:var(--pri)}
|
||
.psel-card.active{border-color:var(--pri);background:linear-gradient(135deg,var(--pri-soft),var(--card));box-shadow:var(--sh2)}
|
||
.psel-card.active::after{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:13px 13px 0 0}
|
||
.psel-num{font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;color:var(--pri);text-transform:uppercase;letter-spacing:.08em;margin-bottom:5px}
|
||
.psel-name{font-size:.86rem;font-weight:700;color:var(--text);line-height:1.3;margin-bottom:8px}
|
||
.psel-prog{height:4px;background:rgba(124,58,237,.10);border-radius:3px;overflow:hidden}
|
||
.psel-prog-fill{height:100%;background:var(--pri);width:0%;transition:width .4s}
|
||
.psel-card.final{background:linear-gradient(135deg,#fff5e1,#fef3c7)}
|
||
|
||
.sec[id="sec-p13"] { --sec-acc:#7c3aed; --sec-acc-d:#6d28d9; --sec-acc-soft:#ede9fe; }
|
||
.sec[id="sec-p14"] { --sec-acc:#a855f7; --sec-acc-d:#9333ea; --sec-acc-soft:#f3e8ff; }
|
||
.sec[id="sec-p15"] { --sec-acc:#c026d3; --sec-acc-d:#a21caf; --sec-acc-soft:#fae8ff; }
|
||
.sec[id="sec-p16"] { --sec-acc:#8b5cf6; --sec-acc-d:#7c3aed; --sec-acc-soft:#ede9fe; }
|
||
.sec[id="sec-p17"] { --sec-acc:#6d28d9; --sec-acc-d:#5b21b6; --sec-acc-soft:#ddd6fe; }
|
||
.sec[id="sec-final2"]{ --sec-acc:#7c3aed; --sec-acc-d:#6d28d9; --sec-acc-soft:#ede9fe; }
|
||
|
||
.sec{display:none;position:relative;animation:fadeIn .35s ease}
|
||
.sec.active{display:block}
|
||
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
|
||
.sec::before{content:attr(data-watermark);position:absolute;right:-20px;top:10%;font-family:'Unbounded',sans-serif;font-size:clamp(6rem,18vw,14rem);font-weight:900;color:transparent;-webkit-text-stroke:1.5px var(--sec-acc-soft,var(--pri-soft));line-height:1;pointer-events:none;z-index:0;opacity:.35}
|
||
.sec-header{margin-bottom:22px;padding-bottom:14px;border-bottom:2px solid var(--sec-acc-soft,var(--pri-soft));position:relative;z-index:1}
|
||
.sec-num{display:inline-block;padding:4px 10px;background:linear-gradient(135deg,var(--sec-acc,var(--pri)),var(--sec-acc-d,var(--pri2)));color:#fff;border-radius:7px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;margin-bottom:8px}
|
||
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));line-height:1.25}
|
||
|
||
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:18px 20px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04),0 8px 24px rgba(124,58,237,.06);position:relative;z-index:1}
|
||
.card-header{display:flex;align-items:center;gap:10px;margin-bottom:12px;padding-bottom:10px;border-bottom:1px dashed var(--border)}
|
||
.card-icon{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff}
|
||
.card-icon.theory{background:#8b5cf6}.card-icon.rule{background:#ec4899}.card-icon.algo{background:#f59e0b}.card-icon.example{background:#10b981}
|
||
.card-icon .ic{width:18px;height:18px}
|
||
.card-title{font-family:'Unbounded',sans-serif;font-size:.82rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);flex:1}
|
||
.card-num{font-size:.74rem;font-weight:700;color:var(--muted);background:var(--sec-acc-soft,var(--pri-soft));padding:3px 7px;border-radius:5px}
|
||
.card-body{font-size:.94rem;line-height:1.65}
|
||
.card-body p{margin-bottom:8px}
|
||
|
||
.wg{background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)));border:1.5px solid var(--sec-acc,var(--pri));border-radius:14px;padding:18px 20px;margin-bottom:18px;box-shadow:var(--sh2);position:relative;z-index:1}
|
||
.wg-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}
|
||
.wg-badge{padding:4px 9px;background:var(--sec-acc,var(--pri));color:#fff;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
|
||
.wg-title{font-family:'Unbounded',sans-serif;font-size:1.05rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));flex:1}
|
||
.wg-help{font-size:.88rem;color:var(--text);margin-bottom:12px;line-height:1.55;background:linear-gradient(135deg,var(--warn-bg,#fef3c7),var(--sec-acc-soft,var(--pri-soft)));border-left:4px solid var(--warn,#f59e0b);padding:9px 14px;border-radius:9px}
|
||
|
||
.btn{padding:8px 16px;border-radius:8px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:600;font-size:.88rem;transition:background .15s,border-color .15s}
|
||
.btn:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
|
||
.btn.primary{background:var(--sec-acc,var(--pri));color:#fff;border-color:var(--sec-acc,var(--pri))}
|
||
.btn.primary:hover{background:var(--sec-acc-d,var(--pri2));border-color:var(--sec-acc-d,var(--pri2))}
|
||
.tinp{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);font-family:'JetBrains Mono',monospace}
|
||
.tinp:focus{outline:0;border-color:var(--sec-acc,var(--pri));box-shadow:0 0 0 3px var(--sec-acc-soft,var(--pri-soft))}
|
||
|
||
.feedback{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none}
|
||
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
|
||
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
|
||
|
||
.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)}
|
||
.sidecard-row{margin-bottom:8px;font-size:.86rem;line-height:1.6}
|
||
.sidecard-row b{color:var(--pri);font-weight:700}
|
||
@media(max-width:980px){.col-side{position:static;max-height:none}}
|
||
|
||
.xp-card{background:linear-gradient(135deg,var(--acc-soft),var(--pri-soft));border:1.5px solid var(--acc);border-radius:12px;padding:14px;margin-bottom:14px}
|
||
.xp-card-title{font-size:.68rem;font-weight:800;color:var(--acc2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between}
|
||
.xp-level{font-size:1.1rem;font-weight:900;color:var(--acc2);font-family:'Unbounded',sans-serif}
|
||
.xp-bar{height:9px;background:rgba(124,58,237,.18);border-radius:6px;overflow:hidden;margin:7px 0}
|
||
.xp-fill{height:100%;background:linear-gradient(90deg,var(--acc),var(--pri));border-radius:6px;transition:width .5s cubic-bezier(.4,0,.2,1)}
|
||
.xp-nums{font-size:.74rem;color:var(--muted);display:flex;justify-content:space-between}
|
||
|
||
.spoiler{border:1px solid var(--border);border-radius:10px;background:var(--card);margin:10px 0;overflow:hidden}
|
||
.spoiler summary{padding:8px 14px;background:var(--sec-acc-soft,var(--pri-soft));font-weight:700;cursor:pointer;font-size:.88rem;color:var(--sec-acc-d,var(--pri2));list-style:none;display:flex;align-items:center;gap:8px}
|
||
.spoiler summary::-webkit-details-marker{display:none}
|
||
.spoiler summary::before{content:'+';font-size:1.2rem;font-weight:900;color:var(--sec-acc,var(--pri));width:18px}
|
||
.spoiler[open] summary::before{content:'\2212'}
|
||
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
|
||
|
||
.sec-nav{display:flex;gap:10px;margin-top:24px;padding-top:20px;border-top:1px solid var(--border);justify-content:space-between;flex-wrap:wrap}
|
||
.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
|
||
|
||
.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,#7c3aed,#a855f7);color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(124,58,237,.45);z-index:1002;display:none;align-items:center;gap:8px;max-width:340px}
|
||
.ach-popup.show{display:flex}
|
||
|
||
.score-display{display:flex;gap:14px;flex-wrap:wrap;align-items:center;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-bottom:12px}
|
||
.score-display b{color:var(--sec-acc-d,var(--pri2));font-size:1.15rem}
|
||
|
||
.hp-boss{height:14px;background:rgba(220,38,38,.12);border-radius:9px;overflow:hidden;border:1px solid #fecaca;margin:8px 0}
|
||
.hp-boss-fill{height:100%;background:linear-gradient(90deg,#dc2626,#f59e0b);border-radius:9px;transition:width .5s cubic-bezier(.4,0,.2,1)}
|
||
|
||
.col-side-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.42);z-index:9990;display:none}
|
||
.col-side-backdrop.show{display:block}
|
||
@media(max-width:980px){
|
||
.col-side{position:fixed;top:0;right:0;height:100vh;width:300px;max-width:88vw;background:var(--bg);box-shadow:-12px 0 24px rgba(0,0,0,.18);padding:18px 16px;overflow-y:auto;transform:translateX(100%);transition:transform .25s ease;z-index:9991;max-height:none}
|
||
.col-side.open{transform:none}
|
||
}
|
||
|
||
.boss-card{padding:16px;background:var(--card);border-radius:12px;border:2px solid var(--bad,#dc2626);margin-bottom:14px}
|
||
.boss-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
|
||
.boss-title{font-family:'Unbounded',sans-serif;font-weight:800;color:#7f1d1d;font-size:1.04rem;flex:1}
|
||
.boss-stage{font-size:.85rem;color:var(--muted)}
|
||
.boss-q{font-size:1rem;line-height:1.55;padding:11px 13px;background:var(--card-soft);border-radius:8px;margin-bottom:9px;border-left:3px solid var(--bad,#dc2626)}
|
||
|
||
.svg-host{display:flex;justify-content:center;margin:12px 0}
|
||
.svg-host-row{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin:12px 0}
|
||
|
||
/* Formula plates */
|
||
.formula-plate{margin:16px 0;border-radius:14px;overflow:hidden;border:1.5px solid var(--border);box-shadow:0 4px 16px rgba(0,0,0,.04);background:var(--card)}
|
||
.formula-plate-head{padding:14px 18px;text-align:center;border-bottom:1px solid var(--border);background:linear-gradient(180deg,rgba(124,58,237,.12),rgba(124,58,237,.06))}
|
||
.formula-plate-title{font-family:'Unbounded',sans-serif;font-size:1.02rem;font-weight:800;letter-spacing:.04em;margin-bottom:4px;text-transform:uppercase;color:#6d28d9}
|
||
.formula-plate-sub{font-size:.84rem;font-style:italic;color:var(--muted);line-height:1.4}
|
||
.formula-plate-body{padding:14px 22px}
|
||
.formula-row{padding:9px 4px;font-size:1.08rem;text-align:center;line-height:1.5;border-bottom:1px dashed rgba(0,0,0,.05)}
|
||
.formula-row:last-child{border-bottom:0}
|
||
.formula-row.alt{color:#0891b2}
|
||
.formula-row.danger{color:#dc2626}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header class="hdr">
|
||
<div class="hdr-row">
|
||
<div>
|
||
<h1>Алгебра 10 · Глава 2</h1>
|
||
<div class="hdr-sub">Корень n-й степени · свойства · функция y = ⁿ√x · иррациональные уравнения</div>
|
||
</div>
|
||
<div class="hdr-side">
|
||
<a href="/textbook/algebra-10" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К Алгебре 10</a>
|
||
<button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
|
||
<button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="main">
|
||
<div class="col-main">
|
||
<section class="hero">
|
||
<h2>Из квадратного корня — в корень любой степени</h2>
|
||
<p>Квадратный корень $\sqrt{x}$ — это число $y \ge 0$, что $y^2 = x$. А что если степень не $2$, а $3, 4, 5$? Этим занимается <b>корень $n$-й степени</b> $\sqrt[n]{x}$. У него есть особенности: при чётном $n$ — нужен модуль; при нечётном — корень есть из любого числа.</p>
|
||
<div class="hero-row">
|
||
<button class="btn-primary" onclick="goTo('p13')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 13</button>
|
||
<div class="hero-progress">
|
||
<span class="hp-label">Прогресс по главе</span>
|
||
<div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div>
|
||
<span id="hero-hp-text" class="hp-text">0%</span>
|
||
</div>
|
||
<div id="hero-xp-badge" class="hero-xp-badge" data-gamified></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="psel">
|
||
<div class="psel-title">Параграфы главы</div>
|
||
<div id="psel-grid" class="psel-grid"></div>
|
||
</section>
|
||
|
||
<section id="sec-p13" class="sec" data-watermark="ⁿ√"><div class="sec-header"><span class="sec-num">§ 13</span><h2 class="sec-h">Корень n-й степени из числа a</h2></div><div id="p13-body"></div></section>
|
||
<section id="sec-p14" class="sec" data-watermark="·"><div class="sec-header"><span class="sec-num">§ 14</span><h2 class="sec-h">Свойства корней n-й степени</h2></div><div id="p14-body"></div></section>
|
||
<section id="sec-p15" class="sec" data-watermark="↔"><div class="sec-header"><span class="sec-num">§ 15</span><h2 class="sec-h">Применение свойств для преобразований</h2></div><div id="p15-body"></div></section>
|
||
<section id="sec-p16" class="sec" data-watermark="∿"><div class="sec-header"><span class="sec-num">§ 16</span><h2 class="sec-h">Функция y = ⁿ√x. Свойства и график</h2></div><div id="p16-body"></div></section>
|
||
<section id="sec-p17" class="sec" data-watermark="="><div class="sec-header"><span class="sec-num">§ 17</span><h2 class="sec-h">Иррациональные уравнения</h2></div><div id="p17-body"></div></section>
|
||
<section id="sec-final2" class="sec" data-watermark="★"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#7c3aed,#c4b5fd)">Финал главы</span><h2 class="sec-h">Итоги. 4 босса главы 2</h2></div><div id="final2-body"></div></section>
|
||
</div>
|
||
|
||
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
|
||
<div class="col-side-backdrop" id="col-side-backdrop"></div>
|
||
</main>
|
||
|
||
<footer class="foot">Интерактивный учебник «Алгебра — 10 класс» · Глава 2 · Корень n-й степени · LearnSpace</footer>
|
||
|
||
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><polygon points="12,2 22,20 2,20"/></svg><span id="ach-text">Достижение!</span></div>
|
||
|
||
<script>
|
||
'use strict';
|
||
|
||
const STATE = { current:'p13', progress:{p13:0,p14:0,p15:0,p16:0,p17:0,final2:0}, achievements:new Map(), xp:0, level:1 };
|
||
const TOTAL_PARAS = 6;
|
||
const _TB_SLUG = 'algebra-10-ch2';
|
||
|
||
function calcLevel(xp){ return Math.floor(Math.sqrt((xp||0)/100))+1; }
|
||
function _xpForLevel(lv){ return (lv-1)*(lv-1)*100; }
|
||
|
||
const ACH_LABELS = {
|
||
start:'Начало главы 2!',
|
||
p13_done:'Определение корня — освоено!',
|
||
p14_done:'Свойства корней — твои!',
|
||
p15_done:'Преобразования — мастер!',
|
||
p16_done:'Функция ⁿ√x — понятна!',
|
||
p17_done:'Иррациональные уравнения — решаешь!',
|
||
ch2_done:'Глава 2 — Корни пройдена!',
|
||
root_master:'Магистр корней! +100 XP',
|
||
};
|
||
|
||
function loadProgress(){
|
||
try{
|
||
const s=localStorage.getItem('algebra10_ch2_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
|
||
const a=localStorage.getItem('algebra10_ch2_achievements');
|
||
if(a){ const p=JSON.parse(a); if(Array.isArray(p)) p.forEach(id=>STATE.achievements.set(id, ACH_LABELS[id]||id)); else if(p&&typeof p==='object'){ for(const[id,t] of Object.entries(p)) STATE.achievements.set(id,(t&&t!==id)?t:(ACH_LABELS[id]||id)); } }
|
||
STATE.xp=+(localStorage.getItem('algebra10_xp')||0); STATE.level=calcLevel(STATE.xp);
|
||
}catch(e){}
|
||
}
|
||
function saveProgress(){
|
||
try{
|
||
localStorage.setItem('algebra10_ch2_progress', JSON.stringify(STATE.progress));
|
||
localStorage.setItem('algebra10_ch2_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
|
||
localStorage.setItem('algebra10_xp', String(STATE.xp));
|
||
}catch(e){}
|
||
}
|
||
function bumpProgress(key, delta){
|
||
STATE.progress[key]=Math.max(0,Math.min(100,(STATE.progress[key]||0)+delta));
|
||
saveProgress(); refreshProgressUI();
|
||
if(STATE.progress[key]>=50) markParaRead(key);
|
||
if(STATE.progress[key]>=100){
|
||
if(key==='p13') achievement('p13_done');
|
||
else if(key==='p14') achievement('p14_done');
|
||
else if(key==='p15') achievement('p15_done');
|
||
else if(key==='p16') achievement('p16_done');
|
||
else if(key==='p17') achievement('p17_done');
|
||
else if(key==='final2') achievement('ch2_done');
|
||
}
|
||
}
|
||
|
||
const _markedRead=new Set();
|
||
let _pendingProgressBody=null, _progressTimer=null;
|
||
function _flushProgress(){
|
||
const body=_pendingProgressBody; _pendingProgressBody=null; if(!body) return;
|
||
const tok=(window.LS&&LS.getToken)?LS.getToken():''; if(!tok) return;
|
||
fetch('/api/textbooks/'+_TB_SLUG+'/progress',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+tok},body:JSON.stringify(body),keepalive:true}).catch(()=>{});
|
||
}
|
||
function _queueProgress(patch){ _pendingProgressBody=Object.assign(_pendingProgressBody||{},patch); if(_progressTimer) clearTimeout(_progressTimer); _progressTimer=setTimeout(_flushProgress, 600); }
|
||
function markLastPara(id){ _queueProgress({last_para:id}); }
|
||
function markParaRead(id){ if(_markedRead.has(id)) return; _markedRead.add(id); _queueProgress({mark_read:id}); }
|
||
window.addEventListener('beforeunload', _flushProgress);
|
||
|
||
function addXp(n,src){
|
||
if(!n) return;
|
||
const prev=STATE.level; STATE.xp=Math.max(0,(STATE.xp||0)+n); STATE.level=calcLevel(STATE.xp);
|
||
saveProgress(); refreshProgressUI();
|
||
if(window.LS&&window.LS.xp) window.LS.xp.add(n,'algebra10-ch2-'+(src||'misc'));
|
||
if(STATE.level>prev){
|
||
const pop=document.getElementById('ach-popup');
|
||
if(pop){ document.getElementById('ach-text').textContent='Уровень '+STATE.level+'!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'),2600); }
|
||
}
|
||
}
|
||
|
||
function refreshProgressUI(){
|
||
const total=Math.round(Object.values(STATE.progress).reduce((a,b)=>a+b,0)/TOTAL_PARAS);
|
||
const f=document.getElementById('hero-hp-fill'); if(f) f.style.width=total+'%';
|
||
const t=document.getElementById('hero-hp-text'); if(t) t.textContent=total+'% пройдено';
|
||
document.querySelectorAll('[data-prog-card]').forEach(el=>{ const k=el.dataset.progCard; const fl=el.querySelector('.psel-prog-fill'); if(fl) fl.style.width=(STATE.progress[k]||0)+'%'; });
|
||
const xpBadge=document.getElementById('hero-xp-badge');
|
||
if(xpBadge){ xpBadge.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:13px;height:13px"><polygon points="12 2 22 20 2 20"/></svg> Ур. '+STATE.level+' \xb7 '+(STATE.xp||0)+' XP'; }
|
||
if(STATE.current && document.getElementById('sidebar-content')){ try{ buildSidebar(STATE.current); }catch(e){} }
|
||
}
|
||
|
||
function achievement(id,text){
|
||
if(STATE.achievements.has(id)) return;
|
||
STATE.achievements.set(id, text||ACH_LABELS[id]||id); saveProgress();
|
||
const pop=document.getElementById('ach-popup');
|
||
if(pop){ document.getElementById('ach-text').textContent=text||ACH_LABELS[id]||id; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'),3300); }
|
||
addXp(20,'ach-'+id);
|
||
}
|
||
|
||
const PARAS = [
|
||
{ id:'p13', num:'§ 13', name:'Определение ⁿ√a', sub:'чётное/нечётное n' },
|
||
{ id:'p14', num:'§ 14', name:'Свойства корней', sub:'произв., частное, степень' },
|
||
{ id:'p15', num:'§ 15', name:'Преобразования', sub:'вынесение, рационализация' },
|
||
{ id:'p16', num:'§ 16', name:'y = ⁿ√x', sub:'свойства и графики' },
|
||
{ id:'p17', num:'§ 17', name:'Иррац. уравнения', sub:'возведение в степень' },
|
||
{ id:'final2', num:'★', name:'Финал главы', sub:'4 босса', final:true },
|
||
];
|
||
|
||
function buildParaSelector(){
|
||
const g=document.getElementById('psel-grid'); g.innerHTML='';
|
||
PARAS.forEach(p=>{
|
||
const card=document.createElement('div');
|
||
card.className='psel-card'+(p.final?' final':'');
|
||
card.dataset.id=p.id; card.dataset.progCard=p.id;
|
||
card.innerHTML='<div class="psel-num">'+p.num+'</div><div class="psel-name">'+p.name+'</div><div class="psel-prog"><div class="psel-prog-fill"></div></div>';
|
||
card.addEventListener('click', ()=>goTo(p.id));
|
||
g.appendChild(card);
|
||
});
|
||
if(window.renderMathInElement) try{ renderMath(g); }catch(e){}
|
||
}
|
||
|
||
const BUILT=new Set();
|
||
const BUILDERS = { p13:()=>buildP13(), p14:()=>buildP14(), p15:()=>buildP15(), p16:()=>buildP16(), p17:()=>buildP17(), final2:()=>buildFinal2() };
|
||
function ensureBuilt(id){ if(BUILT.has(id)) return; const fn=BUILDERS[id]; if(fn){ fn(); BUILT.add(id); } }
|
||
function goTo(id){
|
||
STATE.current=id; ensureBuilt(id);
|
||
document.querySelectorAll('.sec').forEach(s=>s.classList.remove('active'));
|
||
const el=document.getElementById('sec-'+id); if(el) el.classList.add('active');
|
||
document.querySelectorAll('.psel-card').forEach(c=>c.classList.toggle('active', c.dataset.id===id));
|
||
buildSidebar(id);
|
||
window.scrollTo({top:0,behavior:'smooth'});
|
||
if((STATE.progress[id]||0)<10) bumpProgress(id, 10);
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(el), 0);
|
||
markLastPara(id);
|
||
}
|
||
|
||
const SIDEBARS = {
|
||
p13:{title:'Шпаргалка §13',rows:[
|
||
['Опр.','$\\sqrt[n]{a} = b$ ⇔ $b^n = a$, $b \\ge 0$'],
|
||
['Чётное n','требует $a \\ge 0$'],
|
||
['Нечётное n','работает для любого $a$'],
|
||
['$\\sqrt[3]{-8}$','$= -2$ (нечёт., возможно)'],
|
||
['$\\sqrt[4]{-16}$','не существует'],
|
||
['Уравнение','$x^n = a$ ⇒ корней зависит от $n$ и знака $a$'],
|
||
]},
|
||
p14:{title:'Шпаргалка §14',rows:[
|
||
['Произведение','$\\sqrt[n]{ab} = \\sqrt[n]{a} \\cdot \\sqrt[n]{b}$'],
|
||
['Частное','$\\sqrt[n]{\\frac{a}{b}} = \\frac{\\sqrt[n]{a}}{\\sqrt[n]{b}}$'],
|
||
['Степень','$\\sqrt[n]{a^m} = (\\sqrt[n]{a})^m$'],
|
||
['Доумножение','$\\sqrt[n]{a} = \\sqrt[nk]{a^k}$'],
|
||
['Корень из корня','$\\sqrt[k]{\\sqrt[n]{a}} = \\sqrt[kn]{a}$'],
|
||
['$\\sqrt[n]{a^n}$','$= |a|$ (чёт.) или $a$ (нечёт.)'],
|
||
]},
|
||
p15:{title:'Шпаргалка §15',rows:[
|
||
['Вынесение','$\\sqrt[5]{160} = 2\\sqrt[5]{5}$'],
|
||
['Внесение','$2\\sqrt[3]{7} = \\sqrt[3]{56}$'],
|
||
['Рационализация','$\\frac{3}{\\sqrt[4]{8}} = \\frac{3\\sqrt[4]{2}}{2}$'],
|
||
['Сравнение','через приведение к общему показателю'],
|
||
['Сокращение','подкоренное на $k$-й степени'],
|
||
]},
|
||
p16:{title:'Шпаргалка §16',rows:[
|
||
['Чётное n','$D = [0;\\,+\\infty)$, $E = [0;\\,+\\infty)$'],
|
||
['','возрастает на $D$'],
|
||
['Нечётное n','$D = \\mathbb{R}$, $E = \\mathbb{R}$'],
|
||
['','возрастает, нечётная'],
|
||
['$y = \\sqrt[n]{x}$','обратная к $y = x^n$'],
|
||
['Чем больше n','тем график ближе к $y=1$ при $x \\to \\infty$'],
|
||
]},
|
||
p17:{title:'Шпаргалка §17',rows:[
|
||
['Метод','возвести обе части в $n$-ю степень'],
|
||
['ОДЗ','подкоренное $\\ge 0$ для чётных корней'],
|
||
['Проверка','подставить корень в исходное'],
|
||
['Посторонние','появляются при возведении'],
|
||
['$\\sqrt{f} = g$','⇔ $f = g^2$ и $g \\ge 0$'],
|
||
['Замена','часто $t = \\sqrt[n]{f(x)}$'],
|
||
]},
|
||
final2:{title:'Финал главы 2',rows:[
|
||
['Боссов','4 — все темы'],
|
||
['Босс 1','§13-§14 определение + свойства'],
|
||
['Босс 2','§15 преобразования'],
|
||
['Босс 3','§16 функция ⁿ√x'],
|
||
['Босс 4','§17 иррац. уравнения'],
|
||
['Награда','+100 XP + «Магистр корней»'],
|
||
]},
|
||
};
|
||
|
||
const TIPS=[
|
||
{sec:'p13',html:'Корень $n$-й степени из <b>отрицательного</b> числа существует <b>только при нечётном $n$</b>. Например, $\\sqrt[3]{-8} = -2$, но $\\sqrt[4]{-16}$ не существует.'},
|
||
{sec:'p14',html:'Свойства работают <b>в обе стороны</b> — и для упрощения произведения, и для разложения корня на множители. Главное: подкоренные выражения должны быть <b>неотрицательными</b> для чётных корней.'},
|
||
{sec:'p15',html:'Чтобы избавиться от иррациональности в знаменателе — умножь дробь на нужный множитель: для $\\sqrt[n]{a}$ умножай на $\\sqrt[n]{a^{n-1}}$, чтобы получить $\\sqrt[n]{a^n} = a$.'},
|
||
{sec:'p16',html:'Запомни: для <b>чётного $n$</b> функция $y = \\sqrt[n]{x}$ определена только при $x \\ge 0$. Для <b>нечётного $n$</b> — на всей оси. Все они возрастающие.'},
|
||
{sec:'p17',html:'После возведения в чётную степень <b>обязательно проверяй корни</b> подстановкой в исходное уравнение. Это исключает посторонние корни, появившиеся из-за возведения.'},
|
||
{sec:'final2',html:'4 интегрированных босса проверяют все темы главы. После победы — ачивка <b>«Магистр корней»</b> и +100 XP.'},
|
||
];
|
||
|
||
function buildSidebar(id){
|
||
const box=document.getElementById('sidebar-content');
|
||
const sb=SIDEBARS[id]||SIDEBARS.p13;
|
||
let html='';
|
||
const xpForLv=_xpForLevel(STATE.level), xpNext=_xpForLevel(STATE.level+1);
|
||
const xpInLv=STATE.xp-xpForLv, xpRange=xpNext-xpForLv;
|
||
const xpPct=xpRange>0?Math.round(xpInLv/xpRange*100):100;
|
||
html+='<div class="xp-card" data-gamified><div class="xp-card-title" data-gamified><span>XP-прогресс</span><span class="xp-level">Ур. '+STATE.level+'</span></div><div class="xp-bar"><div class="xp-fill" style="width:'+xpPct+'%"></div></div><div class="xp-nums"><span>'+STATE.xp+' XP</span><span>'+xpNext+' XP</span></div></div>';
|
||
html+='<div class="sidecard"><h4>'+sb.title+'</h4>';
|
||
sb.rows.forEach(([k,v])=>{ html+='<div class="sidecard-row"><b>'+k+'</b>'+(v?' — '+v:'')+'</div>'; });
|
||
html+='</div>';
|
||
const tip=TIPS.find(t=>t.sec===id)||TIPS[0];
|
||
html+='<div class="sidecard" style="background:linear-gradient(135deg,var(--warn-bg,#fef3c7),var(--pri-soft));border-color:var(--warn,#f59e0b)"><h4 style="color:#92400e">Подсказка</h4><div class="sidecard-row" style="font-size:.84rem;line-height:1.55">'+tip.html+'</div></div>';
|
||
if(STATE.achievements.size>0){
|
||
html+='<div class="sidecard"><h4>Достижения</h4>';
|
||
[...STATE.achievements.values()].slice(-4).forEach(text=>{ html+='<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">✓ '+text+'</div>'; });
|
||
html+='</div>';
|
||
}
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) try{ renderMath(box); }catch(e){}
|
||
}
|
||
|
||
function initTheme(){
|
||
const t=localStorage.getItem('algebra10_ch2_theme')||'light';
|
||
if(t==='dark') document.documentElement.classList.add('dark');
|
||
document.getElementById('theme-lab').textContent=t==='dark'?'Светлая':'Тёмная';
|
||
document.getElementById('theme-btn').addEventListener('click', ()=>{
|
||
document.documentElement.classList.toggle('dark');
|
||
const dark=document.documentElement.classList.contains('dark');
|
||
localStorage.setItem('algebra10_ch2_theme', dark?'dark':'light');
|
||
document.getElementById('theme-lab').textContent=dark?'Светлая':'Тёмная';
|
||
});
|
||
}
|
||
|
||
function renderMath(root){ if(window.renderMathInElement){ try{ renderMathInElement(root, {delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false}); }catch(e){} } }
|
||
function feedback(elm, ok, text){ if(!elm) return; elm.className='feedback '+(ok?'ok':'fail'); elm.innerHTML=text||(ok?'✓ Верно!':'✗ Неверно'); elm.style.display='block'; try{renderMath(elm);}catch(e){} }
|
||
|
||
const ICONS = {
|
||
theory:'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>',
|
||
algo:'<svg class="ic" viewBox="0 0 24 24"><polyline points="17 11 21 7 17 3"/><line x1="21" y1="7" x2="9" y2="7"/><polyline points="7 13 3 17 7 21"/><line x1="3" y1="17" x2="15" y2="17"/></svg>',
|
||
rule:'<svg class="ic" viewBox="0 0 24 24"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>',
|
||
example:'<svg class="ic" viewBox="0 0 24 24"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 13c1 1 2 2 2 4h4c0-2 1-3 2-4a7 7 0 0 0-4-13z"/></svg>',
|
||
};
|
||
function makeCard(kind, title, num, body){
|
||
const labels={theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример'};
|
||
return '<div class="card"><div class="card-header"><div class="card-icon '+kind+'">'+ICONS[kind]+'</div><div class="card-title">'+(labels[kind]||'')+(title&&title!==labels[kind]?' \xb7 '+title:'')+'</div>'+(num?'<div class="card-num">'+num+'</div>':'')+'</div><div class="card-body">'+body+'</div></div>';
|
||
}
|
||
function secNav(prev, next){
|
||
const NAMES={p13:'§13',p14:'§14',p15:'§15',p16:'§16',p17:'§17',final2:'Финал'};
|
||
let h='<div class="sec-nav">';
|
||
h+=prev?'<button class="btn" onclick="goTo(\''+prev+'\')"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> '+NAMES[prev]+'</button>':'<span></span>';
|
||
h+=next?'<button class="btn primary" onclick="goTo(\''+next+'\')">'+NAMES[next]+' <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>':'<span></span>';
|
||
h+='</div>'; return h;
|
||
}
|
||
|
||
function makeTrainer(opts){
|
||
let i=0, score=0;
|
||
const Q=opts.questions;
|
||
const parser = opts.parser || (v => parseFloat(String(v).replace(',','.')));
|
||
function show(){
|
||
if(i >= Q.length){
|
||
document.getElementById(opts.idPrefix+'-q').innerHTML = '<b>Готово!</b> Результат: '+score+' / '+Q.length;
|
||
if(opts.onComplete) opts.onComplete(score, Q.length);
|
||
return;
|
||
}
|
||
document.getElementById(opts.idPrefix+'-i').textContent = (i+1);
|
||
document.getElementById(opts.idPrefix+'-s').textContent = score;
|
||
document.getElementById(opts.idPrefix+'-q').innerHTML = Q[i].q;
|
||
document.getElementById(opts.idPrefix+'-ans').value = '';
|
||
renderMath(document.getElementById(opts.idPrefix+'-q'));
|
||
document.getElementById(opts.idPrefix+'-fb').style.display = 'none';
|
||
}
|
||
function go(){
|
||
if(i >= Q.length) return;
|
||
const fb = document.getElementById(opts.idPrefix+'-fb');
|
||
const raw = document.getElementById(opts.idPrefix+'-ans').value.trim();
|
||
if(raw === ''){ feedback(fb, false, '✗ Введи ответ.'); return; }
|
||
const expected = Q[i].a;
|
||
let ok = false;
|
||
if(typeof expected === 'function') ok = expected(raw);
|
||
else { const got = parser(raw); ok = !isNaN(got) && Math.abs(got - expected) < 1e-6; }
|
||
if(ok){ score++; feedback(fb, true, '✓ Верно! Дальше ▶'); }
|
||
else feedback(fb, false, '✗ Неверно. Правильно: <b>'+(Q[i].show||expected)+'</b>. Дальше ▶');
|
||
document.getElementById(opts.idPrefix+'-s').textContent = score;
|
||
i++; setTimeout(show, 1100);
|
||
}
|
||
document.getElementById(opts.idPrefix+'-go').addEventListener('click', go);
|
||
document.getElementById(opts.idPrefix+'-ans').addEventListener('keydown', e=>{ if(e.key==='Enter') go(); });
|
||
const restart = document.getElementById(opts.idPrefix+'-start');
|
||
if(restart) restart.addEventListener('click', ()=>{ i=0; score=0; show(); });
|
||
show();
|
||
}
|
||
function trainerHTML(idPrefix, total, placeholder){
|
||
return '<div class="score-display"><span>Задача <b id="'+idPrefix+'-i">1</b> / '+total+'</span><span>Очки: <b id="'+idPrefix+'-s">0</b> / '+total+'</span></div>'
|
||
+'<div id="'+idPrefix+'-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.05rem;margin-bottom:10px;text-align:center"></div>'
|
||
+'<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">'
|
||
+'<input type="text" id="'+idPrefix+'-ans" class="tinp" placeholder="'+(placeholder||'Ответ')+'" style="width:140px;text-align:center">'
|
||
+'<button class="btn primary" id="'+idPrefix+'-go">Проверить</button>'
|
||
+'<button class="btn" id="'+idPrefix+'-start">Заново</button>'
|
||
+'</div><div class="feedback" id="'+idPrefix+'-fb"></div>';
|
||
}
|
||
|
||
function makeBoss(paraId, bossDef){
|
||
const idP = paraId+'-boss';
|
||
const SKEY = 'algebra10_ch2_'+paraId+'_boss';
|
||
let st = {stage:0, defeated:false};
|
||
try{ const s=localStorage.getItem(SKEY); if(s) st=JSON.parse(s); }catch(e){}
|
||
const html = '<div class="boss-card" style="border-color:'+bossDef.color+'">'
|
||
+'<div class="boss-head">'
|
||
+'<svg viewBox="0 0 24 24" fill="none" stroke="'+bossDef.color+'" stroke-width="2.2" style="width:28px;height:28px"><polygon points="12,2 22,20 2,20"/></svg>'
|
||
+'<div class="boss-title" style="color:'+bossDef.color+'">'+bossDef.title+'</div>'
|
||
+'<div class="boss-stage" id="'+idP+'-stage">Этап 1 / '+bossDef.steps.length+'</div>'
|
||
+'</div>'
|
||
+'<div class="hp-boss" style="border-color:'+bossDef.color+'66;background:'+bossDef.color+'1a"><div class="hp-boss-fill" id="'+idP+'-fill" style="width:0%;background:linear-gradient(90deg,'+bossDef.color+',#f59e0b)"></div></div>'
|
||
+'<div class="boss-q" id="'+idP+'-q" style="border-color:'+bossDef.color+'"></div>'
|
||
+'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">'
|
||
+'<input type="text" id="'+idP+'-input" class="tinp" placeholder="Ответ" style="width:160px;text-align:center">'
|
||
+'<button class="btn primary" id="'+idP+'-go" style="background:'+bossDef.color+';border-color:'+bossDef.color+'">Атака</button>'
|
||
+'<button class="btn" id="'+idP+'-hint">Подсказка</button>'
|
||
+'<button class="btn" id="'+idP+'-restart">↻</button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="'+idP+'-fb"></div>'
|
||
+'</div>';
|
||
setTimeout(()=>{
|
||
function save(){ try{ localStorage.setItem(SKEY, JSON.stringify(st)); }catch(e){} }
|
||
function show(){
|
||
const stageEl=document.getElementById(idP+'-stage');
|
||
const fill=document.getElementById(idP+'-fill');
|
||
const q=document.getElementById(idP+'-q');
|
||
const fb=document.getElementById(idP+'-fb');
|
||
if(st.defeated){
|
||
stageEl.textContent='✓ Побеждён'; fill.style.width='100%';
|
||
q.innerHTML='<b style="color:'+bossDef.color+'">Босс повержен!</b>';
|
||
document.getElementById(idP+'-go').disabled=true;
|
||
document.getElementById(idP+'-go').style.opacity=.5;
|
||
return;
|
||
}
|
||
stageEl.textContent='Этап '+(st.stage+1)+' / '+bossDef.steps.length;
|
||
fill.style.width=(st.stage*100/bossDef.steps.length)+'%';
|
||
q.innerHTML=bossDef.steps[st.stage].q;
|
||
document.getElementById(idP+'-input').value='';
|
||
fb.style.display='none';
|
||
renderMath(q);
|
||
}
|
||
document.getElementById(idP+'-go').addEventListener('click',()=>{
|
||
if(st.defeated) return;
|
||
const step=bossDef.steps[st.stage];
|
||
const val=document.getElementById(idP+'-input').value;
|
||
const fb=document.getElementById(idP+'-fb');
|
||
if(!val.trim()){ feedback(fb,false,'✗ Введи ответ.'); return; }
|
||
if(step.verify(val)){
|
||
st.stage++;
|
||
if(st.stage>=bossDef.steps.length){
|
||
st.defeated=true; save();
|
||
feedback(fb,true,'✓ Босс повержен! +20 XP');
|
||
addXp(20,paraId+'-boss'); bumpProgress(paraId, 30);
|
||
setTimeout(show,1400);
|
||
}else{
|
||
save(); feedback(fb,true,'✓ Верно! +3 XP'); addXp(3,paraId+'-boss-step'); setTimeout(show,1100);
|
||
}
|
||
}else{ feedback(fb,false,'✗ Промах.'); }
|
||
});
|
||
document.getElementById(idP+'-hint').addEventListener('click',()=>{
|
||
if(st.defeated) return;
|
||
const fb=document.getElementById(idP+'-fb');
|
||
fb.className='feedback ok';
|
||
fb.innerHTML='<span style="color:#92400e">\u{1F4A1} Подсказка:</span> '+bossDef.steps[st.stage].hint;
|
||
fb.style.display='block';
|
||
fb.style.background='var(--warn-bg)'; fb.style.color='#92400e'; fb.style.borderLeftColor='var(--warn)';
|
||
renderMath(fb);
|
||
});
|
||
document.getElementById(idP+'-restart').addEventListener('click',()=>{
|
||
st={stage:0,defeated:false}; save();
|
||
document.getElementById(idP+'-go').disabled=false;
|
||
document.getElementById(idP+'-go').style.opacity=1;
|
||
show();
|
||
});
|
||
show();
|
||
}, 0);
|
||
return html;
|
||
}
|
||
|
||
function readButton(paraId){
|
||
return '<div style="margin-top:18px;display:flex;justify-content:center">'
|
||
+'<button class="btn primary" id="'+paraId+'-read-btn">'
|
||
+'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>'
|
||
+' Я прочитал §'+paraId.replace('p','').replace('final','финал ')+' (+10 XP)'
|
||
+'</button></div>';
|
||
}
|
||
function wireReadBtn(paraId){
|
||
document.getElementById(paraId+'-read-btn').addEventListener('click', ()=>{
|
||
addXp(10, paraId+'-read'); bumpProgress(paraId, 30);
|
||
const b=document.getElementById(paraId+'-read-btn'); b.textContent='Прочитано! +10 XP'; b.disabled=true; b.style.opacity=.6;
|
||
});
|
||
}
|
||
|
||
function initSidebarToggle(){
|
||
const side=document.getElementById('col-side'),back=document.getElementById('col-side-backdrop'),btn=document.getElementById('sidebar-btn');
|
||
if(!side||!btn) return;
|
||
function open(){ side.classList.add('open'); back.classList.add('show'); }
|
||
function close(){ side.classList.remove('open'); back.classList.remove('show'); }
|
||
btn.addEventListener('click',()=>{ if(side.classList.contains('open')) close(); else open(); });
|
||
back.addEventListener('click',close);
|
||
document.addEventListener('keydown',e=>{ if(e.key==='Escape') close(); });
|
||
}
|
||
|
||
function init(){
|
||
loadProgress(); initTheme(); initSidebarToggle();
|
||
buildParaSelector(); refreshProgressUI(); goTo('p13');
|
||
setTimeout(()=>achievement('start','Начало главы 2!'), 600);
|
||
}
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
|
||
|
||
/* ============================================================
|
||
§ 13 — Корень n-й степени из числа a
|
||
============================================================ */
|
||
function buildP13(){
|
||
const box = document.getElementById('p13-body');
|
||
const A = window.ALG10;
|
||
let html = '';
|
||
|
||
/* === SVG: графики y = xⁿ === */
|
||
let svgGraphs = '';
|
||
if(A){
|
||
const f = A.func.canvas({id:'p13-g', W:560, H:280, xRange:[-2.5, 2.5], yRange:[-6, 8], bg:'#fff'});
|
||
let s = f.open
|
||
+ f.grid({xStep:1, yStep:2, color:'#f1f5f9'})
|
||
+ f.axes({color:'#475569', xTicks:[{val:-2,label:'-2'},{val:-1,label:'-1'},{val:1,label:'1'},{val:2,label:'2'}], yTicks:[{val:-4,label:'-4'},{val:-2,label:'-2'},{val:2,label:'2'},{val:4,label:'4'},{val:6,label:'6'}]})
|
||
/* Горизонтальная линия y = 4 — пример */
|
||
+ '<line x1="0" y1="'+f.pxY(4)+'" x2="'+f.W+'" y2="'+f.pxY(4)+'" stroke="#dc2626" stroke-width="1.5" stroke-dasharray="5 3"/>'
|
||
+ '<text x="'+(f.W-50)+'" y="'+(f.pxY(4)-6)+'" font-size="11" font-family="JetBrains Mono,monospace" font-weight="700" fill="#dc2626">y = 4</text>'
|
||
/* Графики */
|
||
+ f.plot(x => x*x, {color:'#0d9488', width:2.5}) /* y=x² */
|
||
+ f.plot(x => x*x*x, {color:'#7c3aed', width:2.5}) /* y=x³ */
|
||
+ f.plot(x => Math.pow(Math.abs(x),4)*Math.sign(x*x), {color:'#0891b2', width:2.2, dash:'4 3'}) /* y=x⁴ */
|
||
+ f.plot(x => Math.pow(x,5), {color:'#dc2626', width:2.2, dash:'4 3'}) /* y=x⁵ */
|
||
/* Легенда */
|
||
+ '<rect x="20" y="20" width="92" height="92" rx="6" fill="rgba(255,255,255,.85)" stroke="#cbd5e1"/>'
|
||
+ '<line x1="30" y1="36" x2="50" y2="36" stroke="#0d9488" stroke-width="2.5"/>'
|
||
+ '<text x="56" y="40" font-size="12" font-family="JetBrains Mono,monospace" fill="#0d9488" font-weight="700">y = x²</text>'
|
||
+ '<line x1="30" y1="56" x2="50" y2="56" stroke="#7c3aed" stroke-width="2.5"/>'
|
||
+ '<text x="56" y="60" font-size="12" font-family="JetBrains Mono,monospace" fill="#7c3aed" font-weight="700">y = x³</text>'
|
||
+ '<line x1="30" y1="76" x2="50" y2="76" stroke="#0891b2" stroke-width="2.2" stroke-dasharray="4 3"/>'
|
||
+ '<text x="56" y="80" font-size="12" font-family="JetBrains Mono,monospace" fill="#0891b2" font-weight="700">y = x⁴</text>'
|
||
+ '<line x1="30" y1="96" x2="50" y2="96" stroke="#dc2626" stroke-width="2.2" stroke-dasharray="4 3"/>'
|
||
+ '<text x="56" y="100" font-size="12" font-family="JetBrains Mono,monospace" fill="#dc2626" font-weight="700">y = x⁵</text>'
|
||
+ f.close;
|
||
svgGraphs = s;
|
||
}
|
||
|
||
html += makeCard('theory', 'От квадратного корня к n-му', '13.1', `
|
||
<p>В 8 классе мы изучали <b>квадратный корень</b>: $\\sqrt{a} = b$, где $b \\ge 0$ и $b^2 = a$.</p>
|
||
<p>Естественное обобщение — <b>корень $n$-й степени</b> ($n \\ge 2$, $n \\in \\mathbb{N}$). Например:</p>
|
||
<ul style="padding-left:22px;line-height:1.85">
|
||
<li>$\\sqrt[3]{8} = 2$, потому что $2^3 = 8$;</li>
|
||
<li>$\\sqrt[4]{81} = 3$, потому что $3^4 = 81$;</li>
|
||
<li>$\\sqrt[5]{32} = 2$, потому что $2^5 = 32$.</li>
|
||
</ul>`);
|
||
|
||
html += makeCard('rule', 'Определение арифметического корня', '13.2', `
|
||
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Определение.</b> <b>Арифметическим корнем $n$-й степени</b> ($n \\ge 2$) из неотрицательного числа $a$ называется такое <b>неотрицательное</b> число $b$, что $b^n = a$. Обозначается $\\sqrt[n]{a}$.</p>
|
||
<p>Запись: $\\sqrt[n]{a} = b \\;\\Leftrightarrow\\; b \\ge 0$ и $b^n = a$.</p>
|
||
<p>Число $n$ — <b>показатель корня</b>, $a$ — <b>подкоренное выражение</b>.</p>`);
|
||
|
||
html += makeCard('rule', 'Чётные и нечётные показатели', '13.3', `
|
||
<p>Поведение корня сильно зависит от того, чётное или нечётное $n$:</p>
|
||
<table style="width:100%;border-collapse:collapse;margin:8px 0;font-size:.94rem">
|
||
<tr style="background:var(--sec-acc-soft)"><th style="padding:6px;border:1px solid var(--border);text-align:left">$n$</th><th style="padding:6px;border:1px solid var(--border);text-align:left">$a \\ge 0$</th><th style="padding:6px;border:1px solid var(--border);text-align:left">$a < 0$</th></tr>
|
||
<tr><td style="padding:6px;border:1px solid var(--border)"><b>чётное</b> ($2, 4, 6, \\ldots$)</td><td style="padding:6px;border:1px solid var(--border);color:#065f46">$\\sqrt[n]{a}$ — единственное неотр. число</td><td style="padding:6px;border:1px solid var(--border);color:#dc2626"><b>не существует</b></td></tr>
|
||
<tr><td style="padding:6px;border:1px solid var(--border)"><b>нечётное</b> ($3, 5, 7, \\ldots$)</td><td style="padding:6px;border:1px solid var(--border);color:#065f46">$\\sqrt[n]{a}$ — единственное неотр. число</td><td style="padding:6px;border:1px solid var(--border);color:#065f46"><b>существует</b>, равно $-\\sqrt[n]{|a|}$</td></tr>
|
||
</table>
|
||
<div class="svg-host">${svgGraphs}</div>
|
||
<p>На графике видно: линия $y = 4$ пересекает <b>$y = x^2$</b> в двух точках ($\\pm 2$), но <b>$y = x^3$</b> только в одной ($\\sqrt[3]{4}$).</p>
|
||
<p><b>Примеры.</b></p>
|
||
<ul style="padding-left:22px;line-height:1.85">
|
||
<li>$\\sqrt[3]{-8} = -2$, так как $(-2)^3 = -8$ (нечёт. $n$, ОК);</li>
|
||
<li>$\\sqrt[4]{-16}$ — <b>не существует</b> (чёт. $n$, отриц. $a$).</li>
|
||
</ul>`);
|
||
|
||
html += makeCard('example', 'Связь с уравнением', '13.4', `
|
||
<p>Корень $n$-й степени тесно связан с уравнением $x^n = a$:</p>
|
||
<p><b>Чётное $n$:</b></p>
|
||
<ul style="padding-left:22px;line-height:1.85">
|
||
<li>$a > 0$: <b>2 корня</b> — $x = \\pm\\sqrt[n]{a}$;</li>
|
||
<li>$a = 0$: <b>1 корень</b> — $x = 0$;</li>
|
||
<li>$a < 0$: <b>корней нет</b>.</li>
|
||
</ul>
|
||
<p><b>Нечётное $n$:</b> <b>всегда ровно 1 корень</b> — $x = \\sqrt[n]{a}$ (положительный, если $a > 0$, отрицательный, если $a < 0$).</p>`);
|
||
|
||
/* === ИНТЕРАКТИВ 1: Существует ли === */
|
||
html += '<div class="wg" id="p13-iv1">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Существует ли корень?</div></div>'
|
||
+'<div class="wg-help">Чётный корень из отрицательного числа не существует. Из 0 и положительных — существует всегда.</div>'
|
||
+'<div class="score-display"><span>Задача <b id="p13-iv1-i">1</b> / 6</span><span>Очки: <b id="p13-iv1-s">0</b> / 6</span></div>'
|
||
+'<div id="p13-iv1-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.1rem;text-align:center;margin-bottom:10px"></div>'
|
||
+'<div style="display:flex;gap:8px;justify-content:center"><button class="btn primary" id="p13-iv1-y" style="background:#10b981;border-color:#10b981">Существует</button><button class="btn primary" id="p13-iv1-n" style="background:#dc2626;border-color:#dc2626">Не существует</button></div>'
|
||
+'<div class="feedback" id="p13-iv1-fb"></div></div>';
|
||
|
||
/* === ИНТЕРАКТИВ 2: Вычисли === */
|
||
html += '<div class="wg" id="p13-iv2">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Найди значение корня</div></div>'
|
||
+'<div class="wg-help">Подбирай: какое число в $n$-й степени даст подкоренное?</div>'
|
||
+trainerHTML('p13-iv2', 8, 'число')
|
||
+'</div>';
|
||
|
||
/* === ИНТЕРАКТИВ 3: число корней уравнения === */
|
||
html += '<div class="wg" id="p13-iv3">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Сколько корней у $x^n = a$?</div></div>'
|
||
+'<div class="wg-help">Чётное n: 2 / 1 / 0 (зависит от знака a). Нечётное n: всегда 1.</div>'
|
||
+trainerHTML('p13-iv3', 6, 'число корней')
|
||
+'</div>';
|
||
|
||
/* === БОСС === */
|
||
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §13 — Определение корня</h3>';
|
||
html += makeBoss('p13', {
|
||
color:'#7c3aed',
|
||
title:'Босс §13 — Определение корня',
|
||
steps:[
|
||
{ q:'Существует ли $\\sqrt[4]{-81}$? «да» или «нет»', verify:(v)=>String(v).trim().toLowerCase().startsWith('н'), hint:'Чётное n, отрицательное a — не существует.' },
|
||
{ q:'Чему равен $\\sqrt[3]{-27}$?', verify:(v)=>+v===-3, hint:'$(-3)^3 = -27$.' },
|
||
{ q:'$\\sqrt[5]{32} = ?$', verify:(v)=>+v===2, hint:'$2^5 = 32$.' },
|
||
{ q:'Сколько корней у $x^4 = 16$?', verify:(v)=>+v===2, hint:'$x = \\pm 2$.' },
|
||
{ q:'Сколько корней у $x^7 = -128$?', verify:(v)=>+v===1, hint:'Нечётное n — всегда 1 корень.' },
|
||
]
|
||
});
|
||
|
||
html += secNav(null, 'p14') + readButton('p13');
|
||
box.innerHTML = html; renderMath(box);
|
||
|
||
/* IV1 */
|
||
(function(){
|
||
const Q=[
|
||
{ e:'$\\sqrt[4]{16}$', ok:true, why:'$2^4 = 16$.' },
|
||
{ e:'$\\sqrt[4]{-16}$', ok:false, why:'Чётное n, отриц. a — нет.' },
|
||
{ e:'$\\sqrt[3]{-27}$', ok:true, why:'$(-3)^3 = -27$.' },
|
||
{ e:'$\\sqrt[6]{0}$', ok:true, why:'$0^6 = 0$.' },
|
||
{ e:'$\\sqrt[8]{-1}$', ok:false, why:'Чётное n, отриц. a — нет.' },
|
||
{ e:'$\\sqrt[5]{-1}$', ok:true, why:'$(-1)^5 = -1$.' },
|
||
];
|
||
let i=0,score=0;
|
||
function show(){
|
||
if(i>=Q.length){ document.getElementById('p13-iv1-q').innerHTML='<b>Готово!</b> '+score+' / '+Q.length; if(score===Q.length){addXp(15,'p13-iv1');bumpProgress('p13',25);} else if(score>=4){addXp(8,'p13-iv1');bumpProgress('p13',12);} return; }
|
||
document.getElementById('p13-iv1-i').textContent=(i+1);
|
||
document.getElementById('p13-iv1-s').textContent=score;
|
||
document.getElementById('p13-iv1-q').innerHTML=Q[i].e;
|
||
renderMath(document.getElementById('p13-iv1-q'));
|
||
document.getElementById('p13-iv1-fb').style.display='none';
|
||
}
|
||
function ans(yes){
|
||
if(i>=Q.length) return;
|
||
const fb=document.getElementById('p13-iv1-fb');
|
||
if(yes===Q[i].ok){ score++; feedback(fb,true,'✓ Верно! '+Q[i].why); }
|
||
else feedback(fb,false,'✗ '+(Q[i].ok?'Существует: ':'Не существует: ')+Q[i].why);
|
||
document.getElementById('p13-iv1-s').textContent=score;
|
||
i++; setTimeout(show,1400);
|
||
}
|
||
document.getElementById('p13-iv1-y').addEventListener('click',()=>ans(true));
|
||
document.getElementById('p13-iv1-n').addEventListener('click',()=>ans(false));
|
||
show();
|
||
})();
|
||
|
||
/* IV2 */
|
||
makeTrainer({
|
||
idPrefix:'p13-iv2',
|
||
questions:[
|
||
{ q:'$\\sqrt[3]{64} = ?$', a:4 },
|
||
{ q:'$\\sqrt[4]{81} = ?$', a:3 },
|
||
{ q:'$\\sqrt[5]{32} = ?$', a:2 },
|
||
{ q:'$\\sqrt[3]{-125} = ?$', a:-5 },
|
||
{ q:'$\\sqrt[6]{1} = ?$', a:1 },
|
||
{ q:'$\\sqrt[4]{10000} = ?$', a:10 },
|
||
{ q:'$\\sqrt[5]{-1} = ?$', a:-1 },
|
||
{ q:'$\\sqrt[3]{0{,}008} = ?$', a:0.2 },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(18,'p13-iv2');bumpProgress('p13',28);} else if(s>=5){addXp(9,'p13-iv2');bumpProgress('p13',14);} }
|
||
});
|
||
|
||
/* IV3 */
|
||
makeTrainer({
|
||
idPrefix:'p13-iv3',
|
||
questions:[
|
||
{ q:'$x^4 = 16$. Сколько корней?', a:2 },
|
||
{ q:'$x^3 = 27$. Сколько корней?', a:1 },
|
||
{ q:'$x^6 = -64$. Сколько корней?', a:0 },
|
||
{ q:'$x^5 = -32$. Сколько корней?', a:1 },
|
||
{ q:'$x^8 = 0$. Сколько корней?', a:1 },
|
||
{ q:'$x^{10} = 1$. Сколько корней?', a:2 },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(15,'p13-iv3');bumpProgress('p13',25);} else if(s>=4){addXp(8,'p13-iv3');bumpProgress('p13',12);} }
|
||
});
|
||
|
||
wireReadBtn('p13');
|
||
}
|
||
|
||
|
||
/* ============================================================
|
||
§ 14 — Свойства корней n-й степени
|
||
============================================================ */
|
||
function buildP14(){
|
||
const box = document.getElementById('p14-body');
|
||
let html = '';
|
||
|
||
const plateProps = '<div class="formula-plate">'
|
||
+ '<div class="formula-plate-head">'
|
||
+ '<div class="formula-plate-title">5 основных свойств</div>'
|
||
+ '<div class="formula-plate-sub">все формулы — для неотрицательных подкоренных выражений</div>'
|
||
+ '</div>'
|
||
+ '<div class="formula-plate-body">'
|
||
+ '<div class="formula-row">$\\sqrt[n]{a \\cdot b} = \\sqrt[n]{a} \\cdot \\sqrt[n]{b}$</div>'
|
||
+ '<div class="formula-row alt">$\\sqrt[n]{\\dfrac{a}{b}} = \\dfrac{\\sqrt[n]{a}}{\\sqrt[n]{b}}$</div>'
|
||
+ '<div class="formula-row">$\\sqrt[n]{a^m} = \\left(\\sqrt[n]{a}\\right)^m$</div>'
|
||
+ '<div class="formula-row alt">$\\sqrt[nk]{a^{mk}} = \\sqrt[n]{a^m}$ (сокращение)</div>'
|
||
+ '<div class="formula-row">$\\sqrt[k]{\\sqrt[n]{a}} = \\sqrt[kn]{a}$ (корень из корня)</div>'
|
||
+ '</div>'
|
||
+ '</div>';
|
||
|
||
html += makeCard('rule', 'Основные свойства корней', '14.1', `
|
||
${plateProps}
|
||
<p>Эти свойства <b>можно применять в обе стороны</b> — для упрощения и для разложения.</p>`);
|
||
|
||
html += makeCard('rule', 'Корень из степени и модуль', '14.2', `
|
||
<p style="background:var(--warn-bg);padding:10px 14px;border-radius:8px;border-left:4px solid var(--warn)"><b>Важно!</b> Для произвольного $a$ (может быть отрицательным):</p>
|
||
<p style="text-align:center;font-size:1.15rem;margin:10px 0">$\\sqrt[n]{a^n} = \\begin{cases} |a|, & n \\text{ чётное} \\\\ a, & n \\text{ нечётное} \\end{cases}$</p>
|
||
<p>Например:</p>
|
||
<ul style="padding-left:22px;line-height:1.85">
|
||
<li>$\\sqrt{(-5)^2} = \\sqrt{25} = 5 = |-5|$;</li>
|
||
<li>$\\sqrt[3]{(-5)^3} = \\sqrt[3]{-125} = -5$.</li>
|
||
</ul>
|
||
<p>Чётный корень «выпрямляет» знак, нечётный — сохраняет.</p>`);
|
||
|
||
html += makeCard('example', 'Применение свойств', '14.3', `
|
||
<p><b>Пример 1.</b> $\\sqrt[3]{8 \\cdot 27} = \\sqrt[3]{8} \\cdot \\sqrt[3]{27} = 2 \\cdot 3 = 6$.</p>
|
||
<p><b>Пример 2.</b> $\\sqrt[4]{\\dfrac{16}{81}} = \\dfrac{\\sqrt[4]{16}}{\\sqrt[4]{81}} = \\dfrac{2}{3}$.</p>
|
||
<p><b>Пример 3.</b> $\\sqrt[6]{a^4} = \\sqrt[3]{a^2}$ (разделили оба показателя на 2).</p>
|
||
<p><b>Пример 4.</b> $\\sqrt[3]{\\sqrt{64}} = \\sqrt[6]{64} = 2$.</p>`);
|
||
|
||
/* === ИНТЕРАКТИВ 1 === */
|
||
html += '<div class="wg" id="p14-iv1">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Вычисли через свойства</div></div>'
|
||
+'<div class="wg-help">Раскладывай подкоренное на множители — степени с нужным показателем дают целое число.</div>'
|
||
+trainerHTML('p14-iv1', 8, 'число')
|
||
+'</div>';
|
||
|
||
/* === ИНТЕРАКТИВ 2 === */
|
||
html += '<div class="wg" id="p14-iv2">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">$\\sqrt[n]{a^n}$ с модулем</div></div>'
|
||
+'<div class="wg-help">Чётный корень даёт модуль, нечётный сохраняет знак.</div>'
|
||
+trainerHTML('p14-iv2', 6, 'число')
|
||
+'</div>';
|
||
|
||
/* === БОСС === */
|
||
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §14 — Свойства корней</h3>';
|
||
html += makeBoss('p14', {
|
||
color:'#a855f7',
|
||
title:'Босс §14 — Свойства корней',
|
||
steps:[
|
||
{ q:'$\\sqrt[3]{8 \\cdot 125} = ?$', verify:(v)=>+v===10, hint:'$\\sqrt[3]{8} \\cdot \\sqrt[3]{125} = 2 \\cdot 5$.' },
|
||
{ q:'$\\sqrt[4]{\\dfrac{16}{81}} = ?$ Введи как 2/3.', verify:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='2/3'||Math.abs(+v - 2/3)<0.01;}, hint:'$\\sqrt[4]{16}/\\sqrt[4]{81} = 2/3$.' },
|
||
{ q:'$\\sqrt[6]{a^6}$ при $a = -3$ = ?', verify:(v)=>+v===3, hint:'Чётный корень даёт $|a| = 3$.' },
|
||
{ q:'$\\sqrt[5]{a^5}$ при $a = -7$ = ?', verify:(v)=>+v===-7, hint:'Нечётный корень сохраняет знак.' },
|
||
{ q:'$\\sqrt{\\sqrt[3]{64}} = ?$', verify:(v)=>+v===2, hint:'$\\sqrt[6]{64} = 2$.' },
|
||
]
|
||
});
|
||
|
||
html += secNav('p13', 'p15') + readButton('p14');
|
||
box.innerHTML = html; renderMath(box);
|
||
|
||
/* IV1 */
|
||
makeTrainer({
|
||
idPrefix:'p14-iv1',
|
||
questions:[
|
||
{ q:'$\\sqrt[3]{27 \\cdot 64} = ?$', a:12 },
|
||
{ q:'$\\sqrt[4]{16 \\cdot 81} = ?$', a:6 },
|
||
{ q:'$\\sqrt[3]{\\dfrac{125}{8}} = ?$ Введи как 5/2 или 2.5.', a:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='5/2'||+v===2.5;}, show:'$5/2$' },
|
||
{ q:'$\\sqrt[5]{32 \\cdot 1024} = ?$', a:4 },
|
||
{ q:'$\\sqrt[4]{2401} = ?$ ($2401 = 7^4$)', a:7 },
|
||
{ q:'$\\sqrt{\\sqrt{16}} = ?$', a:2 },
|
||
{ q:'$\\sqrt[3]{2} \\cdot \\sqrt[3]{4} = ?$', a:2 },
|
||
{ q:'$\\dfrac{\\sqrt[4]{162}}{\\sqrt[4]{2}} = ?$ ($162/2 = 81$)', a:3 },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(20,'p14-iv1');bumpProgress('p14',32);} else if(s>=5){addXp(10,'p14-iv1');bumpProgress('p14',15);} }
|
||
});
|
||
|
||
/* IV2 */
|
||
makeTrainer({
|
||
idPrefix:'p14-iv2',
|
||
questions:[
|
||
{ q:'$\\sqrt{(-7)^2} = ?$', a:7 },
|
||
{ q:'$\\sqrt[3]{(-7)^3} = ?$', a:-7 },
|
||
{ q:'$\\sqrt[4]{(-2)^4} = ?$', a:2 },
|
||
{ q:'$\\sqrt[5]{(-3)^5} = ?$', a:-3 },
|
||
{ q:'$\\sqrt[6]{(-1)^6} = ?$', a:1 },
|
||
{ q:'$\\sqrt[7]{(-10)^7} = ?$', a:-10 },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(15,'p14-iv2');bumpProgress('p14',25);} else if(s>=4){addXp(8,'p14-iv2');bumpProgress('p14',12);} }
|
||
});
|
||
|
||
wireReadBtn('p14');
|
||
}
|
||
|
||
|
||
/* ============================================================
|
||
§ 15 — Применение свойств для преобразований
|
||
============================================================ */
|
||
function buildP15(){
|
||
const box = document.getElementById('p15-body');
|
||
let html = '';
|
||
|
||
html += makeCard('algo', 'Вынесение множителя за знак корня', '15.1', `
|
||
<p><b>Идея:</b> разложи подкоренное на множители так, чтобы один из них был степенью с показателем, равным показателю корня.</p>
|
||
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Пример.</b> $\\sqrt[5]{160}$.</p>
|
||
<p>$160 = 32 \\cdot 5 = 2^5 \\cdot 5$. Тогда $\\sqrt[5]{160} = \\sqrt[5]{2^5 \\cdot 5} = 2\\sqrt[5]{5}$.</p>
|
||
<p><b>Алгоритм (4 шага):</b></p>
|
||
<ol style="padding-left:22px;line-height:1.9">
|
||
<li>Разложи подкоренное на множители.</li>
|
||
<li>Найди множитель, который является степенью с показателем $n$.</li>
|
||
<li>Вынеси корень $n$-й степени из этого множителя.</li>
|
||
<li>Запиши: коэффициент перед корнем + оставшийся корень.</li>
|
||
</ol>`);
|
||
|
||
html += makeCard('algo', 'Внесение множителя под знак корня', '15.2', `
|
||
<p>Обратное действие. Чтобы внести положительный множитель $a$ под корень $n$-й степени, представь его как $\\sqrt[n]{a^n}$.</p>
|
||
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Пример.</b> $2\\sqrt[3]{7} = \\sqrt[3]{2^3} \\cdot \\sqrt[3]{7} = \\sqrt[3]{8 \\cdot 7} = \\sqrt[3]{56}$.</p>
|
||
<p><b>Внимание:</b> если $a < 0$ и $n$ чётное, то $a \\cdot \\sqrt[n]{b} = -\\sqrt[n]{a^n b}$ (знак минус остаётся снаружи).</p>`);
|
||
|
||
html += makeCard('algo', 'Избавление от иррациональности в знаменателе', '15.3', `
|
||
<p>Дробь вида $\\dfrac{c}{\\sqrt[n]{a}}$ можно «рационализировать» — превратить в дробь без корня в знаменателе.</p>
|
||
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Правило:</b> умножь числитель и знаменатель на $\\sqrt[n]{a^{n-1}}$. Тогда в знаменателе будет $\\sqrt[n]{a^n} = a$.</p>
|
||
<p><b>Пример 1.</b> $\\dfrac{3}{\\sqrt{2}} = \\dfrac{3 \\cdot \\sqrt{2}}{\\sqrt{2} \\cdot \\sqrt{2}} = \\dfrac{3\\sqrt{2}}{2}$.</p>
|
||
<p><b>Пример 2.</b> $\\dfrac{1}{\\sqrt[3]{4}} = \\dfrac{\\sqrt[3]{16}}{\\sqrt[3]{4 \\cdot 16}} = \\dfrac{\\sqrt[3]{16}}{\\sqrt[3]{64}} = \\dfrac{\\sqrt[3]{16}}{4}$.</p>
|
||
<details class="spoiler"><summary>Случай разности корней</summary>
|
||
<div class="spoiler-body">
|
||
<p>Для дроби $\\dfrac{c}{\\sqrt{a} - \\sqrt{b}}$ умножь на <b>сопряжённое</b> $\\sqrt{a} + \\sqrt{b}$:</p>
|
||
<p>$\\dfrac{c}{\\sqrt{a} - \\sqrt{b}} = \\dfrac{c(\\sqrt{a} + \\sqrt{b})}{(\\sqrt{a})^2 - (\\sqrt{b})^2} = \\dfrac{c(\\sqrt{a} + \\sqrt{b})}{a - b}$.</p>
|
||
</div></details>`);
|
||
|
||
html += makeCard('example', 'Сравнение значений корней', '15.4', `
|
||
<p>Чтобы сравнить $\\sqrt[n]{a}$ и $\\sqrt[m]{b}$, приведи их к <b>общему показателю</b> (НОК от $n$ и $m$).</p>
|
||
<p><b>Пример.</b> Сравни $\\sqrt[3]{5}$ и $\\sqrt[4]{10}$.</p>
|
||
<p>Общий показатель: $\\text{НОК}(3, 4) = 12$.</p>
|
||
<p>$\\sqrt[3]{5} = \\sqrt[12]{5^4} = \\sqrt[12]{625}$.</p>
|
||
<p>$\\sqrt[4]{10} = \\sqrt[12]{10^3} = \\sqrt[12]{1000}$.</p>
|
||
<p>$625 < 1000$, значит $\\sqrt[3]{5} < \\sqrt[4]{10}$.</p>`);
|
||
|
||
/* === ИНТЕРАКТИВ 1: Вынеси === */
|
||
html += '<div class="wg" id="p15-iv1">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Вынеси множитель</div></div>'
|
||
+'<div class="wg-help">Ответ в виде «k root» — целое k перед оставшимся корнем. Например, $2\\sqrt[5]{5}$ → введи 2.</div>'
|
||
+trainerHTML('p15-iv1', 6, 'коэф. k')
|
||
+'</div>';
|
||
|
||
/* === ИНТЕРАКТИВ 2: Внеси === */
|
||
html += '<div class="wg" id="p15-iv2">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Внеси множитель</div></div>'
|
||
+'<div class="wg-help">Возведи коэффициент в степень показателя корня и умножь на подкоренное.</div>'
|
||
+trainerHTML('p15-iv2', 5, 'число под корнем')
|
||
+'</div>';
|
||
|
||
/* === ИНТЕРАКТИВ 3: Рационализация === */
|
||
html += '<div class="wg" id="p15-iv3">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Избавься от иррациональности</div></div>'
|
||
+'<div class="wg-help">Умножь на нужный множитель так, чтобы в знаменателе осталось целое число.</div>'
|
||
+trainerHTML('p15-iv3', 5, 'знаменатель')
|
||
+'</div>';
|
||
|
||
/* === БОСС === */
|
||
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §15 — Преобразования</h3>';
|
||
html += makeBoss('p15', {
|
||
color:'#c026d3',
|
||
title:'Босс §15 — Преобразования',
|
||
steps:[
|
||
{ q:'Вынеси: $\\sqrt[3]{54} = k\\sqrt[3]{2}$. Введи k.', verify:(v)=>+v===3, hint:'$54 = 27 \\cdot 2 = 3^3 \\cdot 2$.' },
|
||
{ q:'Внеси: $3\\sqrt[4]{5}$. Чему равно подкоренное?', verify:(v)=>+v===405, hint:'$3^4 \\cdot 5 = 81 \\cdot 5 = 405$.' },
|
||
{ q:'$\\dfrac{6}{\\sqrt{3}}$ после рационализации = $a\\sqrt{3}$. Введи a.', verify:(v)=>+v===2, hint:'$\\frac{6\\sqrt{3}}{3} = 2\\sqrt{3}$.' },
|
||
{ q:'Что больше: $\\sqrt[3]{5}$ или $\\sqrt{3}$? Введи: 1 (если первое) или 2.', verify:(v)=>+v===1, hint:'$\\sqrt[3]{5} = \\sqrt[6]{25}$, $\\sqrt{3} = \\sqrt[6]{27}$. Нет, тогда второе. Хм, проверим: $\\sqrt[6]{25} < \\sqrt[6]{27}$, значит $\\sqrt[3]{5} < \\sqrt{3}$. Ответ 2.', a:2 },
|
||
{ q:'$\\dfrac{1}{\\sqrt[3]{9}}$ после рационализации = $\\dfrac{\\sqrt[3]{?}}{3}$. Введи подкоренное.', verify:(v)=>+v===3, hint:'Умножь на $\\sqrt[3]{3}$ в числителе и знаменателе: $\\frac{\\sqrt[3]{3}}{\\sqrt[3]{27}} = \\frac{\\sqrt[3]{3}}{3}$.' },
|
||
]
|
||
});
|
||
|
||
html += secNav('p14', 'p16') + readButton('p15');
|
||
box.innerHTML = html; renderMath(box);
|
||
|
||
/* IV1 */
|
||
makeTrainer({
|
||
idPrefix:'p15-iv1',
|
||
questions:[
|
||
{ q:'$\\sqrt[3]{16} = k\\sqrt[3]{2}$. Введи k.', a:2, show:'$2$ ($16 = 2^3 \\cdot 2$)' },
|
||
{ q:'$\\sqrt[4]{48} = k\\sqrt[4]{3}$. Введи k.', a:2, show:'$2$ ($48 = 16 \\cdot 3$)' },
|
||
{ q:'$\\sqrt[5]{96} = k\\sqrt[5]{3}$. Введи k.', a:2, show:'$2$ ($96 = 32 \\cdot 3$)' },
|
||
{ q:'$\\sqrt{72} = k\\sqrt{2}$. Введи k.', a:6, show:'$6$ ($72 = 36 \\cdot 2$)' },
|
||
{ q:'$\\sqrt[3]{250} = k\\sqrt[3]{2}$. Введи k.', a:5, show:'$5$ ($250 = 125 \\cdot 2$)' },
|
||
{ q:'$\\sqrt[4]{162} = k\\sqrt[4]{2}$. Введи k.', a:3, show:'$3$ ($162 = 81 \\cdot 2$)' },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(18,'p15-iv1');bumpProgress('p15',30);} else if(s>=4){addXp(9,'p15-iv1');bumpProgress('p15',14);} }
|
||
});
|
||
|
||
/* IV2 */
|
||
makeTrainer({
|
||
idPrefix:'p15-iv2',
|
||
questions:[
|
||
{ q:'$2\\sqrt[3]{7} = \\sqrt[3]{?}$', a:56 },
|
||
{ q:'$3\\sqrt{2} = \\sqrt{?}$', a:18 },
|
||
{ q:'$2\\sqrt[5]{3} = \\sqrt[5]{?}$', a:96 },
|
||
{ q:'$5\\sqrt[3]{2} = \\sqrt[3]{?}$', a:250 },
|
||
{ q:'$4\\sqrt{3} = \\sqrt{?}$', a:48 },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(15,'p15-iv2');bumpProgress('p15',25);} else if(s>=3){addXp(8,'p15-iv2');bumpProgress('p15',12);} }
|
||
});
|
||
|
||
/* IV3 */
|
||
makeTrainer({
|
||
idPrefix:'p15-iv3',
|
||
questions:[
|
||
{ q:'$\\dfrac{1}{\\sqrt{5}}$ → $\\dfrac{\\sqrt{5}}{?}$. Введи знаменатель.', a:5 },
|
||
{ q:'$\\dfrac{2}{\\sqrt{3}}$ → $\\dfrac{2\\sqrt{3}}{?}$.', a:3 },
|
||
{ q:'$\\dfrac{3}{\\sqrt{2}}$ → $\\dfrac{3\\sqrt{2}}{?}$.', a:2 },
|
||
{ q:'$\\dfrac{1}{\\sqrt[3]{4}}$ → $\\dfrac{\\sqrt[3]{2}}{?}$.', a:2, show:'$2$ ($\\sqrt[3]{4} \\cdot \\sqrt[3]{2} = \\sqrt[3]{8} = 2$)' },
|
||
{ q:'$\\dfrac{1}{\\sqrt{7}+\\sqrt{5}}$ → $\\dfrac{\\sqrt{7}-\\sqrt{5}}{?}$.', a:2, show:'$2$ ($(\\sqrt{7})^2 - (\\sqrt{5})^2 = 2$)' },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(15,'p15-iv3');bumpProgress('p15',25);} else if(s>=3){addXp(8,'p15-iv3');bumpProgress('p15',12);} }
|
||
});
|
||
|
||
wireReadBtn('p15');
|
||
}
|
||
|
||
|
||
/* ============================================================
|
||
§ 16 — Функция y = ⁿ√x. Свойства и график
|
||
============================================================ */
|
||
function buildP16(){
|
||
const box = document.getElementById('p16-body');
|
||
const A = window.ALG10;
|
||
let html = '';
|
||
|
||
/* === SVG: графики ⁿ√x для разных n === */
|
||
let svgEven = '', svgOdd = '';
|
||
if(A){
|
||
/* Графики для чётных n: ²√x, ⁴√x, ⁶√x (только x≥0) */
|
||
const f1 = A.func.canvas({id:'p16-ev', W:300, H:260, xRange:[-0.5, 4], yRange:[-0.5, 2.5], bg:'#fff'});
|
||
let s1 = f1.open
|
||
+ '<rect x="0" y="0" width="'+f1.W+'" height="36" fill="rgba(124,58,237,.08)"/>'
|
||
+ '<text x="'+(f1.W/2)+'" y="22" text-anchor="middle" font-size="12" font-family="Unbounded,Inter,sans-serif" font-weight="800" fill="#6d28d9">y = ⁿ√x, n чётное</text>'
|
||
+ f1.grid({xStep:1, yStep:0.5, color:'#f1f5f9'})
|
||
+ f1.axes({color:'#475569', xTicks:[{val:1,label:'1'},{val:2,label:'2'},{val:3,label:'3'}], yTicks:[{val:1,label:'1'},{val:2,label:'2'}]})
|
||
+ f1.plot(x => x>=0 ? Math.sqrt(x) : NaN, {color:'#0d9488', width:2.5})
|
||
+ f1.plot(x => x>=0 ? Math.pow(x, 1/4) : NaN, {color:'#7c3aed', width:2.5})
|
||
+ f1.plot(x => x>=0 ? Math.pow(x, 1/6) : NaN, {color:'#dc2626', width:2.2, dash:'4 3'})
|
||
/* Легенда */
|
||
+ '<rect x="195" y="195" width="98" height="56" rx="6" fill="rgba(255,255,255,.92)" stroke="#cbd5e1"/>'
|
||
+ '<line x1="202" y1="210" x2="222" y2="210" stroke="#0d9488" stroke-width="2.5"/>'
|
||
+ '<text x="226" y="214" font-size="11" font-family="JetBrains Mono,monospace" fill="#0d9488" font-weight="700">²√x</text>'
|
||
+ '<line x1="202" y1="226" x2="222" y2="226" stroke="#7c3aed" stroke-width="2.5"/>'
|
||
+ '<text x="226" y="230" font-size="11" font-family="JetBrains Mono,monospace" fill="#7c3aed" font-weight="700">⁴√x</text>'
|
||
+ '<line x1="202" y1="242" x2="222" y2="242" stroke="#dc2626" stroke-width="2.2" stroke-dasharray="4 3"/>'
|
||
+ '<text x="226" y="246" font-size="11" font-family="JetBrains Mono,monospace" fill="#dc2626" font-weight="700">⁶√x</text>'
|
||
+ f1.close;
|
||
svgEven = s1;
|
||
|
||
/* Графики для нечётных n: ³√x, ⁵√x, ⁷√x (вся ось) */
|
||
const f2 = A.func.canvas({id:'p16-od', W:300, H:260, xRange:[-3, 3], yRange:[-2, 2], bg:'#fff'});
|
||
function odd(x, n){ return x>=0 ? Math.pow(x, 1/n) : -Math.pow(-x, 1/n); }
|
||
let s2 = f2.open
|
||
+ '<rect x="0" y="0" width="'+f2.W+'" height="36" fill="rgba(168,85,247,.08)"/>'
|
||
+ '<text x="'+(f2.W/2)+'" y="22" text-anchor="middle" font-size="12" font-family="Unbounded,Inter,sans-serif" font-weight="800" fill="#9333ea">y = ⁿ√x, n нечётное</text>'
|
||
+ f2.grid({xStep:1, yStep:0.5, color:'#f1f5f9'})
|
||
+ f2.axes({color:'#475569', xTicks:[{val:-2,label:'-2'},{val:-1,label:'-1'},{val:1,label:'1'},{val:2,label:'2'}], yTicks:[{val:-1,label:'-1'},{val:1,label:'1'}]})
|
||
+ f2.plot(x => odd(x, 3), {color:'#0d9488', width:2.5})
|
||
+ f2.plot(x => odd(x, 5), {color:'#7c3aed', width:2.5})
|
||
+ f2.plot(x => odd(x, 7), {color:'#dc2626', width:2.2, dash:'4 3'})
|
||
+ '<rect x="195" y="50" width="98" height="56" rx="6" fill="rgba(255,255,255,.92)" stroke="#cbd5e1"/>'
|
||
+ '<line x1="202" y1="65" x2="222" y2="65" stroke="#0d9488" stroke-width="2.5"/>'
|
||
+ '<text x="226" y="69" font-size="11" font-family="JetBrains Mono,monospace" fill="#0d9488" font-weight="700">³√x</text>'
|
||
+ '<line x1="202" y1="81" x2="222" y2="81" stroke="#7c3aed" stroke-width="2.5"/>'
|
||
+ '<text x="226" y="85" font-size="11" font-family="JetBrains Mono,monospace" fill="#7c3aed" font-weight="700">⁵√x</text>'
|
||
+ '<line x1="202" y1="97" x2="222" y2="97" stroke="#dc2626" stroke-width="2.2" stroke-dasharray="4 3"/>'
|
||
+ '<text x="226" y="101" font-size="11" font-family="JetBrains Mono,monospace" fill="#dc2626" font-weight="700">⁷√x</text>'
|
||
+ f2.close;
|
||
svgOdd = s2;
|
||
}
|
||
|
||
html += makeCard('rule', 'Свойства функции y = ⁿ√x', '16.1', `
|
||
<p>Функция $y = \\sqrt[n]{x}$ — это <b>обратная</b> к $y = x^n$ (на подходящей области). Её свойства зависят от чётности $n$.</p>
|
||
<table style="width:100%;border-collapse:collapse;margin:8px 0;font-size:.9rem">
|
||
<tr style="background:var(--sec-acc-soft)"><th style="padding:6px;border:1px solid var(--border)">Свойство</th><th style="padding:6px;border:1px solid var(--border)">$n$ чётное</th><th style="padding:6px;border:1px solid var(--border)">$n$ нечётное</th></tr>
|
||
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$D$</b></td><td style="padding:6px;border:1px solid var(--border);text-align:center">$[0;\\,+\\infty)$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\mathbb{R}$</td></tr>
|
||
<tr><td style="padding:6px;border:1px solid var(--border)"><b>$E$</b></td><td style="padding:6px;border:1px solid var(--border);text-align:center">$[0;\\,+\\infty)$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$\\mathbb{R}$</td></tr>
|
||
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Монотонность</b></td><td style="padding:6px;border:1px solid var(--border);text-align:center">возрастает</td><td style="padding:6px;border:1px solid var(--border);text-align:center">возрастает</td></tr>
|
||
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Чётность</b></td><td style="padding:6px;border:1px solid var(--border);text-align:center">— (только $x \\ge 0$)</td><td style="padding:6px;border:1px solid var(--border);text-align:center">нечётная</td></tr>
|
||
<tr><td style="padding:6px;border:1px solid var(--border)"><b>Нули</b></td><td style="padding:6px;border:1px solid var(--border);text-align:center">$x = 0$</td><td style="padding:6px;border:1px solid var(--border);text-align:center">$x = 0$</td></tr>
|
||
</table>`);
|
||
|
||
html += makeCard('rule', 'Графики для чётных и нечётных n', '16.2', `
|
||
<p>Чётные корни существуют только при $x \\ge 0$ — графики живут в правой полуплоскости:</p>
|
||
<div class="svg-host">${svgEven}</div>
|
||
<p>Нечётные корни определены для всех $x$ — графики симметричны относительно начала координат:</p>
|
||
<div class="svg-host">${svgOdd}</div>
|
||
<p><b>Закономерности:</b></p>
|
||
<ul style="padding-left:22px;line-height:1.85">
|
||
<li>Чем <b>больше $n$</b>, тем «положе» график при больших $x$ (всё ближе к 1 на интервале $[0; 1]$).</li>
|
||
<li>Все графики проходят через точки $(0; 0)$ и $(1; 1)$.</li>
|
||
<li>Для нечётных $n$ также проходят через $(-1; -1)$.</li>
|
||
</ul>`);
|
||
|
||
html += makeCard('example', 'Сравнение значений', '16.3', `
|
||
<p>Так как $y = \\sqrt[n]{x}$ возрастает на своей области, для сравнения корней одного показателя достаточно сравнить подкоренные выражения.</p>
|
||
<p>$\\sqrt[5]{8} < \\sqrt[5]{15}$, потому что $8 < 15$.</p>
|
||
<p>Для разных показателей — приводи к общему (через свойства из §14).</p>`);
|
||
|
||
/* === ИНТЕРАКТИВ 1 === */
|
||
html += '<div class="wg" id="p16-iv1">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Сравни корни</div></div>'
|
||
+'<div class="wg-help">Введи знак: <b><</b>, <b>></b> или <b>=</b>.</div>'
|
||
+trainerHTML('p16-iv1', 6, 'знак')
|
||
+'</div>';
|
||
|
||
/* === ИНТЕРАКТИВ 2 === */
|
||
html += '<div class="wg" id="p16-iv2">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Свойства y = ⁿ√x</div></div>'
|
||
+'<div class="wg-help">Используй таблицу свойств.</div>'
|
||
+trainerHTML('p16-iv2', 5, 'ответ')
|
||
+'</div>';
|
||
|
||
/* === БОСС === */
|
||
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §16 — Функция ⁿ√x</h3>';
|
||
html += makeBoss('p16', {
|
||
color:'#8b5cf6',
|
||
title:'Босс §16 — Функция ⁿ√x',
|
||
steps:[
|
||
{ q:'Какая область определения $y = \\sqrt[4]{x}$? Введи минимум допустимого $x$.', verify:(v)=>+v===0, hint:'$D = [0; +\\infty)$, минимум $= 0$.' },
|
||
{ q:'$y = \\sqrt[3]{x}$ — чётная или нечётная? Введи слово.', verify:(v)=>String(v).trim().toLowerCase().startsWith('нечёт')||String(v).trim().toLowerCase().startsWith('нечет'), hint:'$\\sqrt[3]{-x} = -\\sqrt[3]{x}$.' },
|
||
{ q:'Сравни $\\sqrt[3]{10}$ и $\\sqrt[3]{7}$. Введи 1 (если первое больше) или 2.', verify:(v)=>+v===1, hint:'Корень возрастает: $10 > 7$.' },
|
||
{ q:'Через какую точку проходят ВСЕ графики $y = \\sqrt[n]{x}$ при $x = 1$? Введи $y$.', verify:(v)=>+v===1, hint:'$\\sqrt[n]{1} = 1$ для любого $n$.' },
|
||
{ q:'Функция $y = \\sqrt[6]{x}$ возрастает или убывает? Введи слово.', verify:(v)=>String(v).trim().toLowerCase().startsWith('возр'), hint:'Все ⁿ√x — возрастают на своей области.' },
|
||
]
|
||
});
|
||
|
||
html += secNav('p15', 'p17') + readButton('p16');
|
||
box.innerHTML = html; renderMath(box);
|
||
|
||
/* IV1 */
|
||
makeTrainer({
|
||
idPrefix:'p16-iv1',
|
||
parser:(v)=>v,
|
||
questions:[
|
||
{ q:'$\\sqrt[3]{8}$ и $\\sqrt[3]{27}$', a:(v)=>String(v).trim().startsWith('<'), show:'$<$' },
|
||
{ q:'$\\sqrt[5]{32}$ и $\\sqrt[5]{16}$', a:(v)=>String(v).trim().startsWith('>'), show:'$>$' },
|
||
{ q:'$\\sqrt[4]{16}$ и $\\sqrt[4]{16}$', a:(v)=>String(v).trim().startsWith('='), show:'$=$' },
|
||
{ q:'$\\sqrt{4}$ и $\\sqrt[3]{8}$ (оба равны 2)', a:(v)=>String(v).trim().startsWith('='), show:'$=$' },
|
||
{ q:'$\\sqrt[3]{2}$ и $\\sqrt{2}$ (общий показатель 6: $\\sqrt[6]{4}$ vs $\\sqrt[6]{8}$)', a:(v)=>String(v).trim().startsWith('<'), show:'$<$' },
|
||
{ q:'$\\sqrt[5]{-32}$ и $0$', a:(v)=>String(v).trim().startsWith('<'), show:'$<$' },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(15,'p16-iv1');bumpProgress('p16',25);} else if(s>=4){addXp(8,'p16-iv1');bumpProgress('p16',12);} }
|
||
});
|
||
|
||
/* IV2 */
|
||
makeTrainer({
|
||
idPrefix:'p16-iv2',
|
||
parser:(v)=>v,
|
||
questions:[
|
||
{ q:'Сколько точек пересечения с осью $x$ у $y = \\sqrt[3]{x}$?', a:(v)=>+v===1, show:'1 (точка $0$)' },
|
||
{ q:'Сколько у $y = \\sqrt[4]{x}$?', a:(v)=>+v===1, show:'1 (точка $0$)' },
|
||
{ q:'Чему равно $\\sqrt[n]{1}$ для любого $n$?', a:(v)=>+v===1, show:'$1$' },
|
||
{ q:'$y = \\sqrt[3]{x}$ — какая область значений? Введи: «R» или конкретное число.', a:(v)=>{const s=String(v).trim().toLowerCase(); return s==='r'||s==='ℝ'||s==='все';}, show:'$\\mathbb{R}$' },
|
||
{ q:'$y = \\sqrt[6]{x}$ — какая область определения? Введи минимум.', a:(v)=>+v===0, show:'$0$ ($D = [0;+\\infty)$)' },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(15,'p16-iv2');bumpProgress('p16',25);} else if(s>=3){addXp(8,'p16-iv2');bumpProgress('p16',12);} }
|
||
});
|
||
|
||
wireReadBtn('p16');
|
||
}
|
||
|
||
|
||
/* ============================================================
|
||
§ 17 — Иррациональные уравнения
|
||
============================================================ */
|
||
function buildP17(){
|
||
const box = document.getElementById('p17-body');
|
||
let html = '';
|
||
|
||
html += makeCard('theory', 'Что такое иррациональное уравнение', '17.1', `
|
||
<p><b>Иррациональным</b> называется уравнение, в котором переменная находится <b>под знаком корня</b>.</p>
|
||
<p>Примеры:</p>
|
||
<ul style="padding-left:22px;line-height:1.85">
|
||
<li>$\\sqrt{x + 3} = 5$;</li>
|
||
<li>$\\sqrt[3]{2x - 1} = 2$;</li>
|
||
<li>$\\sqrt{x} + \\sqrt{x + 7} = 7$;</li>
|
||
<li>$\\sqrt{x - 1} - 2 = x$.</li>
|
||
</ul>`);
|
||
|
||
html += makeCard('algo', 'Метод возведения в степень', '17.2', `
|
||
<p style="background:var(--sec-acc-soft);padding:10px 14px;border-radius:8px"><b>Идея:</b> чтобы «избавиться» от корня $n$-й степени, возведи обе части в $n$-ю степень.</p>
|
||
<p><b>Алгоритм:</b></p>
|
||
<ol style="padding-left:22px;line-height:1.9">
|
||
<li><b>Уединить корень</b> в левой части (если нужно).</li>
|
||
<li><b>Возвести</b> обе части в $n$-ю степень.</li>
|
||
<li>Решить получившееся уравнение.</li>
|
||
<li><b>Обязательно проверить</b> корни подстановкой в исходное уравнение.</li>
|
||
</ol>
|
||
<p style="background:var(--warn-bg);padding:10px 14px;border-radius:8px;border-left:4px solid var(--warn)"><b>Почему проверка обязательна?</b> При возведении в чётную степень могут появиться <b>посторонние корни</b> — числа, удовлетворяющие уравнению после возведения, но <b>не</b> удовлетворяющие исходному.</p>`);
|
||
|
||
html += makeCard('example', 'Пример с проверкой', '17.3', `
|
||
<p><b>Уравнение.</b> $\\sqrt{x + 3} = 5$.</p>
|
||
<p><b>Решение.</b></p>
|
||
<ol style="padding-left:22px;line-height:1.9">
|
||
<li>Возводим в квадрат: $x + 3 = 25$.</li>
|
||
<li>$x = 22$.</li>
|
||
<li>Проверка: $\\sqrt{22 + 3} = \\sqrt{25} = 5$ ✓.</li>
|
||
</ol>
|
||
<p><b>Уравнение с подвохом.</b> $\\sqrt{x - 1} = x - 7$.</p>
|
||
<p>Возводим в квадрат: $x - 1 = (x - 7)^2 = x^2 - 14x + 49$.</p>
|
||
<p>$x^2 - 15x + 50 = 0$. Корни: $x_1 = 5, x_2 = 10$.</p>
|
||
<p><b>Проверка:</b></p>
|
||
<ul style="padding-left:22px;line-height:1.85">
|
||
<li>$x = 5$: $\\sqrt{4} = 5 - 7 = -2$. Но $\\sqrt{4} = 2 \\ne -2$. <b>Посторонний!</b></li>
|
||
<li>$x = 10$: $\\sqrt{9} = 10 - 7 = 3$. ✓</li>
|
||
</ul>
|
||
<p>Ответ: $x = 10$.</p>`);
|
||
|
||
html += makeCard('rule', 'Эквивалентность для $\\sqrt{f} = g$', '17.4', `
|
||
<p>Можно сразу записать <b>эквивалентную</b> систему:</p>
|
||
<p style="text-align:center;font-size:1.1rem;margin:10px 0">$\\sqrt{f(x)} = g(x) \\Leftrightarrow \\begin{cases} f(x) = g^2(x), \\\\ g(x) \\ge 0. \\end{cases}$</p>
|
||
<p>Условие $g(x) \\ge 0$ автоматически отсекает посторонние корни — и проверять подстановкой не нужно.</p>`);
|
||
|
||
html += makeCard('algo', 'Метод замены переменной', '17.5', `
|
||
<p>Если в уравнении встречается одно и то же корневое выражение, удобно ввести замену.</p>
|
||
<p><b>Пример.</b> $\\sqrt{x} + 6 = 5\\sqrt[4]{x}$.</p>
|
||
<p>Заметим: $\\sqrt{x} = (\\sqrt[4]{x})^2$. Пусть $t = \\sqrt[4]{x}$ ($t \\ge 0$). Тогда $t^2 + 6 = 5t$ ⇒ $t^2 - 5t + 6 = 0$ ⇒ $t = 2$ или $t = 3$.</p>
|
||
<p>Возвращаемся: $\\sqrt[4]{x} = 2$ ⇒ $x = 16$. $\\sqrt[4]{x} = 3$ ⇒ $x = 81$.</p>`);
|
||
|
||
/* === ИНТЕРАКТИВ 1: Простейшие === */
|
||
html += '<div class="wg" id="p17-iv1">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Реши простейшее уравнение</div></div>'
|
||
+'<div class="wg-help">Возведи в нужную степень, реши, проверь корни.</div>'
|
||
+trainerHTML('p17-iv1', 6, 'корень или число корней')
|
||
+'</div>';
|
||
|
||
/* === ИНТЕРАКТИВ 2: посторонние корни === */
|
||
html += '<div class="wg" id="p17-iv2">'
|
||
+'<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Сколько <b>истинных</b> корней?</div></div>'
|
||
+'<div class="wg-help">После возведения в степень может появиться больше корней. Подставь каждый и оставь только настоящие.</div>'
|
||
+trainerHTML('p17-iv2', 5, 'число корней')
|
||
+'</div>';
|
||
|
||
/* === БОСС === */
|
||
html += '<h3 style="font-family:Unbounded,sans-serif;font-size:1.05rem;color:var(--pri2);margin:20px 0 12px">Босс §17 — Иррациональные уравнения</h3>';
|
||
html += makeBoss('p17', {
|
||
color:'#6d28d9',
|
||
title:'Босс §17 — Иррац. уравнения',
|
||
steps:[
|
||
{ q:'Реши $\\sqrt{x - 5} = 3$. Введи $x$.', verify:(v)=>+v===14, hint:'Возведи в квадрат: $x - 5 = 9$.' },
|
||
{ q:'Реши $\\sqrt[3]{2x + 1} = 3$. Введи $x$.', verify:(v)=>+v===13, hint:'$2x + 1 = 27$, $x = 13$.' },
|
||
{ q:'Сколько <b>истинных</b> корней у $\\sqrt{x + 4} = x - 2$?', verify:(v)=>+v===1, hint:'$x + 4 = (x-2)^2 \\Rightarrow x^2 - 5x = 0 \\Rightarrow x = 0$ или $5$. Но $x \\ge 2$ для $g \\ge 0$. Только $x = 5$.' },
|
||
{ q:'Какое условие добавить к $\\sqrt{f(x)} = g(x)$ при возведении в квадрат? «g ≥ 0» или «g > 0»?', verify:(v)=>{const s=String(v).replace(/\\s/g,''); return s==='g≥0'||s==='g>=0'||s.toLowerCase().startsWith('g≥');}, hint:'Левая часть $\\sqrt{f} \\ge 0$, значит правая тоже.' },
|
||
{ q:'Реши $\\sqrt{x^2 - 5} = 2$. Введи положительный корень.', verify:(v)=>+v===3, hint:'$x^2 - 5 = 4$, $x^2 = 9$, $x = \\pm 3$. Положительный — 3.' },
|
||
{ q:'Заменой решаем $\\sqrt{x} - 5\\sqrt[4]{x} + 6 = 0$. Сколько корней?', verify:(v)=>+v===2, hint:'$t = \\sqrt[4]{x}$: $t^2 - 5t + 6 = 0$, $t = 2$ или $3$. $x = 16$ или $81$. Оба годятся.' },
|
||
]
|
||
});
|
||
|
||
html += secNav('p16', 'final2') + readButton('p17');
|
||
box.innerHTML = html; renderMath(box);
|
||
|
||
/* IV1 */
|
||
makeTrainer({
|
||
idPrefix:'p17-iv1',
|
||
questions:[
|
||
{ q:'$\\sqrt{x} = 4$. Корень $x = ?$', a:16 },
|
||
{ q:'$\\sqrt{x + 2} = 5$. Корень $x = ?$', a:23 },
|
||
{ q:'$\\sqrt[3]{x - 1} = 2$. Корень $x = ?$', a:9 },
|
||
{ q:'$\\sqrt{2x + 3} = 3$. Корень $x = ?$', a:3 },
|
||
{ q:'$\\sqrt{x^2} = 5$. Сколько <b>корней</b>?', a:2, show:'2 ($\\pm 5$)' },
|
||
{ q:'$\\sqrt{x - 1} = -3$. Сколько корней?', a:0, show:'0 (правая часть отрицательна, а $\\sqrt{} \\ge 0$)' },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(18,'p17-iv1');bumpProgress('p17',30);} else if(s>=4){addXp(9,'p17-iv1');bumpProgress('p17',14);} }
|
||
});
|
||
|
||
/* IV2 */
|
||
makeTrainer({
|
||
idPrefix:'p17-iv2',
|
||
questions:[
|
||
{ q:'$\\sqrt{x + 2} = x$. Сколько истинных?', a:1, show:'1 ($x = 2$; $x = -1$ — посторонний)' },
|
||
{ q:'$\\sqrt{2x + 7} = x + 2$. Сколько?', a:1, show:'1 ($x = 3$; $x = -1$ даёт $\\sqrt{5} \\ne 1$)' },
|
||
{ q:'$\\sqrt{x - 3} = x - 5$. Сколько?', a:1, show:'1 ($x = 7$; $x = 4$ даёт $1 \\ne -1$)' },
|
||
{ q:'$\\sqrt{x^2 + 8} = x + 2$. Сколько?', a:1, show:'1 ($x = 1$; $x \\ge -2$ для $g \\ge 0$)' },
|
||
{ q:'$\\sqrt{x - 1} = 1 - x$. Сколько?', a:1, show:'1 ($x = 1$; единств. где обе части = 0)' },
|
||
],
|
||
onComplete:(s,n)=>{ if(s===n){addXp(18,'p17-iv2');bumpProgress('p17',30);} else if(s>=3){addXp(9,'p17-iv2');bumpProgress('p17',14);} }
|
||
});
|
||
|
||
wireReadBtn('p17');
|
||
}
|
||
|
||
|
||
/* ============================================================
|
||
ФИНАЛ ГЛАВЫ 2 — 4 интегрированных босса
|
||
============================================================ */
|
||
const FINAL2_BOSSES = [
|
||
{
|
||
n:1, tag:'§ 13–14',
|
||
title:'Определение + свойства',
|
||
color:'#7c3aed',
|
||
steps:[
|
||
{ q:'Существует ли $\\sqrt[6]{-64}$? «да»/«нет»', verify:(v)=>String(v).trim().toLowerCase().startsWith('н'), hint:'Чётное n, отриц. a.' },
|
||
{ q:'$\\sqrt[3]{-216} = ?$', verify:(v)=>+v===-6, hint:'$(-6)^3 = -216$.' },
|
||
{ q:'$\\sqrt[4]{16 \\cdot 81} = ?$', verify:(v)=>+v===6, hint:'$\\sqrt[4]{16} \\cdot \\sqrt[4]{81} = 2 \\cdot 3$.' },
|
||
{ q:'$\\sqrt[8]{(-5)^8} = ?$', verify:(v)=>+v===5, hint:'Чётный корень → $|{-5}| = 5$.' },
|
||
{ q:'Сколько корней у $x^6 = 64$?', verify:(v)=>+v===2, hint:'$\\pm \\sqrt[6]{64} = \\pm 2$.' },
|
||
]
|
||
},
|
||
{
|
||
n:2, tag:'§ 15',
|
||
title:'Преобразования корней',
|
||
color:'#c026d3',
|
||
steps:[
|
||
{ q:'Вынеси: $\\sqrt[3]{40} = k\\sqrt[3]{5}$. Введи k.', verify:(v)=>+v===2, hint:'$40 = 8 \\cdot 5 = 2^3 \\cdot 5$.' },
|
||
{ q:'Внеси: $3\\sqrt[5]{2} = \\sqrt[5]{?}$', verify:(v)=>+v===486, hint:'$3^5 \\cdot 2 = 243 \\cdot 2 = 486$.' },
|
||
{ q:'$\\dfrac{4}{\\sqrt{2}}$ после рационализации = $a\\sqrt{2}$. Введи a.', verify:(v)=>+v===2, hint:'$\\frac{4\\sqrt{2}}{2} = 2\\sqrt{2}$.' },
|
||
{ q:'Сравни $\\sqrt[3]{4}$ и $\\sqrt{2}$. Введи 1 (если первое больше) или 2.', verify:(v)=>+v===1, hint:'$\\sqrt[3]{4} = \\sqrt[6]{16}$, $\\sqrt{2} = \\sqrt[6]{8}$. $16 > 8$.' },
|
||
{ q:'$(\\sqrt[3]{5})^6 = ?$', verify:(v)=>+v===25, hint:'$(\\sqrt[3]{5})^6 = 5^{6/3} = 5^2$.' },
|
||
]
|
||
},
|
||
{
|
||
n:3, tag:'§ 16',
|
||
title:'Функция y = ⁿ√x',
|
||
color:'#8b5cf6',
|
||
steps:[
|
||
{ q:'Область определения $y = \\sqrt[4]{x}$? Введи мин. допуст. $x$.', verify:(v)=>+v===0, hint:'$[0; +\\infty)$.' },
|
||
{ q:'$y = \\sqrt[5]{x}$ — чётная или нечётная?', verify:(v)=>String(v).trim().toLowerCase().startsWith('нечёт')||String(v).trim().toLowerCase().startsWith('нечет'), hint:'Нечётная.' },
|
||
{ q:'Все ⁿ√x возрастают или убывают?', verify:(v)=>String(v).trim().toLowerCase().startsWith('возр'), hint:'Возрастают.' },
|
||
{ q:'$\\sqrt[7]{0} = ?$', verify:(v)=>+v===0, hint:'$0^7 = 0$.' },
|
||
{ q:'Через какую точку $(1; y)$ проходят ВСЕ графики $y = \\sqrt[n]{x}$? Введи $y$.', verify:(v)=>+v===1, hint:'$\\sqrt[n]{1} = 1$.' },
|
||
]
|
||
},
|
||
{
|
||
n:4, tag:'§ 17 + синтез',
|
||
title:'Иррациональные уравнения + синтез',
|
||
color:'#6d28d9',
|
||
steps:[
|
||
{ q:'Реши $\\sqrt{2x - 1} = 5$. Введи $x$.', verify:(v)=>+v===13, hint:'$2x - 1 = 25$.' },
|
||
{ q:'Реши $\\sqrt[3]{x + 5} = -2$. Введи $x$.', verify:(v)=>+v===-13, hint:'$x + 5 = -8$.' },
|
||
{ q:'Сколько истинных корней у $\\sqrt{x + 6} = x$?', verify:(v)=>+v===1, hint:'$x + 6 = x^2 \\Rightarrow x = 3$ или $-2$. Но $x \\ge 0$ для $g \\ge 0$. Только $x = 3$.' },
|
||
{ q:'Реши заменой $t = \\sqrt{x}$ уравнение $x - 5\\sqrt{x} + 6 = 0$. Сколько корней?', verify:(v)=>+v===2, hint:'$t^2 - 5t + 6 = 0$, $t = 2$ или $3$. $x = 4$ или $9$.' },
|
||
{ q:'Чему равно $\\sqrt[3]{27} + \\sqrt[4]{16} - \\sqrt[5]{32}$?', verify:(v)=>+v===3, hint:'$3 + 2 - 2 = 3$.' },
|
||
]
|
||
},
|
||
];
|
||
|
||
function buildFinal2(){
|
||
const box = document.getElementById('final2-body');
|
||
let html = '';
|
||
|
||
/* === Hero card === */
|
||
html += '<div style="background:linear-gradient(135deg,#7c3aed,#c4b5fd);color:#fff;border-radius:18px;padding:24px 22px;margin-bottom:24px;box-shadow:0 8px 28px rgba(124,58,237,.25);position:relative;overflow:hidden">'
|
||
+'<div style="position:absolute;right:-20px;top:-30px;font-size:8rem;font-weight:900;color:rgba(255,255,255,.1);font-family:Unbounded,sans-serif;line-height:1;pointer-events:none">★</div>'
|
||
+'<div style="position:relative;z-index:1">'
|
||
+'<div style="font-size:.78rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;opacity:.85;margin-bottom:6px">ФИНАЛ ГЛАВЫ 2</div>'
|
||
+'<h2 style="font-family:Unbounded,sans-serif;font-size:1.55rem;font-weight:800;margin-bottom:8px">4 интегрированных босса</h2>'
|
||
+'<p style="font-size:.95rem;opacity:.92;margin-bottom:14px;max-width:580px">Каждый босс проверяет синтез знаний главы. Победи всех — получи ачивку <b>«Магистр корней»</b> и +100 XP.</p>'
|
||
+'<div style="display:flex;gap:12px;flex-wrap:wrap;align-items:center">'
|
||
+'<div style="padding:8px 14px;background:rgba(255,255,255,.18);border-radius:99px;font-size:.82rem;font-weight:700">★ 4 босса</div>'
|
||
+'<div style="padding:8px 14px;background:rgba(255,255,255,.18);border-radius:99px;font-size:.82rem;font-weight:700">+ до 200 XP</div>'
|
||
+'<div style="padding:8px 14px;background:rgba(255,255,255,.18);border-radius:99px;font-size:.82rem;font-weight:700">★ Финальная ачивка</div>'
|
||
+'</div></div></div>';
|
||
|
||
/* === Overall progress === */
|
||
html += '<div style="background:var(--card);border:1.5px solid var(--border);border-radius:14px;padding:16px 20px;margin-bottom:20px">'
|
||
+'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">'
|
||
+'<div style="font-family:Unbounded,sans-serif;font-size:.85rem;font-weight:800;color:var(--text);letter-spacing:.06em;text-transform:uppercase">Прогресс по боссам</div>'
|
||
+'<div id="final2-overall" style="font-size:.95rem;font-weight:700;color:var(--pri2)">0 / 4 побеждено</div>'
|
||
+'</div>'
|
||
+'<div style="height:12px;background:rgba(124,58,237,.12);border-radius:8px;overflow:hidden">'
|
||
+'<div id="final2-overall-fill" style="height:100%;width:0%;background:linear-gradient(90deg,#7c3aed,#c4b5fd);transition:width .6s cubic-bezier(.16,1,.3,1)"></div>'
|
||
+'</div></div>';
|
||
|
||
html += '<div id="final2-bosses"></div>';
|
||
|
||
/* === Celebration === */
|
||
html += '<div id="final2-cel" style="display:none;margin:24px 0;padding:24px 22px;background:linear-gradient(135deg,#fef3c7,#fde68a);border:2px solid #f59e0b;border-radius:18px;text-align:center;box-shadow:0 6px 22px rgba(245,158,11,.25)">'
|
||
+'<div style="font-size:3rem;margin-bottom:6px">★</div>'
|
||
+'<div style="font-family:Unbounded,sans-serif;font-size:1.4rem;font-weight:900;color:#92400e;margin-bottom:6px">МАГИСТР КОРНЕЙ!</div>'
|
||
+'<div style="font-size:.95rem;color:#78350f;margin-bottom:14px">Ты победил всех 4 боссов главы 2 и освоил корни n-й степени.<br>Получено: <b>+100 XP</b> и финальная ачивка.</div>'
|
||
+'<a href="/textbook/algebra-10" style="display:inline-flex;align-items:center;gap:8px;padding:11px 22px;background:linear-gradient(135deg,#7c3aed,#a855f7);color:#fff;border-radius:11px;font-weight:700;text-decoration:none">Вернуться к Алгебре 10 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px"><polyline points="9 18 15 12 9 6"/></svg></a>'
|
||
+'</div>';
|
||
|
||
html += secNav('p17', null) + readButton('final2');
|
||
box.innerHTML = html; renderMath(box);
|
||
|
||
/* === State === */
|
||
const SKEY = 'algebra10_ch2_final2_state';
|
||
let state = {};
|
||
try{ const s=localStorage.getItem(SKEY); if(s) state = JSON.parse(s); }catch(e){}
|
||
FINAL2_BOSSES.forEach(b => { if(!state['b'+b.n]) state['b'+b.n] = {stage:0, defeated:false}; });
|
||
function save(){ try{ localStorage.setItem(SKEY, JSON.stringify(state)); }catch(e){} }
|
||
function refreshOverall(){
|
||
let won = 0;
|
||
FINAL2_BOSSES.forEach(b => { if(state['b'+b.n].defeated) won++; });
|
||
document.getElementById('final2-overall').textContent = won + ' / 4 побеждено';
|
||
document.getElementById('final2-overall-fill').style.width = (won*100/4) + '%';
|
||
if(won >= 4){
|
||
document.getElementById('final2-cel').style.display = 'block';
|
||
if(STATE.progress.final2 < 100) bumpProgress('final2', 100);
|
||
if(!STATE.achievements.has('root_master')){
|
||
achievement('root_master');
|
||
addXp(100, 'root-master');
|
||
}
|
||
}
|
||
}
|
||
|
||
const cont = document.getElementById('final2-bosses');
|
||
cont.innerHTML = FINAL2_BOSSES.map(b => {
|
||
return '<div class="boss-card" id="bb-'+b.n+'-card" style="border-color:'+b.color+'">'
|
||
+'<div class="boss-head" style="flex-wrap:wrap">'
|
||
+'<svg viewBox="0 0 24 24" fill="none" stroke="'+b.color+'" stroke-width="2.2" style="width:28px;height:28px"><polygon points="12,2 22,20 2,20"/></svg>'
|
||
+'<div style="padding:3px 10px;background:'+b.color+'22;color:'+b.color+';border-radius:99px;font-family:Unbounded,sans-serif;font-size:.7rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase">'+b.tag+'</div>'
|
||
+'<div class="boss-title" style="color:'+b.color+';flex:1;min-width:0">Босс '+b.n+'. '+b.title+'</div>'
|
||
+'<div class="boss-stage" id="bb-'+b.n+'-stage">Этап 1 / '+b.steps.length+'</div>'
|
||
+'</div>'
|
||
+'<div class="hp-boss" style="border-color:'+b.color+'66;background:'+b.color+'1a"><div class="hp-boss-fill" id="bb-'+b.n+'-fill" style="width:0%;background:linear-gradient(90deg,'+b.color+',#f59e0b)"></div></div>'
|
||
+'<div class="boss-q" id="bb-'+b.n+'-q" style="border-color:'+b.color+'"></div>'
|
||
+'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">'
|
||
+'<input type="text" id="bb-'+b.n+'-input" class="tinp" placeholder="Ответ" style="width:160px;text-align:center">'
|
||
+'<button class="btn primary" id="bb-'+b.n+'-go" style="background:'+b.color+';border-color:'+b.color+'">Атака</button>'
|
||
+'<button class="btn" id="bb-'+b.n+'-hint">Подсказка</button>'
|
||
+'<button class="btn" id="bb-'+b.n+'-restart">↻</button>'
|
||
+'</div>'
|
||
+'<div class="feedback" id="bb-'+b.n+'-fb"></div>'
|
||
+'</div>';
|
||
}).join('');
|
||
if(window.renderMathInElement) try{ renderMath(cont); }catch(e){}
|
||
|
||
FINAL2_BOSSES.forEach(b => {
|
||
const stKey = 'b' + b.n;
|
||
function show(){
|
||
const st = state[stKey];
|
||
const stageEl=document.getElementById('bb-'+b.n+'-stage');
|
||
const fill=document.getElementById('bb-'+b.n+'-fill');
|
||
const q=document.getElementById('bb-'+b.n+'-q');
|
||
const fb=document.getElementById('bb-'+b.n+'-fb');
|
||
if(st.defeated){
|
||
stageEl.textContent='✓ Побеждён';
|
||
fill.style.width='100%';
|
||
q.innerHTML='<b style="color:'+b.color+'">Босс повержен!</b>';
|
||
document.getElementById('bb-'+b.n+'-go').disabled=true;
|
||
document.getElementById('bb-'+b.n+'-go').style.opacity=.5;
|
||
return;
|
||
}
|
||
stageEl.textContent='Этап '+(st.stage+1)+' / '+b.steps.length;
|
||
fill.style.width=(st.stage*100/b.steps.length)+'%';
|
||
q.innerHTML=b.steps[st.stage].q;
|
||
document.getElementById('bb-'+b.n+'-input').value='';
|
||
fb.style.display='none';
|
||
renderMath(q);
|
||
}
|
||
document.getElementById('bb-'+b.n+'-go').addEventListener('click', ()=>{
|
||
const st = state[stKey];
|
||
if(st.defeated) return;
|
||
const step=b.steps[st.stage];
|
||
const val=document.getElementById('bb-'+b.n+'-input').value;
|
||
const fb=document.getElementById('bb-'+b.n+'-fb');
|
||
if(!val.trim()){ feedback(fb,false,'✗ Введи ответ.'); return; }
|
||
if(step.verify(val)){
|
||
st.stage++;
|
||
if(st.stage>=b.steps.length){
|
||
st.defeated=true; save();
|
||
feedback(fb,true,'✓ Босс '+b.n+' повержен! +25 XP');
|
||
addXp(25,'final2-b'+b.n);
|
||
refreshOverall();
|
||
setTimeout(show, 1400);
|
||
} else {
|
||
save();
|
||
feedback(fb,true,'✓ Верно! +5 XP');
|
||
addXp(5,'final2-b'+b.n+'-step');
|
||
setTimeout(show, 1100);
|
||
}
|
||
} else {
|
||
feedback(fb,false,'✗ Промах. Подумай ещё.');
|
||
}
|
||
});
|
||
document.getElementById('bb-'+b.n+'-hint').addEventListener('click', ()=>{
|
||
const st = state[stKey];
|
||
if(st.defeated) return;
|
||
const fb=document.getElementById('bb-'+b.n+'-fb');
|
||
fb.className='feedback ok';
|
||
fb.innerHTML='<span style="color:#92400e">\u{1F4A1} Подсказка:</span> '+b.steps[st.stage].hint;
|
||
fb.style.display='block';
|
||
fb.style.background='var(--warn-bg)'; fb.style.color='#92400e'; fb.style.borderLeftColor='var(--warn)';
|
||
renderMath(fb);
|
||
});
|
||
document.getElementById('bb-'+b.n+'-restart').addEventListener('click', ()=>{
|
||
state[stKey] = {stage:0, defeated:false}; save();
|
||
document.getElementById('bb-'+b.n+'-go').disabled=false;
|
||
document.getElementById('bb-'+b.n+'-go').style.opacity=1;
|
||
show(); refreshOverall();
|
||
});
|
||
show();
|
||
});
|
||
|
||
refreshOverall();
|
||
wireReadBtn('final2');
|
||
}
|
||
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|
||
|