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>
4739 lines
393 KiB
HTML
4739 lines
393 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>Геометрия 8 · Глава 3 · Подобные треугольники</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>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<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:#fafafa; --card:#fff; --card-soft:#faf5ff; --text:#0f172a; --ink:#0f172a; --muted:#64748b;
|
||
--border:#e2e8f0; --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:#8b5cf6; --acc2:#7c3aed; --acc-soft:#ddd6fe;
|
||
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
|
||
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
|
||
}
|
||
.dark{--bg:#08030e; --card:#10071a; --card-soft:#140820; --text:#f3e8ff; --ink:#f3e8ff; --muted:#9f7ec0; --border:#2a1040}
|
||
*{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%,#a78bfa 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(167,139,250,.2);min-height:130px}
|
||
.hdr::before{content:'ГЛАВА 3';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(220,200,255,.12);line-height:1;pointer-events:none;user-select: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 h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px;letter-spacing:-.01em}
|
||
.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);transition:transform .15s,box-shadow .15s}
|
||
.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;letter-spacing:.02em;box-shadow:0 4px 12px rgba(124,58,237,.22);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(160px,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:.88rem;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,#f5f3ff,#ede9fe)}
|
||
.psel-card.final .psel-num{color:var(--warn)}
|
||
|
||
/* SECTION COLORS — purple/violet/indigo spectrum */
|
||
.sec[id="sec-p1"] { --sec-acc:#7c3aed; --sec-acc-d:#6d28d9; --sec-acc-soft:#ede9fe; }
|
||
.sec[id="sec-p2"] { --sec-acc:#8b5cf6; --sec-acc-d:#7c3aed; --sec-acc-soft:#ddd6fe; }
|
||
.sec[id="sec-p3"] { --sec-acc:#a78bfa; --sec-acc-d:#8b5cf6; --sec-acc-soft:#f3f0ff; }
|
||
.sec[id="sec-p4"] { --sec-acc:#6366f1; --sec-acc-d:#4f46e5; --sec-acc-soft:#e0e7ff; }
|
||
.sec[id="sec-p5"] { --sec-acc:#4f46e5; --sec-acc-d:#4338ca; --sec-acc-soft:#e0e7ff; }
|
||
.sec[id="sec-p6"] { --sec-acc:#7c3aed; --sec-acc-d:#6d28d9; --sec-acc-soft:#ede9fe; }
|
||
.sec[id="sec-p7"] { --sec-acc:#8b5cf6; --sec-acc-d:#7c3aed; --sec-acc-soft:#ddd6fe; }
|
||
.sec[id="sec-p8"] { --sec-acc:#c026d3; --sec-acc-d:#a21caf; --sec-acc-soft:#fae8ff; }
|
||
.sec[id="sec-p9"] { --sec-acc:#7c3aed; --sec-acc-d:#6d28d9; --sec-acc-soft:#ede9fe; }
|
||
.sec[id="sec-final3"] { --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;user-select: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.7rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));letter-spacing:-.01em;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;transition:transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s}
|
||
.card:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(0,0,0,.06),0 16px 36px rgba(124,58,237,.12)}
|
||
.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.repeat{background:#0ea5e9}.card-icon.theory{background:#8b5cf6}.card-icon.algo{background:#f59e0b}.card-icon.rule{background:#ec4899}.card-icon.example{background:#10b981}.card-icon.oral{background:#06b6d4}.card-icon.class{background:#3b82f6}.card-icon.home{background:#f97316}
|
||
.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,transform .1s}
|
||
.btn:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
|
||
.btn:active{transform:scale(.96)}
|
||
.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))}
|
||
.btn.small{padding:5px 11px;font-size:.78rem}
|
||
.tinp{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);transition:border-color .15s}
|
||
.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}
|
||
.sidecard-row:last-child{margin-bottom:0}
|
||
@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(139,92,246,.15);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}
|
||
.tbl{width:100%;border-collapse:collapse;margin:12px 0;font-size:.88rem}
|
||
.tbl th,.tbl td{padding:7px 10px;border:1px solid var(--border);text-align:center}
|
||
.tbl th{background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));font-weight:700}
|
||
|
||
.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,#7c3aed,#8b5cf6);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;animation:achIn .45s cubic-bezier(.34,1.56,.64,1) forwards;max-width:340px}
|
||
.ach-popup.show{display:flex}
|
||
@keyframes achIn{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:none}}
|
||
|
||
.dnd-pool{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;min-height:54px;transition:border-color .18s,background .18s}
|
||
.dnd-pool.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid}
|
||
.dnd-pool.col{flex-direction:column;align-items:stretch}
|
||
.dnd-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--card);border:1.5px solid var(--border);border-radius:10px;cursor:grab;user-select:none;font-size:.92rem;line-height:1.4;transition:transform .12s,box-shadow .12s,border-color .12s;touch-action:none;max-width:100%}
|
||
.dnd-chip:hover{transform:translateY(-1px);border-color:var(--sec-acc,var(--pri));box-shadow:var(--sh)}
|
||
.dnd-chip.armed{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));box-shadow:0 0 0 3px rgba(124,58,237,.22);transform:translateY(-1px)}
|
||
.dnd-chip.dragging{opacity:.28}
|
||
.dnd-chip.placed{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
|
||
.dnd-chip .dnd-x{padding:0 5px;color:var(--muted);font-weight:700;font-size:1.05rem;border-radius:4px;cursor:pointer}
|
||
.dnd-chip .dnd-x:hover{color:var(--bad,var(--fail));background:var(--fail-bg)}
|
||
.drop-box{background:var(--card);border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:90px;transition:border-color .15s,background .15s}
|
||
.drop-box:hover{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
|
||
.drop-box h5{font-family:'Unbounded',sans-serif;font-size:.78rem;color:var(--sec-acc-d,var(--pri2));margin-bottom:8px;text-transform:uppercase;letter-spacing:.05em}
|
||
.drop-box.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid;transform:scale(1.015)}
|
||
.drop-items{display:flex;flex-wrap:wrap;gap:6px;min-height:32px}
|
||
.dnd-hint{font-size:.78rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:6px}
|
||
.dnd-hint svg{width:14px;height:14px;flex-shrink:0}
|
||
.actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
|
||
.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:10px}
|
||
.sliders label{display:block;font-size:.92rem;color:var(--muted);background:var(--card);padding:8px 12px;border-radius:8px;border:1px solid var(--border);line-height:1.5}
|
||
.sliders label b{font-family:'JetBrains Mono',monospace;font-size:1.05rem;color:var(--sec-acc-d,var(--pri2));margin-left:4px}
|
||
.sliders label input[type="range"]{display:block;width:100%;margin-top:6px;accent-color:var(--sec-acc,var(--pri))}
|
||
.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}
|
||
|
||
.col-side-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.42);z-index:9990;display:none;animation:fadeIn .18s ease}
|
||
.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}
|
||
}
|
||
|
||
.gloss-term{border-bottom:1.5px dotted var(--sec-acc,var(--pri));cursor:help;color:var(--sec-acc-d,var(--pri2));font-weight:600;padding:0 1px}
|
||
.gloss-term:hover{background:var(--sec-acc-soft,var(--pri-soft));border-radius:3px}
|
||
.gloss-tip{position:fixed;max-width:320px;padding:11px 14px;background:var(--card);border:1.5px solid var(--sec-acc,var(--pri));border-radius:11px;font-size:.84rem;line-height:1.55;box-shadow:0 12px 32px rgba(0,0,0,.18);z-index:9994;display:none;pointer-events:none;color:var(--text)}
|
||
.gloss-tip.show{display:block;animation:tipIn .15s ease}
|
||
.gloss-tip b{color:var(--sec-acc-d,var(--pri2));font-size:.92rem}
|
||
@keyframes tipIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
|
||
|
||
.search-modal{position:fixed;inset:0;background:rgba(15,23,42,.55);backdrop-filter:blur(4px);z-index:9993;display:none;align-items:flex-start;justify-content:center;padding-top:14vh}
|
||
.search-modal.show{display:flex;animation:fadeIn .15s ease}
|
||
.search-box{background:var(--bg);border:1px solid var(--border);border-radius:14px;width:560px;max-width:92vw;max-height:70vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 64px rgba(0,0,0,.4)}
|
||
.search-input{padding:14px 16px;font-size:1rem;border:0;border-bottom:1px solid var(--border);background:transparent;color:var(--text);outline:none}
|
||
.search-results{flex:1;overflow-y:auto;padding:6px 0}
|
||
.search-row{display:block;padding:8px 16px;cursor:pointer;border-bottom:1px solid var(--border);text-align:left;background:transparent;border-left:0;border-right:0;border-top:0;width:100%;color:var(--text)}
|
||
.search-row:hover,.search-row.active{background:var(--sec-acc-soft,var(--pri-soft))}
|
||
.search-row .sr-kind{font-size:.7rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px}
|
||
.search-row .sr-title{font-weight:700;font-size:.92rem;color:var(--text)}
|
||
.search-row .sr-desc{font-size:.8rem;color:var(--muted);margin-top:2px}
|
||
.search-empty{padding:20px;text-align:center;color:var(--muted);font-size:.88rem}
|
||
.search-foot{padding:8px 14px;border-top:1px solid var(--border);font-size:.74rem;color:var(--muted);display:flex;gap:14px;background:var(--card-soft,transparent)}
|
||
.search-foot kbd{padding:2px 6px;background:var(--card);border:1px solid var(--border);border-radius:4px;font-family:'JetBrains Mono',monospace;font-size:.72rem}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header class="hdr">
|
||
<div class="hdr-row">
|
||
<div>
|
||
<h1>Геометрия 8 · Глава 3</h1>
|
||
<div class="hdr-sub">Подобные треугольники</div>
|
||
</div>
|
||
<div class="hdr-side">
|
||
<a href="/textbook/geometry-8" class="hdr-btn" title="К Геометрии 8 — все главы">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
|
||
К геометрии 8
|
||
</a>
|
||
<button id="search-btn" class="hdr-btn" title="Поиск (Ctrl+K)">
|
||
<svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg>
|
||
Поиск
|
||
</button>
|
||
<button id="sidebar-btn" class="hdr-btn" title="Шпаргалка">
|
||
<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" title="Сменить тему">
|
||
<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>Подобные фигуры имеют одинаковую форму, но разный размер. Ключевые инструменты: <b>теорема Фалеса</b> (обобщённая), три признака подобия треугольников, свойство <b>биссектрисы</b>. Итог — отношение площадей подобных треугольников равно квадрату коэффициента подобия.</p>
|
||
<div class="hero-row">
|
||
<button class="btn-primary" onclick="goTo('p1')">
|
||
<svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg>
|
||
Начать § 1
|
||
</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" title="Опыт" 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-p1" class="sec" data-watermark="∥"><div class="sec-header"><span class="sec-num">§ 1</span><h2 class="sec-h">Теорема Фалеса (обобщённая)</h2></div><div id="p1-body"></div></section>
|
||
<section id="sec-p2" class="sec" data-watermark="m:n"><div class="sec-header"><span class="sec-num">§ 2</span><h2 class="sec-h">Деление отрезка в отношении m : n</h2></div><div id="p2-body"></div></section>
|
||
<section id="sec-p3" class="sec" data-watermark="∼"><div class="sec-header"><span class="sec-num">§ 3</span><h2 class="sec-h">Определение подобных треугольников</h2></div><div id="p3-body"></div></section>
|
||
<section id="sec-p4" class="sec" data-watermark="∥k"><div class="sec-header"><span class="sec-num">§ 4</span><h2 class="sec-h">Свойство прямой, параллельной стороне треугольника</h2></div><div id="p4-body"></div></section>
|
||
<section id="sec-p5" class="sec" data-watermark="∠∠"><div class="sec-header"><span class="sec-num">§ 5</span><h2 class="sec-h">Первый признак подобия. Следствие</h2></div><div id="p5-body"></div></section>
|
||
<section id="sec-p6" class="sec" data-watermark="∆"><div class="sec-header"><span class="sec-num">§ 6</span><h2 class="sec-h">Второй признак подобия</h2></div><div id="p6-body"></div></section>
|
||
<section id="sec-p7" class="sec" data-watermark="∆∼"><div class="sec-header"><span class="sec-num">§ 7</span><h2 class="sec-h">Третий признак подобия</h2></div><div id="p7-body"></div></section>
|
||
<section id="sec-p8" class="sec" data-watermark="⋅"><div class="sec-header"><span class="sec-num">§ 8</span><h2 class="sec-h">Свойство биссектрисы треугольника</h2></div><div id="p8-body"></div></section>
|
||
<section id="sec-p9" class="sec" data-watermark="k²"><div class="sec-header"><span class="sec-num">§ 9</span><h2 class="sec-h">Отношение площадей подобных треугольников</h2></div><div id="p9-body"></div></section>
|
||
<section id="sec-final3" class="sec" data-watermark="★"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#7c3aed,#8b5cf6)">Финал главы</span><h2 class="sec-h">Итоги. Боссы главы 3</h2></div><div id="final3-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">Интерактивный учебник «Геометрия 8» · Глава 3 · Подобные треугольники · 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>
|
||
<div id="gloss-tip" class="gloss-tip"></div>
|
||
<div id="search-modal" class="search-modal" role="dialog" aria-label="Поиск по главе">
|
||
<div class="search-box">
|
||
<input type="text" id="search-input" class="search-input" placeholder="Поиск: признак подобия, теорема…" autocomplete="off">
|
||
<div id="search-results" class="search-results"></div>
|
||
<div class="search-foot"><span><kbd>↑↓</kbd> навигация</span><span><kbd>Enter</kbd> открыть</span><span><kbd>Esc</kbd> закрыть</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
'use strict';
|
||
const STATE={ current:'p1', progress:{p1:0,p2:0,p3:0,p4:0,p5:0,p6:0,p7:0,p8:0,p9:0,final3:0}, achievements:new Map(), xp:0, level:1 };
|
||
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:'Начало главы 3!', ch3_done:'Подобие изучено!' };
|
||
|
||
function loadProgress(){ try{ const s=localStorage.getItem('geometry8_ch3_progress');if(s)Object.assign(STATE.progress,JSON.parse(s)); const a=localStorage.getItem('geometry8_ch3_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('geometry8_xp')||0);STATE.level=calcLevel(STATE.xp); }catch(e){} }
|
||
function saveProgress(){ try{localStorage.setItem('geometry8_ch3_progress',JSON.stringify(STATE.progress));localStorage.setItem('geometry8_ch3_achievements',JSON.stringify(Object.fromEntries(STATE.achievements)));localStorage.setItem('geometry8_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); }
|
||
|
||
const _TB_SLUG='geometry-8-ch3';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 loadServerReadState(){const tok=(window.LS&&LS.getToken)?LS.getToken():'';if(!tok)return;fetch('/api/textbooks/'+_TB_SLUG,{headers:{'Authorization':'Bearer '+tok}}).then(r=>r.ok?r.json():null).then(d=>{if(!d||!d.progress)return;(d.progress.read||[]).forEach(k=>{_markedRead.add(k);if((STATE.progress[k]||0)<50)STATE.progress[k]=100;});saveProgress();refreshProgressUI();}).catch(()=>{});}
|
||
|
||
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,'geometry8-ch3-'+(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);}if(window.confetti)try{confetti();}catch(e){}}}
|
||
|
||
const TOTAL_PARAS=10;
|
||
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:'p1',num:'§ 1',name:'Теорема Фалеса (обобщённая)',sub:'Параллельные и пропорции'},
|
||
{id:'p2',num:'§ 2',name:'Деление отрезка m:n',sub:'Внутреннее и внешнее'},
|
||
{id:'p3',num:'§ 3',name:'Подобные треугольники',sub:'Определение и коэффициент'},
|
||
{id:'p4',num:'§ 4',name:'Прямая || стороне',sub:'Отсекает подобный треугольник'},
|
||
{id:'p5',num:'§ 5',name:'1-й признак подобия',sub:'По двум углам (УУ)'},
|
||
{id:'p6',num:'§ 6',name:'2-й признак подобия',sub:'По двум сторонам и углу (СУС)'},
|
||
{id:'p7',num:'§ 7',name:'3-й признак подобия',sub:'По трём сторонам (ССС)'},
|
||
{id:'p8',num:'§ 8',name:'Биссектриса треугольника',sub:'Делит сторону пропорционально'},
|
||
{id:'p9',num:'§ 9',name:'Отношение площадей',sub:'S₁/S₂ = k²'},
|
||
{id:'final3',num:'★',name:'Финал главы',sub:'Итоги · Боссы',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);});}
|
||
|
||
const BUILT=new Set();
|
||
const BUILDERS={p1:()=>buildP1(),p2:()=>buildP2(),p3:()=>buildP3(),p4:()=>buildP4(),p5:()=>buildP5(),p6:()=>buildP6(),p7:()=>buildP7(),p8:()=>buildP8(),p9:()=>buildP9(),final3:()=>buildFinal3()};
|
||
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);setTimeout(()=>{try{wrapGlossary(el);}catch(e){}},60);markLastPara(id);}
|
||
|
||
const SIDEBARS={
|
||
p1:{title:'Шпаргалка § 1',rows:[['Теорема Фалеса','параллельные прямые пропорционально рассекают две прямые'],['Следствие','прямая || стороне треугольника отсекает подобный треугольник']]},
|
||
p2:{title:'Шпаргалка § 2',rows:[['Внутреннее деление','точка между крайними'],['Отношение','$AM:MB = m:n$']]},
|
||
p3:{title:'Шпаргалка § 3',rows:[['Подобие','$\\triangle ABC \\sim \\triangle A\'B\'C\'$'],['Коэффициент','$k = AB/A\'B\' = BC/B\'C\'$'],['Углы','попарно равны']]},
|
||
p4:{title:'Шпаргалка § 4',rows:[['Прямая || стороне','отсекает треугольник, подобный данному'],['Пропорция','отрезки пропорциональны']]},
|
||
p5:{title:'Шпаргалка § 5',rows:[['1-й признак — по двум углам (УУ)','два угла одного равны двум углам другого'],['Следствие','два прямоугольных с общим острым углом подобны']]},
|
||
p6:{title:'Шпаргалка § 6',rows:[['2-й признак — по двум сторонам и углу (СУС)','стороны пропорциональны, угол между ними равен'],['$\\dfrac{AB}{A\'B\'} = \\dfrac{AC}{A\'C\'}$, угол $A = A\'$','']]},
|
||
p7:{title:'Шпаргалка § 7',rows:[['3-й признак — по трём сторонам (ССС)','все три пары сторон пропорциональны'],['$\\dfrac{a}{a\'}=\\dfrac{b}{b\'}=\\dfrac{c}{c\'}$','']]},
|
||
p8:{title:'Шпаргалка § 8',rows:[['Биссектриса','делит противоположную сторону в отношении прилежащих сторон'],['$\\dfrac{BD}{DC}=\\dfrac{AB}{AC}$','']]},
|
||
p9:{title:'Шпаргалка § 9',rows:[['Отношение площадей','$\\dfrac{S_1}{S_2} = k^2$'],['$k$','коэффициент подобия']]},
|
||
final3:{title:'Финал главы',rows:[['9 параграфов','подобие изучено'],['3 признака','по двум углам, по двум сторонам и углу, по трём сторонам']]},
|
||
};
|
||
const TIPS=[
|
||
{sec:'p1',html:'Теорема Фалеса (обобщённая): несколько параллельных прямых пропорционально пересекают любые две секущие.'},
|
||
{sec:'p2',html:'Деление в отношении $m:n$: $AM = \\dfrac{m}{m+n}\\cdot AB$.'},
|
||
{sec:'p3',html:'Коэффициент подобия $k$ — отношение <b>соответственных</b> сторон.'},
|
||
{sec:'p4',html:'Прямая, параллельная стороне треугольника, отсекает треугольник, подобный исходному.'},
|
||
{sec:'p5',html:'1-й признак — по двум углам: два угла равны. Это наиболее часто используемый признак!'},
|
||
{sec:'p6',html:'2-й признак — по двум сторонам и углу (СУС): стороны пропорциональны и угол между ними равен.'},
|
||
{sec:'p7',html:'3-й признак — по трём сторонам (ССС): все три пары сторон пропорциональны.'},
|
||
{sec:'p8',html:'Биссектриса угла треугольника делит противоположную сторону в отношении смежных сторон.'},
|
||
{sec:'p9',html:'Площади подобных фигур относятся как <b>квадрат</b> коэффициента подобия: $S_1/S_2 = k^2$.'},
|
||
{sec:'final3',html:'Три признака подобия — главный инструмент геометрических доказательств.'},
|
||
];
|
||
|
||
function buildSidebar(id){const box=document.getElementById('sidebar-content');const sb=SIDEBARS[id]||SIDEBARS.p1;let html='';const xpForLv=_xpForLevel(STATE.level),xpNext=_xpForLevel(STATE.level+1);const xpInLv=STATE.xp-xpForLv,xpRange=xpNext-xpForLv,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:#4c1d95;display:flex;align-items:center;gap:6px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px"><polygon points="12,2 22,20 2,20"/></svg>Подсказка</h4><div class="sidecard-row" style="margin-bottom:0;font-size:.84rem;line-height:1.55">${tip.html}</div></div>`;if(STATE.achievements.size>0){html+=`<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">${STATE.achievements.size}</span></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('geometry8_ch3_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('geometry8_ch3_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){}}
|
||
function fmt(n){if(!isFinite(n))return '?';if(Number.isInteger(n))return String(n);return Math.abs(n-Math.round(n))<1e-9?String(Math.round(n)):(+n.toFixed(4)).toString();}
|
||
const ICONS={repeat:'<svg class="ic" viewBox="0 0 24 24"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',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>',oral:'<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',class:'<svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="14" rx="1"/><line x1="3" y1="21" x2="21" y2="21"/><polyline points="7 14 10 11 13 14 17 10"/></svg>',home:'<svg class="ic" viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>'};
|
||
function makeCard(kind,title,num,body){const labels={repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно',class:'Класс',home:'Домашка'};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={p1:'§1',p2:'§2',p3:'§3',p4:'§4',p5:'§5',p6:'§6',p7:'§7',p8:'§8',p9:'§9',final3:'Финал'};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;}
|
||
|
||
let _confettiCanvas=null,_confettiParticles=[],_confettiRaf=null;
|
||
function confetti(){if(!_confettiCanvas){_confettiCanvas=document.createElement('canvas');_confettiCanvas.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9999';document.body.appendChild(_confettiCanvas);}const c=_confettiCanvas;c.width=window.innerWidth;c.height=window.innerHeight;const ctx=c.getContext('2d');const colors=['#7c3aed','#8b5cf6','#a78bfa','#f59e0b','#10b981'];for(let i=0;i<80;i++){_confettiParticles.push({x:window.innerWidth/2+(Math.random()-.5)*200,y:window.innerHeight/2,vx:(Math.random()-.5)*14,vy:-10-Math.random()*10,g:.4,life:100,color:colors[i%colors.length],r:4+Math.random()*4,rot:0,vRot:(Math.random()-.5)*.3});}if(_confettiRaf)cancelAnimationFrame(_confettiRaf);function frame(){ctx.clearRect(0,0,c.width,c.height);_confettiParticles=_confettiParticles.filter(p=>{p.x+=p.vx;p.y+=p.vy;p.vy+=p.g;p.life--;p.rot+=p.vRot;ctx.save();ctx.translate(p.x,p.y);ctx.rotate(p.rot);ctx.fillStyle=p.color;ctx.fillRect(-p.r,-p.r/2,p.r*2,p.r);ctx.restore();return p.life>0&&p.y<c.height+50;});if(_confettiParticles.length>0)_confettiRaf=requestAnimationFrame(frame);else{ctx.clearRect(0,0,c.width,c.height);_confettiRaf=null;}}frame();}
|
||
|
||
const GLOSSARY=[
|
||
{term:'пропорциональность',def:'Равенство двух отношений: $a/b = c/d$. Числа $a,b,c,d$ называются пропорциональными.',sec:'p1',aliases:['пропорциональность','пропорциональны','пропорциональные','пропорциональных','пропорциональными']},
|
||
{term:'подобные треугольники',def:'Треугольники, у которых углы равны попарно и стороны пропорциональны.',sec:'p3',aliases:['подобные треугольники','подобных треугольников','подобными треугольниками','подобный треугольник','подобного треугольника']},
|
||
{term:'коэффициент подобия',def:'Отношение соответственных сторон подобных треугольников.',sec:'p3',aliases:['коэффициент подобия','коэффициента подобия','коэффициенте подобия']},
|
||
{term:'биссектриса',def:'Луч из вершины угла, делящий угол пополам.',sec:'p8',aliases:['биссектриса','биссектрисы','биссектрису','биссектрисой']},
|
||
{term:'теорема Фалеса',def:'Параллельные прямые, пересекая две секущие, отсекают пропорциональные отрезки.',sec:'p1',aliases:['теорема Фалеса','теореме Фалеса','теоремы Фалеса']},
|
||
{term:'многоугольник',def:'Замкнутая ломаная линия, образующая плоскую фигуру.',sec:'p1',aliases:['многоугольник','многоугольника','многоугольников']},
|
||
{term:'медиана',def:'Отрезок от вершины до середины противоположной стороны.',sec:'p1',aliases:['медиана','медианы','медиан','медиану']},
|
||
{term:'площадь',def:'Числовая мера размера плоской фигуры.',sec:'p9',aliases:['площадь','площади','площадью']},
|
||
{term:'параллелограмм',def:'Четырёхугольник, у которого противоположные стороны параллельны.',sec:'p1',aliases:['параллелограмм','параллелограмма','параллелограммы']},
|
||
{term:'теорема Пифагора',def:'$a^2+b^2=c^2$ в прямоугольном треугольнике.',sec:'p9',aliases:['теорема Пифагора','теоремы Пифагора','теореме Пифагора']},
|
||
{term:'касательная',def:'Прямая, касающаяся окружности в одной точке.',sec:'p1',aliases:['касательная','касательной','касательную']},
|
||
{term:'вписанный угол',def:'Угол с вершиной на окружности, стороны которого — хорды.',sec:'p1',aliases:['вписанный угол','вписанного угла']},
|
||
{term:'центральный угол',def:'Угол с вершиной в центре окружности.',sec:'p1',aliases:['центральный угол','центрального угла']},
|
||
{term:'хорда',def:'Отрезок, соединяющий две точки окружности.',sec:'p1',aliases:['хорда','хорды','хорде','хорд']},
|
||
{term:'трапеция',def:'Четырёхугольник с одной парой параллельных сторон.',sec:'p1',aliases:['трапеция','трапеции','трапецию']},
|
||
{term:'диагональ',def:'Отрезок, соединяющий несмежные вершины многоугольника.',sec:'p1',aliases:['диагональ','диагонали','диагоналей']},
|
||
{term:'гипотенуза',def:'Сторона прямоугольного треугольника напротив прямого угла.',sec:'p1',aliases:['гипотенуза','гипотенузы','гипотенузу']},
|
||
{term:'высота',def:'Перпендикуляр из вершины на противоположную сторону.',sec:'p1',aliases:['высота','высоты','высоту']},
|
||
{term:'пифагорова тройка',def:'Три натуральных числа $(a,b,c)$ с $a^2+b^2=c^2$.',sec:'p9',aliases:['пифагорова тройка','пифагоровы тройки']},
|
||
{term:'секущая',def:'Прямая, пересекающая окружность в двух точках.',sec:'p1',aliases:['секущая','секущей','секущую']},
|
||
{term:'хорда',def:'Отрезок, соединяющий две точки окружности.',sec:'p1',aliases:['хорда','хорды','хорд']},
|
||
];
|
||
function wrapGlossary(root){if(!root||root.__glossDone)return;const allAliases=[];GLOSSARY.forEach((g,i)=>g.aliases.forEach(a=>allAliases.push({a,i})));allAliases.sort((x,y)=>y.a.length-x.a.length);const re=new RegExp('(?<![\\w\\u0400-\\u04ff-])('+allAliases.map(x=>x.a.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')).join('|')+')(?![\\w\\u0400-\\u04ff-])','iu');const walker=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,{acceptNode(node){const p=node.parentElement;if(!p)return NodeFilter.FILTER_REJECT;if(p.closest('.katex,.gloss-term,button,input,select,.wg-badge,.card-icon,.sec-num,.psel-num,.hdr,.ach-popup,script,style,.search-modal,.sidecard,.gloss-tip'))return NodeFilter.FILTER_REJECT;if(!re.test(node.nodeValue))return NodeFilter.FILTER_REJECT;return NodeFilter.FILTER_ACCEPT;}});const nodes=[];let n;while((n=walker.nextNode()))nodes.push(n);nodes.forEach(node=>{const text=node.nodeValue;const out=document.createDocumentFragment();let cursor=0;const global=new RegExp(re.source,'giu');let m;while((m=global.exec(text))!==null){if(m.index>cursor)out.appendChild(document.createTextNode(text.slice(cursor,m.index)));const found=m[0].toLowerCase();const hit=allAliases.find(x=>x.a.toLowerCase()===found);const g=hit?GLOSSARY[hit.i]:null;const sp=document.createElement('span');sp.className='gloss-term';sp.dataset.gloss=g?g.term:'';sp.textContent=m[0];out.appendChild(sp);cursor=m.index+m[0].length;}if(cursor<text.length)out.appendChild(document.createTextNode(text.slice(cursor)));node.parentNode.replaceChild(out,node);});root.__glossDone=true;}
|
||
function initGlossaryTip(){const tip=document.getElementById('gloss-tip');if(!tip)return;let lockOpen=null;function show(elm){const g=GLOSSARY.find(x=>x.term===elm.dataset.gloss);if(!g)return;tip.innerHTML='<b>'+g.term[0].toUpperCase()+g.term.slice(1)+'</b><div style="margin-top:4px">'+g.def+'</div><div style="margin-top:6px;font-size:.72rem;color:var(--muted);text-transform:uppercase;letter-spacing:.06em">См. § '+g.sec.replace('p','')+'</div>';if(window.renderMathInElement)renderMath(tip);const r=elm.getBoundingClientRect();tip.classList.add('show');const tw=tip.offsetWidth,th=tip.offsetHeight;let left=r.left,top=r.bottom+8;if(left+tw>window.innerWidth-12)left=window.innerWidth-tw-12;if(top+th>window.innerHeight-12)top=r.top-th-8;tip.style.left=Math.max(8,left)+'px';tip.style.top=Math.max(8,top)+'px';}function hide(){tip.classList.remove('show');}document.addEventListener('mouseover',e=>{const elm=e.target.closest&&e.target.closest('.gloss-term');if(elm&&!lockOpen)show(elm);});document.addEventListener('mouseout',e=>{const elm=e.target.closest&&e.target.closest('.gloss-term');if(elm&&!lockOpen)hide();});document.addEventListener('click',e=>{const elm=e.target.closest&&e.target.closest('.gloss-term');if(elm){if(lockOpen===elm){lockOpen=null;hide();}else{lockOpen=elm;show(elm);}}else if(lockOpen&&!e.target.closest('.gloss-tip')){lockOpen=null;hide();}});}
|
||
|
||
const SEARCH_INDEX=(function(){const arr=[];PARAS.forEach(p=>arr.push({kind:'Параграф',title:p.num+' '+p.name,desc:p.sub||'',sec:p.id}));GLOSSARY.forEach(g=>arr.push({kind:'Понятие',title:g.term,desc:g.def.replace(/\$/g,''),sec:g.sec,gloss:g.term}));[['Формула','Теорема Фалеса — пропорциональность','§1','p1'],['Формула','1-й признак подобия — два угла','§5','p5'],['Формула','Биссектриса: BD/DC = AB/AC','§8','p8'],['Формула','Отношение площадей = k²','§9','p9']].forEach(([k,t,d,s])=>arr.push({kind:k,title:t,desc:d,sec:s}));return arr;})();
|
||
function initSearch(){const modal=document.getElementById('search-modal'),inp=document.getElementById('search-input'),out=document.getElementById('search-results'),btn=document.getElementById('search-btn');if(!modal||!inp||!out)return;let cur=0,rows=[];function score(q,it){const t=(it.title+' '+it.desc).toLowerCase();if(t.includes(q))return 100+(it.title.toLowerCase().startsWith(q)?50:0);let s=0;q.split(/\s+/).forEach(w=>{if(w&&t.includes(w))s+=10;});return s;}function rank(q){q=q.trim().toLowerCase();if(!q)return SEARCH_INDEX.slice(0,12);return SEARCH_INDEX.map(it=>({it,s:score(q,it)})).filter(x=>x.s>0).sort((a,b)=>b.s-a.s).slice(0,20).map(x=>x.it);}function render(){cur=0;if(!rows.length){out.innerHTML='<div class="search-empty">Ничего не найдено</div>';return;}out.innerHTML=rows.map((r,i)=>`<button class="search-row${i===0?' active':''}" data-i="${i}"><div class="sr-kind">${r.kind}</div><div class="sr-title">${r.title}</div>${r.desc?`<div class="sr-desc">${r.desc.length>90?r.desc.slice(0,90)+'…':r.desc}</div>`:''}</button>`).join('');out.querySelectorAll('.search-row').forEach(b=>b.addEventListener('click',()=>{cur=+b.dataset.i;pick();}));}function pick(){const r=rows[cur];if(!r)return;close();goTo(r.sec);if(r.gloss){setTimeout(()=>{const sec=document.getElementById('sec-'+r.sec);const elm=sec&&sec.querySelector('[data-gloss="'+r.gloss+'"]');if(elm){elm.scrollIntoView({behavior:'smooth',block:'center'});elm.style.transition='background .3s';elm.style.background='var(--warn,#f59e0b)';setTimeout(()=>{elm.style.background='';},1400);}},400);}}function move(d){const items=out.querySelectorAll('.search-row');if(!items.length)return;items[cur]&&items[cur].classList.remove('active');cur=(cur+d+items.length)%items.length;items[cur].classList.add('active');items[cur].scrollIntoView({block:'nearest'});}function open(){modal.classList.add('show');inp.value='';rows=rank('');render();setTimeout(()=>inp.focus(),50);}function close(){modal.classList.remove('show');}btn&&btn.addEventListener('click',open);modal.addEventListener('click',e=>{if(e.target===modal)close();});inp.addEventListener('input',()=>{rows=rank(inp.value);render();});inp.addEventListener('keydown',e=>{if(e.key==='ArrowDown'){e.preventDefault();move(1);}else if(e.key==='ArrowUp'){e.preventDefault();move(-1);}else if(e.key==='Enter'){e.preventDefault();pick();}else if(e.key==='Escape'){e.preventDefault();close();}});document.addEventListener('keydown',e=>{if((e.ctrlKey||e.metaKey)&&(e.key==='k'||e.key==='K')){e.preventDefault();if(modal.classList.contains('show'))close();else open();}});}
|
||
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();initGlossaryTip();initSearch();buildParaSelector();refreshProgressUI();loadServerReadState();goTo('p1');setTimeout(()=>achievement('start','Начало главы 3!'),600);if(window.LS&&window.LS.xp){window.LS.xp.load().then(function(s){if(s&&s.xp>STATE.xp){STATE.xp=s.xp;STATE.level=calcLevel(STATE.xp);saveProgress();refreshProgressUI();if(STATE.current)buildSidebar(STATE.current);}});}}
|
||
document.addEventListener('DOMContentLoaded',init);
|
||
|
||
function buildP1(){
|
||
const box=document.getElementById('p1-body');
|
||
let html='';
|
||
|
||
html+=makeCard('theory','Теорема Фалеса (классическая)','1.1',`
|
||
<p><b>Теорема Фалеса.</b> Если параллельные прямые пересекают одну из сторон угла в равных частях, то они отсекают равные части и на другой стороне угла.</p>
|
||
<p style="margin-top:8px"><b>Следствие (обобщённая теорема Фалеса).</b> Если несколько параллельных прямых пересекают две секущие прямые, то они отсекают на этих секущих <em>пропорциональные</em> отрезки:</p>
|
||
$$\\dfrac{AB}{BC} = \\dfrac{A'B'}{B'C'}$$
|
||
<p style="margin-top:8px">где $A,B,C$ — точки на первой секущей, $A',B',C'$ — точки на второй секущей, отсекаемые теми же параллельными прямыми.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 280 170" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- угол с вершиной O=(30,150); два луча, три параллельные прямые -->
|
||
<!-- луч 1: O→(260,60), луч 2: O→(260,150) -->
|
||
<line x1="30" y1="150" x2="260" y2="60" stroke="#7c3aed" stroke-width="2"/>
|
||
<line x1="30" y1="150" x2="260" y2="150" stroke="#7c3aed" stroke-width="2"/>
|
||
<!-- параллельные прямые (3 шт, горизонтальные) пересекают оба луча -->
|
||
<!-- луч1: при x=80→y=120.5, при x=160→y=91, при x=240→y=61.5 -->
|
||
<!-- луч2: при x=80→y=150, при x=160→y=150, при x=240→y=150 -->
|
||
<line x1="80" y1="30" x2="80" y2="160" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/>
|
||
<line x1="160" y1="30" x2="160" y2="160" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/>
|
||
<line x1="240" y1="30" x2="240" y2="160" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/>
|
||
<!-- точки на луче 1 -->
|
||
<circle cx="80" cy="121" r="3.5" fill="#7c3aed"/>
|
||
<circle cx="160" cy="91" r="3.5" fill="#7c3aed"/>
|
||
<circle cx="240" cy="62" r="3.5" fill="#7c3aed"/>
|
||
<!-- точки на луче 2 -->
|
||
<circle cx="80" cy="150" r="3.5" fill="#7c3aed"/>
|
||
<circle cx="160" cy="150" r="3.5" fill="#7c3aed"/>
|
||
<circle cx="240" cy="150" r="3.5" fill="#7c3aed"/>
|
||
<!-- метки луч1 -->
|
||
<text x="76" y="117" text-anchor="end" font-size="10" font-weight="700" fill="#6d28d9">A</text>
|
||
<text x="156" y="87" text-anchor="end" font-size="10" font-weight="700" fill="#6d28d9">B</text>
|
||
<text x="236" y="58" text-anchor="end" font-size="10" font-weight="700" fill="#6d28d9">C</text>
|
||
<!-- метки луч2 -->
|
||
<text x="80" y="165" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9">A'</text>
|
||
<text x="160" y="165" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9">B'</text>
|
||
<text x="240" y="165" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9">C'</text>
|
||
<text x="18" y="153" font-size="10" font-weight="700" fill="#6d28d9">O</text>
|
||
<text x="140" y="20" text-anchor="middle" font-size="10" fill="#6d28d9" font-style="italic">AB/BC = A'B'/B'C'</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Пропорциональность отрезков','1.2',`
|
||
<p>Обозначим точки пересечения параллельных прямых $\\ell_1,\\ell_2,\\ell_3$ со сторонами угла как $A,B,C$ и $A',B',C'$ соответственно. Тогда:</p>
|
||
$$\\dfrac{AB}{BC} = \\dfrac{A'B'}{B'C'}, \\quad \\dfrac{AB}{AC} = \\dfrac{A'B'}{A'C'}$$
|
||
<p style="margin-top:8px">Это выражает <b>пропорциональность отрезков</b>, отсекаемых параллельными прямыми.</p>
|
||
<p style="margin-top:8px"><b>Применение:</b> с помощью теоремы Фалеса доказывают подобие треугольников, делят отрезок в заданном отношении, строят пропорциональные отрезки.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:12px">
|
||
<svg viewBox="0 0 280 130" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- треугольник ABC с точками D,E на сторонах, DE || BC -->
|
||
<polygon points="140,15 30,115 250,115" fill="rgba(124,58,237,.1)" stroke="#7c3aed" stroke-width="2"/>
|
||
<!-- DE параллельна BC, D на AB, E на AC -->
|
||
<line x1="85" y1="65" x2="195" y2="65" stroke="#a78bfa" stroke-width="2" stroke-dasharray="5,3"/>
|
||
<circle cx="85" cy="65" r="3" fill="#7c3aed"/>
|
||
<circle cx="195" cy="65" r="3" fill="#7c3aed"/>
|
||
<text x="140" y="12" text-anchor="middle" font-size="11" font-weight="700" fill="#6d28d9">A</text>
|
||
<text x="24" y="122" font-size="11" font-weight="700" fill="#6d28d9">B</text>
|
||
<text x="252" y="122" font-size="11" font-weight="700" fill="#6d28d9">C</text>
|
||
<text x="78" y="63" text-anchor="end" font-size="10" font-weight="700" fill="#8b5cf6">D</text>
|
||
<text x="201" y="63" font-size="10" font-weight="700" fill="#8b5cf6">E</text>
|
||
<text x="140" y="82" text-anchor="middle" font-size="9" fill="#6d28d9">DE ∥ BC</text>
|
||
<text x="140" y="126" text-anchor="middle" font-size="9" fill="#6d28d9" font-style="italic">AD/DB = AE/EC</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('example','Пример применения','1.3',`
|
||
<p><b>Пример.</b> Параллельные прямые отсекают на первой стороне угла отрезки $AB = 6$ и $BC = 9$. На второй стороне $A'B' = 4$. Найти $B'C'$.</p>
|
||
<p style="margin-top:8px"><b>Решение:</b> по теореме Фалеса $\\dfrac{AB}{BC}=\\dfrac{A'B'}{B'C'}$, то есть $\\dfrac{6}{9}=\\dfrac{4}{B'C'}$.</p>
|
||
<p style="margin-top:4px">$B'C' = \\dfrac{4 \\cdot 9}{6} = 6$.</p>`);
|
||
|
||
/* ИНТЕРАКТИВ 1 — SVG-угол с параллельными прямыми */
|
||
html+=`<div class="wg" id="p1-angle-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Угол с параллельными прямыми</div></div>
|
||
<div class="wg-help">Меняй количество параллельных прямых и угол наклона второй стороны. Видишь, как отношения остаются равными!</div>
|
||
<div class="sliders">
|
||
<label>Кол-во параллельных: <b id="p1-npar-val">3</b>
|
||
<input type="range" min="2" max="6" value="3" id="p1-npar-sl">
|
||
</label>
|
||
<label>Угол второй стороны: <b id="p1-angle-val">30</b>°
|
||
<input type="range" min="10" max="60" value="30" id="p1-angle-sl">
|
||
</label>
|
||
</div>
|
||
<div id="p1-angle-svg" style="display:flex;justify-content:center"></div>
|
||
<div id="p1-angle-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 2 — Пошаговое доказательство */
|
||
html+=`<div class="wg" id="p1-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство теоремы Фалеса — по шагам</div></div>
|
||
<div class="wg-help">Нажимай «Далее» — каждый шаг показывает ключевую идею.</div>
|
||
<div id="p1-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p1-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p1-proof-next">Далее</button>
|
||
<button class="btn" id="p1-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 3 — Калькулятор пропорций */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор пропорций (Теорема Фалеса)</div></div>
|
||
<div class="wg-help">Дано три отрезка из пропорции $\\dfrac{a}{b}=\\dfrac{c}{x}$ — найди четвёртый.</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
|
||
<div style="display:flex;flex-direction:column;align-items:center;gap:4px">
|
||
<input type="number" id="p1-pa" class="tinp" placeholder="a" style="width:70px" min="0.001">
|
||
<span style="font-size:.8rem;color:var(--muted)">AB</span>
|
||
</div>
|
||
<span style="font-size:1.3rem;color:var(--muted)">/</span>
|
||
<div style="display:flex;flex-direction:column;align-items:center;gap:4px">
|
||
<input type="number" id="p1-pb" class="tinp" placeholder="b" style="width:70px" min="0.001">
|
||
<span style="font-size:.8rem;color:var(--muted)">BC</span>
|
||
</div>
|
||
<span style="font-size:1.3rem;color:var(--muted)">=</span>
|
||
<div style="display:flex;flex-direction:column;align-items:center;gap:4px">
|
||
<input type="number" id="p1-pc" class="tinp" placeholder="c" style="width:70px" min="0.001">
|
||
<span style="font-size:.8rem;color:var(--muted)">A'B'</span>
|
||
</div>
|
||
<span style="font-size:1.3rem;color:var(--muted)">/</span>
|
||
<div style="display:flex;flex-direction:column;align-items:center;gap:4px">
|
||
<input type="number" id="p1-px" class="tinp" placeholder="x" style="width:70px" disabled style="background:var(--sec-acc-soft)">
|
||
<span style="font-size:.8rem;color:var(--muted)">B'C'</span>
|
||
</div>
|
||
<button class="btn primary" id="p1-pcalc">Найти x</button>
|
||
</div>
|
||
<div id="p1-pcalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 4 — Тренажёр */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §1 — Теорема Фалеса</div></div>
|
||
<div class="wg-help">5 задач на пропорциональность отрезков. Введи ответ и нажми «Проверить».</div>
|
||
<div class="score-display"><span>Задача <b id="p1-tr-i">1</b> / 5</span><span>Очки: <b id="p1-tr-score">0</b></span></div>
|
||
<div id="p1-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p1-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
|
||
<button class="btn primary" id="p1-tr-go">Проверить</button>
|
||
<button class="btn" id="p1-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p1-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 5 — DnD-сортер */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Определи: пропорциональные или нет?</div></div>
|
||
<div class="wg-help">Перетащи каждую карточку в нужную колонку.</div>
|
||
<div id="p1-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p1-drop-yes"><h5>Пропорциональные</h5><div class="drop-items" id="p1-drop-yes-items"></div></div>
|
||
<div class="drop-box" id="p1-drop-no"><h5>Непропорциональные</h5><div class="drop-items" id="p1-drop-no-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p1-dnd-check">Проверить</button><button class="btn" id="p1-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p1-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 6 — Босс §1 */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §1</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p1-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p1-read-btn" onclick="addXp(10,'p1-read');bumpProgress('p1',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §1 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav(null,'p2');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: угол с параллелями == */
|
||
(function(){
|
||
const nSl=document.getElementById('p1-npar-sl');
|
||
const nVal=document.getElementById('p1-npar-val');
|
||
const aSl=document.getElementById('p1-angle-sl');
|
||
const aVal=document.getElementById('p1-angle-val');
|
||
const svgWrap=document.getElementById('p1-angle-svg');
|
||
const info=document.getElementById('p1-angle-info');
|
||
function draw(){
|
||
const n=+nSl.value;
|
||
const angDeg=+aSl.value;
|
||
nVal.textContent=n;
|
||
aVal.textContent=angDeg;
|
||
const W=320, H=180;
|
||
const Ox=20, Oy=H-20;
|
||
const ang=angDeg*Math.PI/180;
|
||
const L=280;
|
||
// луч 1: горизонталь вправо
|
||
// луч 2: под углом ang вверх
|
||
const pts1=[]; // точки на луче1 (горизональном)
|
||
const pts2=[]; // точки на луче2
|
||
const step=L/(n);
|
||
for(let i=1;i<=n;i++){
|
||
const x=Ox+step*i;
|
||
pts1.push({x, y:Oy});
|
||
pts2.push({x, y:Oy-step*i*Math.tan(ang)});
|
||
}
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
// лучи
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="${Ox+L+10}" y2="${Oy}" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="${Ox+L+10}" y2="${Oy-(L+10)*Math.tan(ang)}" stroke="#7c3aed" stroke-width="2"/>`;
|
||
// параллельные прямые (вертикальные)
|
||
for(let i=0;i<n;i++){
|
||
const cx=pts1[i].x;
|
||
s+=`<line x1="${cx}" y1="5" x2="${cx}" y2="${H-5}" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/>`;
|
||
s+=`<circle cx="${pts1[i].x}" cy="${pts1[i].y}" r="4" fill="#7c3aed"/>`;
|
||
s+=`<circle cx="${pts2[i].x}" cy="${pts2[i].y}" r="4" fill="#7c3aed"/>`;
|
||
const lbl=String.fromCharCode(65+i);
|
||
s+=`<text x="${pts1[i].x}" y="${Oy+14}" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9">${lbl}</text>`;
|
||
s+=`<text x="${pts2[i].x+4}" y="${pts2[i].y-5}" font-size="10" font-weight="700" fill="#6d28d9">${lbl}'</text>`;
|
||
}
|
||
s+=`<text x="${Ox-4}" y="${Oy+4}" font-size="10" font-weight="700" fill="#6d28d9">O</text>`;
|
||
s+='</svg>';
|
||
svgWrap.innerHTML=s;
|
||
|
||
// вычисляем отрезки
|
||
let infoHtml='';
|
||
for(let i=0;i<n-1;i++){
|
||
const seg1=Math.round((pts1[i+1].x-pts1[i].x)*10)/10;
|
||
const dy2=pts2[i+1].y-pts2[i].y, dx2=pts2[i+1].x-pts2[i].x;
|
||
const seg2=Math.round(Math.sqrt(dx2*dx2+dy2*dy2)*10)/10;
|
||
const lA=String.fromCharCode(65+i), lB=String.fromCharCode(66+i);
|
||
infoHtml+=`<span style="margin-right:16px">${lA}${lB} = <b>${seg1}</b> px; ${lA}'${lB}' = <b>${fmt(seg2)}</b> px</span>`;
|
||
}
|
||
if(n>=2){
|
||
const r1=Math.round((pts1[1].x-pts1[0].x)/(pts1[0].x-pts1[0].x+1)*1000)/1000;
|
||
const dy0=pts2[1].y-pts2[0].y, dx0=pts2[1].x-pts2[0].x;
|
||
const s1=pts1[1].x-pts1[0].x;
|
||
const s2=Math.sqrt(dx0*dx0+dy0*dy0);
|
||
infoHtml+=`<div style="margin-top:6px;color:var(--sec-acc-d,var(--pri2));font-weight:700">Отношение AB/A'B' = ${fmt(s1/s2)} ≈ постоянно для всех пар</div>`;
|
||
}
|
||
info.innerHTML=infoHtml;
|
||
addXp(1,'p1-angle');
|
||
}
|
||
nSl.addEventListener('input',draw);
|
||
aSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Даны два луча из вершины O и три параллельные прямые, пересекающие их в точках A, B, C и A\', B\', C\'.',
|
||
svg:()=>{
|
||
// Ray 1: horizontal from O=(20,140) to (250,140)
|
||
// Ray 2: from O=(20,140) to (250,60), slope = (60-140)/(250-20) = -80/230
|
||
// Parallel transversals at x=70,150,230 (vertical)
|
||
// Intersection with ray 2: y = 140 + (x-20)*(-80/230)
|
||
// x=70: y = 140 - 50*80/230 ≈ 123
|
||
// x=150: y = 140 - 130*80/230 ≈ 95
|
||
// x=230: y = 140 - 210*80/230 ≈ 67
|
||
const W=260,H=160,Ox=20,Oy=140;
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="250" y2="${Oy}" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="250" y2="60" stroke="#7c3aed" stroke-width="2"/>`;
|
||
// parallels: connect point on ray1 to correctly computed point on ray2
|
||
[[70,140,70,123],[150,140,150,95],[230,140,230,67]].forEach(([x1,y1,x2,y2])=>{
|
||
s+=`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/>`;
|
||
});
|
||
s+=`<text x="${Ox-4}" y="${Oy+4}" font-size="10" fill="#6d28d9" font-weight="700">O</text>`;
|
||
['A','B','C'].forEach((l,i)=>s+=`<text x="${70+i*80}" y="${Oy+14}" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="700">${l}</text>`);
|
||
['A\'','B\'','C\''].forEach((l,i)=>s+=`<text x="${70+i*80+4}" y="${[119,91,63][i]-4}" font-size="10" fill="#6d28d9" font-weight="700">${l}</text>`);
|
||
s+='</svg>';return s;}},
|
||
{desc:'<b>Шаг 2.</b> Через точки A, B, C проводим прямые, параллельные второму лучу. Получаем параллелограммы.',
|
||
svg:()=>{
|
||
// Same geometry as step 1. Corrected y′ values on ray 2.
|
||
// Ray 2 direction vector: (230,-80). Auxiliary lines from A,B parallel to ray 2:
|
||
// From A=(70,140) in dir (230,-80) scaled: Δx=80 → Δy=-80*80/230≈-28 → meets x=150 at y≈112
|
||
// From B=(150,140) in dir (230,-80): meets x=230 at y≈112
|
||
const W=260,H=160,Ox=20,Oy=140;
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="250" y2="${Oy}" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="250" y2="60" stroke="#7c3aed" stroke-width="2"/>`;
|
||
[[70,140,70,123],[150,140,150,95],[230,140,230,67]].forEach(([x1,y1,x2,y2])=>{
|
||
s+=`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/>`;
|
||
});
|
||
// auxiliary lines from A and B parallel to ray 2 (direction (230,-80))
|
||
s+=`<line x1="70" y1="140" x2="150" y2="112" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="3,3"/>`;
|
||
s+=`<line x1="150" y1="140" x2="230" y2="112" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="3,3"/>`;
|
||
s+=`<text x="100" y="131" font-size="9" fill="#b45309" font-weight="700">параллелограмм</text>`;
|
||
s+='</svg>';return s;}},
|
||
{desc:'<b>Шаг 3.</b> В параллелограмме противоположные стороны равны: $A_1B_1 = AB_2 = AB$, поэтому параллельная прямая откладывает равные отрезки на обоих лучах (если исходные части равны).',
|
||
svg:()=>{
|
||
// Parallelogram: A=(70,140), B=(150,140) on ray1; A'=(70,123), aux=(150,112) from auxiliary line
|
||
// This forms parallelogram A-B-aux-A' with A'B' (on ray2) as the top side
|
||
const W=260,H=160;
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
s+=`<polygon points="70,140 150,140 150,112 70,123" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="1.5"/>`;
|
||
// tick marks on parallel sides AB and A'B'' to show equality
|
||
s+=`<line x1="107" y1="140" x2="110" y2="134" stroke="#7c3aed" stroke-width="1.5"/>`;
|
||
s+=`<line x1="113" y1="140" x2="116" y2="134" stroke="#7c3aed" stroke-width="1.5"/>`;
|
||
s+=`<line x1="107" y1="118" x2="110" y2="112" stroke="#7c3aed" stroke-width="1.5"/>`;
|
||
s+=`<line x1="113" y1="118" x2="116" y2="112" stroke="#7c3aed" stroke-width="1.5"/>`;
|
||
s+=`<text x="110" y="110" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="700">Параллелограмм</text>`;
|
||
s+=`<text x="110" y="150" text-anchor="middle" font-size="9" fill="#6d28d9">AB = A\'B\' (пр. стор.)</text>`;
|
||
s+='</svg>';return s;}},
|
||
{desc:'<b>Шаг 4.</b> Если параллельные прямые делят луч на <em>равные</em> части, то и второй луч делится на равные части. Это и есть теорема Фалеса в классической форме.',
|
||
svg:()=>{
|
||
const W=260,H=160,Ox=20,Oy=140;
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="250" y2="${Oy}" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<line x1="${Ox}" y1="${Oy}" x2="250" y2="60" stroke="#7c3aed" stroke-width="2"/>`;
|
||
// corrected y′ values on ray2: y=140+(x-20)*(-80/230)
|
||
[[70,140,70,123],[150,140,150,95],[230,140,230,67]].forEach(([x1,y1,x2,y2])=>{
|
||
s+=`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="#a78bfa" stroke-width="1.5"/>`;
|
||
});
|
||
// равные отрезки — tick marks on ray1 segments
|
||
[[110,140],[190,140]].forEach(([x,y])=>{
|
||
s+=`<line x1="${x-4}" y1="${y-5}" x2="${x}" y2="${y+5}" stroke="#10b981" stroke-width="1.5"/>`;
|
||
});
|
||
// tick marks on ray2 segments
|
||
[[110,109],[190,81]].forEach(([x,y])=>{
|
||
s+=`<line x1="${x-4}" y1="${y-5}" x2="${x}" y2="${y+5}" stroke="#10b981" stroke-width="1.5"/>`;
|
||
});
|
||
s+=`<text x="110" y="${Oy+14}" text-anchor="middle" font-size="9" fill="#10b981" font-weight="700">AB=AB</text>`;
|
||
s+=`<text x="190" y="${Oy+14}" text-anchor="middle" font-size="9" fill="#10b981" font-weight="700">BC=BC</text>`;
|
||
s+='</svg>';return s;}},
|
||
{desc:'<b>Шаг 5.</b> Обобщённая теорема Фалеса: при <em>произвольных</em> параллельных прямых (не обязательно с равными частями) отрезки на двух лучах всё равно пропорциональны: $\\dfrac{AB}{BC}=\\dfrac{A\'B\'}{B\'C\'}$. <b>Доказано.</b>',
|
||
svg:()=>{
|
||
// Ray1: O=(20,140) horizontal to (250,140)
|
||
// Ray2: O=(20,140) to (250,50), slope=-90/230
|
||
// 2 parallel verticals at x=80 and x=170
|
||
// Ray2 intersections: x=80 → y=140-60*90/230≈117; x=170 → y=140-150*90/230≈81
|
||
const W=260,H=160;
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
s+=`<line x1="20" y1="140" x2="250" y2="140" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<line x1="20" y1="140" x2="250" y2="50" stroke="#7c3aed" stroke-width="2"/>`;
|
||
// parallel transversals from ray1 to ray2 (not full vertical lines - just the segments)
|
||
s+=`<line x1="80" y1="140" x2="80" y2="117" stroke="#a78bfa" stroke-width="1.8" stroke-dasharray="4,3"/>`;
|
||
s+=`<line x1="170" y1="140" x2="170" y2="81" stroke="#a78bfa" stroke-width="1.8" stroke-dasharray="4,3"/>`;
|
||
// dot intersections on both rays
|
||
s+=`<circle cx="80" cy="140" r="3" fill="#7c3aed"/>`;
|
||
s+=`<circle cx="170" cy="140" r="3" fill="#7c3aed"/>`;
|
||
s+=`<circle cx="80" cy="117" r="3" fill="#7c3aed"/>`;
|
||
s+=`<circle cx="170" cy="81" r="3" fill="#7c3aed"/>`;
|
||
s+=`<text x="80" y="152" text-anchor="middle" font-size="9" fill="#6d28d9">A</text>`;
|
||
s+=`<text x="170" y="152" text-anchor="middle" font-size="9" fill="#6d28d9">B</text>`;
|
||
s+=`<text x="84" y="114" font-size="9" fill="#6d28d9">A'</text>`;
|
||
s+=`<text x="174" y="78" font-size="9" fill="#6d28d9">B'</text>`;
|
||
s+=`<text x="20" y="152" text-anchor="middle" font-size="9" fill="#6d28d9">O</text>`;
|
||
s+=`<text x="130" y="20" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="800">AB/A'B' = OA/OA'</text>`;
|
||
s+=`<text x="130" y="100" text-anchor="middle" font-size="9" fill="#10b981" font-weight="700">QED ∎</text>`;
|
||
s+='</svg>';return s;}},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p1-proof-svg');
|
||
const descEl=document.getElementById('p1-proof-desc');
|
||
function show(){
|
||
svgEl.innerHTML=steps[step].svg();
|
||
descEl.innerHTML=steps[step].desc;
|
||
renderMath(descEl);
|
||
}
|
||
document.getElementById('p1-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p1-proof-step');}
|
||
else{addXp(5,'p1-proof-done');bumpProgress('p1',10);}
|
||
});
|
||
document.getElementById('p1-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: калькулятор пропорций == */
|
||
(function(){
|
||
document.getElementById('p1-pcalc').addEventListener('click',()=>{
|
||
const a=parseFloat(document.getElementById('p1-pa').value);
|
||
const b=parseFloat(document.getElementById('p1-pb').value);
|
||
const c=parseFloat(document.getElementById('p1-pc').value);
|
||
const out=document.getElementById('p1-pcalc-out');
|
||
if(!isFinite(a)||!isFinite(b)||!isFinite(c)||a<=0||b<=0||c<=0){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи три положительных числа.</span>';return;
|
||
}
|
||
const x=b*c/a;
|
||
out.style.display='block';
|
||
out.innerHTML=`По теореме Фалеса: $x = \\dfrac{b \\cdot c}{a} = \\dfrac{${fmt(b)} \\cdot ${fmt(c)}}{${fmt(a)}} = ${fmt(x)}$`;
|
||
renderMath(out);
|
||
addXp(2,'p1-pcalc');bumpProgress('p1',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'Параллельные прямые отсекают на первом луче отрезки $AB=4$, $BC=6$. На втором луче $A\'B\'=6$. Найди $B\'C\'$.', ans:9, hint:'BC·A\'B\'/AB = 6·6/4 = 9.'},
|
||
{q:'$AB=3$, $BC=9$, $A\'B\'=5$. Найди $B\'C\'$.', ans:15, hint:'9·5/3 = 15.'},
|
||
{q:'Параллельные прямые отсекают $AB=8$, $BC=12$, $B\'C\'=9$. Найди $A\'B\'$.', ans:6, hint:'A\'B\' = AB·B\'C\'/BC = 8·9/12 = 6.'},
|
||
{q:'$AB=5$, $A\'B\'=7$, $B\'C\'=14$. Найди $BC$.', ans:10, hint:'BC = AB·B\'C\'/A\'B\' = 5·14/7 = 10.'},
|
||
{q:'Три параллельные прямые отсекают на луче отрезки $2$ и $3$. На другом луче первый отрезок равен $4$. Найди второй отрезок.', ans:6, hint:'4·3/2 = 6.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p1-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p1-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p1-tr-ans').value='';
|
||
document.getElementById('p1-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p1-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p1-tr-score').textContent=0;show();});
|
||
document.getElementById('p1-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p1-tr-ans').value;
|
||
const fb=document.getElementById('p1-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.01){
|
||
score++;document.getElementById('p1-tr-score').textContent=score;
|
||
addXp(3,'p1-tr-'+idx);bumpProgress('p1',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p1-tr-all');bumpProgress('p1',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p1-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p1-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: DnD-сортер == */
|
||
(function(){
|
||
const items=[
|
||
{text:'AB=3, BC=6, A\'B\'=4, B\'C\'=8',yes:true},
|
||
{text:'AB=2, BC=4, A\'B\'=3, B\'C\'=7',yes:false},
|
||
{text:'AB=5, BC=10, A\'B\'=1, B\'C\'=2',yes:true},
|
||
{text:'AB=6, BC=3, A\'B\'=8, B\'C\'=5',yes:false},
|
||
{text:'AB=4, BC=8, A\'B\'=3, B\'C\'=6',yes:true},
|
||
];
|
||
const pool=document.getElementById('p1-dnd-pool');
|
||
const yesBox=document.getElementById('p1-drop-yes-items');
|
||
const noBox=document.getElementById('p1-drop-no-items');
|
||
let dragging=null;
|
||
function makeChip(it,idx){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';
|
||
chip.dataset.idx=idx;
|
||
chip.textContent=it.text;
|
||
chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p1-drop-yes'),document.getElementById('p1-drop-no'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p1-drop-yes')?yesBox:box===document.getElementById('p1-drop-no')?noBox:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p1-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p1-dnd-fb');
|
||
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
|
||
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
|
||
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
|
||
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p1-dnd');bumpProgress('p1',8);}
|
||
else{feedback(fb,false,'Есть ошибки — перепроверь отношения AB/BC и A\'B\'/B\'C\'.');}
|
||
});
|
||
document.getElementById('p1-dnd-reset').addEventListener('click',()=>{
|
||
[...yesBox.children].forEach(c=>pool.appendChild(c));
|
||
[...noBox.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p1-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §1 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'<svg viewBox="0 0 240 130" style="display:block;max-width:250px;margin:0 auto 8px;background:#f5f3ff;border:1px solid #ddd6fe;border-radius:8px"><line x1="20" y1="110" x2="220" y2="110" stroke="#7c3aed" stroke-width="2"/><line x1="20" y1="110" x2="220" y2="30" stroke="#7c3aed" stroke-width="2"/><line x1="80" y1="10" x2="80" y2="118" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/><line x1="160" y1="10" x2="160" y2="118" stroke="#a78bfa" stroke-width="1.5" stroke-dasharray="4,3"/><text x="120" y="125" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="700">AB=10, BC=?, A\'B\'=6, B\'C\'=9</text></svg>$AB=10$, $A\'B\'=6$, $B\'C\'=9$. Найди $BC$.', ans:15, hint:'BC = AB·B\'C\'/A\'B\' = 10·9/6 = 15.'},
|
||
{q:'Параллельные прямые отсекают на двух лучах: луч 1 — отрезки $4$ и $x$, луч 2 — отрезки $6$ и $12$. Найди $x$.', ans:8, hint:'4/x = 6/12 → x = 4·12/6 = 8.'},
|
||
{q:'Прямая $DE \\parallel BC$ в треугольнике $ABC$. $AD=6$, $DB=9$, $AE=8$. Найди $EC$.', ans:12, hint:'AD/DB = AE/EC → EC = DB·AE/AD = 9·8/6 = 12.'},
|
||
{q:'$AB=15$, $BC=25$, $B\'C\'=20$. Найди $A\'B\'$.', ans:12, hint:'A\'B\' = AB·B\'C\'/BC = 15·20/25 = 12.'},
|
||
];
|
||
const bossBox=document.getElementById('p1-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p1b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p1b-a${i}').value;
|
||
const fb=document.getElementById('p1b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.01){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p1BossSolved.has(${i})){ window.p1BossSolved.add(${i}); addXp(5,'p1-boss${i}'); bumpProgress('p1',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p1b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p1BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
function buildP2(){
|
||
const box=document.getElementById('p2-body');
|
||
let html='';
|
||
|
||
html+=makeCard('theory','Деление отрезка в заданном отношении','2.1',`
|
||
<p><b>Определение.</b> Говорят, что точка $C$ делит отрезок $AB$ <em>в отношении $m:n$</em> (<em>внутреннее деление</em>), если $C$ лежит между $A$ и $B$, и:</p>
|
||
$$\\dfrac{AC}{CB} = \\dfrac{m}{n}, \\quad m,n > 0$$
|
||
<p style="margin-top:8px"><b>Формула координат.</b> Если $A = (x_A, y_A)$, $B = (x_B, y_B)$, то точка деления:</p>
|
||
$$C = \\left(\\dfrac{n\\,x_A + m\\,x_B}{m+n},\\; \\dfrac{n\\,y_A + m\\,y_B}{m+n}\\right)$$
|
||
<p style="margin-top:8px"><b>Частный случай $m=n$:</b> точка $C$ — середина $AB$.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 280 80" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- отрезок AB с точкой C -->
|
||
<line x1="20" y1="40" x2="260" y2="40" stroke="#7c3aed" stroke-width="2.5"/>
|
||
<circle cx="20" cy="40" r="4" fill="#7c3aed"/>
|
||
<circle cx="260" cy="40" r="4" fill="#7c3aed"/>
|
||
<!-- C делит в 2:3: x = 20 + 2/(2+3)*240 = 20+96 = 116 -->
|
||
<circle cx="116" cy="40" r="5" fill="#f59e0b"/>
|
||
<!-- скобки -->
|
||
<line x1="20" y1="52" x2="116" y2="52" stroke="#10b981" stroke-width="1.5"/>
|
||
<line x1="116" y1="52" x2="260" y2="52" stroke="#8b5cf6" stroke-width="1.5"/>
|
||
<text x="68" y="65" text-anchor="middle" font-size="11" fill="#10b981" font-weight="700">m = 2</text>
|
||
<text x="188" y="65" text-anchor="middle" font-size="11" fill="#8b5cf6" font-weight="700">n = 3</text>
|
||
<text x="20" y="32" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">A</text>
|
||
<text x="116" y="32" text-anchor="middle" font-size="11" fill="#b45309" font-weight="700">C</text>
|
||
<text x="260" y="32" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">B</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('algo','Построение циркулем и линейкой','2.2',`
|
||
<p>Чтобы разделить отрезок $AB$ в отношении $m:n$:</p>
|
||
<ol style="margin-left:18px;margin-top:6px;line-height:2">
|
||
<li>Из точки $A$ проводим луч $AK$, не совпадающий с $AB$.</li>
|
||
<li>На луче $AK$ последовательно откладываем $m+n$ равных отрезков единичной длины: точки $P_1, P_2, \\ldots, P_{m+n}$.</li>
|
||
<li>Соединяем точку $P_{m+n}$ с точкой $B$.</li>
|
||
<li>Через $P_m$ проводим прямую, параллельную $P_{m+n}B$ — она пересекает $AB$ в нужной точке $C$.</li>
|
||
</ol>
|
||
<p style="margin-top:8px">По теореме Фалеса $\\dfrac{AC}{CB} = \\dfrac{m}{n}$. <b>ч.т.д.</b></p>
|
||
<div style="display:flex;justify-content:center;margin-top:12px">
|
||
<svg viewBox="0 0 280 160" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- отрезок AB -->
|
||
<line x1="20" y1="60" x2="260" y2="60" stroke="#7c3aed" stroke-width="2"/>
|
||
<circle cx="20" cy="60" r="4" fill="#7c3aed"/>
|
||
<circle cx="260" cy="60" r="4" fill="#7c3aed"/>
|
||
<text x="16" y="52" font-size="10" fill="#6d28d9" font-weight="700">A</text>
|
||
<text x="256" y="52" font-size="10" fill="#6d28d9" font-weight="700">B</text>
|
||
<!-- луч AK: из A=(20,60) под углом вниз -->
|
||
<line x1="20" y1="60" x2="170" y2="140" stroke="#f59e0b" stroke-width="1.5"/>
|
||
<!-- 5 точек (m+n=2+3) на луче, шаг=30px по лучу -->
|
||
<!-- P1=(50,76), P2=(80,92), P3=(110,108), P4=(140,124), P5=(170,140) -->
|
||
<circle cx="50" cy="76" r="3" fill="#f59e0b"/>
|
||
<circle cx="80" cy="92" r="3" fill="#f59e0b"/>
|
||
<circle cx="110" cy="108" r="3" fill="#10b981"/>
|
||
<circle cx="140" cy="124" r="3" fill="#f59e0b"/>
|
||
<circle cx="170" cy="140" r="3" fill="#f59e0b"/>
|
||
<text x="50" y="72" text-anchor="middle" font-size="8" fill="#b45309">P₁</text>
|
||
<text x="80" y="88" text-anchor="middle" font-size="8" fill="#b45309">P₂</text>
|
||
<text x="110" y="104" text-anchor="middle" font-size="8" fill="#047857" font-weight="700">P_m</text>
|
||
<text x="165" y="155" text-anchor="middle" font-size="8" fill="#b45309">P₅</text>
|
||
<!-- линия P5B -->
|
||
<line x1="170" y1="140" x2="260" y2="60" stroke="#8b5cf6" stroke-width="1.2" stroke-dasharray="4,3"/>
|
||
<!-- параллельная через Pm: C на AB -->
|
||
<!-- C: x = 20 + 2/5*(260-20) = 20+96 = 116 -->
|
||
<line x1="110" y1="108" x2="116" y2="60" stroke="#10b981" stroke-width="1.8" stroke-dasharray="4,3"/>
|
||
<circle cx="116" cy="60" r="5" fill="#10b981"/>
|
||
<text x="116" y="52" text-anchor="middle" font-size="10" fill="#047857" font-weight="700">C</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('example','Пример','2.3',`
|
||
<p><b>Пример 1.</b> $A=(0,0)$, $B=(10,0)$, разделить в отношении $3:2$.</p>
|
||
<p>$C_x = \\dfrac{2\\cdot 0 + 3\\cdot 10}{3+2} = \\dfrac{30}{5} = 6$. Ответ: $C=(6,0)$.</p>
|
||
<p style="margin-top:8px"><b>Пример 2.</b> $A=(1,2)$, $B=(7,8)$, разделить в отношении $1:2$.</p>
|
||
<p>$C_x = \\dfrac{2\\cdot 1+1\\cdot 7}{3}=3$, $C_y=\\dfrac{2\\cdot 2+1\\cdot 8}{3}=4$. Ответ: $C=(3,4)$.</p>`);
|
||
|
||
/* ИНТЕРАКТИВ 1 — SVG-построение */
|
||
html+=`<div class="wg" id="p2-build-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Построение деления отрезка m:n</div></div>
|
||
<div class="wg-help">Меняй m и n — смотри, как перемещается точка C на отрезке AB.</div>
|
||
<div class="sliders">
|
||
<label>m = <b id="p2-m-val">2</b>
|
||
<input type="range" min="1" max="6" value="2" id="p2-m-sl">
|
||
</label>
|
||
<label>n = <b id="p2-n-val">3</b>
|
||
<input type="range" min="1" max="6" value="3" id="p2-n-sl">
|
||
</label>
|
||
</div>
|
||
<div id="p2-build-svg" style="display:flex;justify-content:center"></div>
|
||
<div id="p2-build-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.93rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 2 — Калькулятор */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор деления отрезка</div></div>
|
||
<div class="wg-help">Введи длину отрезка и отношение m:n — получи расстояние AC от начала.</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
|
||
<div style="display:flex;flex-direction:column;gap:4px">
|
||
<span style="font-size:.8rem;color:var(--muted)">AB</span>
|
||
<input type="number" id="p2-lab" class="tinp" placeholder="AB" style="width:80px" min="0.001">
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;gap:4px">
|
||
<span style="font-size:.8rem;color:var(--muted)">m</span>
|
||
<input type="number" id="p2-lm" class="tinp" placeholder="m" style="width:60px" min="1">
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;gap:4px">
|
||
<span style="font-size:.8rem;color:var(--muted)">n</span>
|
||
<input type="number" id="p2-ln" class="tinp" placeholder="n" style="width:60px" min="1">
|
||
</div>
|
||
<button class="btn primary" id="p2-lcalc">Вычислить</button>
|
||
</div>
|
||
<div id="p2-lcalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 3 — Пошаговое доказательство */
|
||
html+=`<div class="wg" id="p2-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Доказательство формулы — по шагам</div></div>
|
||
<div class="wg-help">4 шага — вывод формулы координат точки деления через теорему Фалеса.</div>
|
||
<div id="p2-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p2-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p2-proof-next">Далее</button>
|
||
<button class="btn" id="p2-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 4 — Тренажёр */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §2</div></div>
|
||
<div class="wg-help">5 задач на деление отрезка. Введи числовой ответ.</div>
|
||
<div class="score-display"><span>Задача <b id="p2-tr-i">1</b> / 5</span><span>Очки: <b id="p2-tr-score">0</b></span></div>
|
||
<div id="p2-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p2-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
|
||
<button class="btn primary" id="p2-tr-go">Проверить</button>
|
||
<button class="btn" id="p2-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p2-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 5 — Босс §2 */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §2</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p2-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p2-read-btn" onclick="addXp(10,'p2-read');bumpProgress('p2',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §2 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p1','p3');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: построение == */
|
||
(function(){
|
||
const mSl=document.getElementById('p2-m-sl');
|
||
const nSl=document.getElementById('p2-n-sl');
|
||
const mVal=document.getElementById('p2-m-val');
|
||
const nVal=document.getElementById('p2-n-val');
|
||
const svgWrap=document.getElementById('p2-build-svg');
|
||
const infoEl=document.getElementById('p2-build-info');
|
||
function draw(){
|
||
const m=+mSl.value, n=+nSl.value;
|
||
mVal.textContent=m; nVal.textContent=n;
|
||
const W=320, H=140;
|
||
const Ax=24, Ay=50, Bx=296, By=50;
|
||
const AB=Bx-Ax;
|
||
const Cx=Ax+m/(m+n)*AB;
|
||
const Cy=50;
|
||
// луч AK: вниз под углом 30°
|
||
const rayLen=(m+n)*22;
|
||
const rayAngle=Math.PI/6;
|
||
const Kx=Ax+rayLen*Math.cos(rayAngle);
|
||
const Ky=Ay+rayLen*Math.sin(rayAngle);
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
// отрезок AB
|
||
s+=`<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#7c3aed" stroke-width="2.5"/>`;
|
||
s+=`<circle cx="${Ax}" cy="${Ay}" r="4" fill="#7c3aed"/>`;
|
||
s+=`<circle cx="${Bx}" cy="${By}" r="4" fill="#7c3aed"/>`;
|
||
s+=`<text x="${Ax}" y="${Ay-8}" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">A</text>`;
|
||
s+=`<text x="${Bx}" y="${By-8}" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">B</text>`;
|
||
// луч AK
|
||
s+=`<line x1="${Ax}" y1="${Ay}" x2="${Kx}" y2="${Ky}" stroke="#f59e0b" stroke-width="1.5"/>`;
|
||
// точки P1..P(m+n) на луче
|
||
for(let i=1;i<=m+n;i++){
|
||
const px=Ax+i*22*Math.cos(rayAngle);
|
||
const py=Ay+i*22*Math.sin(rayAngle);
|
||
const isM=(i===m);
|
||
s+=`<circle cx="${px}" cy="${py}" r="${isM?5:3}" fill="${isM?'#10b981':'#f59e0b'}"/>`;
|
||
s+=`<text x="${px+6}" y="${py+4}" font-size="8" fill="${isM?'#047857':'#b45309'}" font-weight="${isM?'700':'400'}">P${i}${isM?' (m)':''}</text>`;
|
||
}
|
||
// линия P(m+n)→B
|
||
const Pmn_x=Ax+(m+n)*22*Math.cos(rayAngle);
|
||
const Pmn_y=Ay+(m+n)*22*Math.sin(rayAngle);
|
||
s+=`<line x1="${Pmn_x}" y1="${Pmn_y}" x2="${Bx}" y2="${By}" stroke="#8b5cf6" stroke-width="1.3" stroke-dasharray="4,3"/>`;
|
||
// параллельная через Pm → C
|
||
const Pm_x=Ax+m*22*Math.cos(rayAngle);
|
||
const Pm_y=Ay+m*22*Math.sin(rayAngle);
|
||
s+=`<line x1="${Pm_x}" y1="${Pm_y}" x2="${Cx}" y2="${Cy}" stroke="#10b981" stroke-width="2" stroke-dasharray="4,3"/>`;
|
||
// точка C
|
||
s+=`<circle cx="${Cx}" cy="${Cy}" r="6" fill="#10b981"/>`;
|
||
s+=`<text x="${Cx}" y="${Cy-10}" text-anchor="middle" font-size="11" fill="#047857" font-weight="700">C</text>`;
|
||
// метки AC, CB
|
||
s+=`<line x1="${Ax}" y1="${Ay+14}" x2="${Cx}" y2="${Cy+14}" stroke="#10b981" stroke-width="1.5"/>`;
|
||
s+=`<line x1="${Cx}" y1="${Cy+14}" x2="${Bx}" y2="${By+14}" stroke="#8b5cf6" stroke-width="1.5"/>`;
|
||
s+=`<text x="${(Ax+Cx)/2}" y="${Cy+26}" text-anchor="middle" font-size="10" fill="#047857" font-weight="700">m=${m}</text>`;
|
||
s+=`<text x="${(Cx+Bx)/2}" y="${Cy+26}" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="700">n=${n}</text>`;
|
||
s+='</svg>';
|
||
svgWrap.innerHTML=s;
|
||
const AClen=fmt(m/(m+n)*100);
|
||
const CBlen=fmt(n/(m+n)*100);
|
||
infoEl.innerHTML=`Отношение $AC:CB = ${m}:${n}$. Если $AB=100$, то $AC=${AClen}$, $CB=${CBlen}$.`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p2-build');
|
||
}
|
||
mSl.addEventListener('input',draw);
|
||
nSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: калькулятор == */
|
||
(function(){
|
||
document.getElementById('p2-lcalc').addEventListener('click',()=>{
|
||
const AB=parseFloat(document.getElementById('p2-lab').value);
|
||
const m=parseFloat(document.getElementById('p2-lm').value);
|
||
const n=parseFloat(document.getElementById('p2-ln').value);
|
||
const out=document.getElementById('p2-lcalc-out');
|
||
if(!isFinite(AB)||!isFinite(m)||!isFinite(n)||AB<=0||m<=0||n<=0){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;
|
||
}
|
||
const AC=m/(m+n)*AB;
|
||
const CB=n/(m+n)*AB;
|
||
out.style.display='block';
|
||
out.innerHTML=`$AC = \\dfrac{m}{m+n}\\cdot AB = \\dfrac{${fmt(m)}}{${fmt(m+n)}}\\cdot ${fmt(AB)} = ${fmt(AC)}$<br>$CB = \\dfrac{${fmt(n)}}{${fmt(m+n)}}\\cdot ${fmt(AB)} = ${fmt(CB)}$`;
|
||
renderMath(out);
|
||
addXp(2,'p2-calc');bumpProgress('p2',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Даны точки $A$ и $B$ на прямой. Хотим найти точку $C$ такую, что $AC:CB = m:n$.',
|
||
svg:`<svg viewBox="0 0 280 70" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><line x1="20" y1="35" x2="260" y2="35" stroke="#7c3aed" stroke-width="2"/><circle cx="20" cy="35" r="4" fill="#7c3aed"/><circle cx="260" cy="35" r="4" fill="#7c3aed"/><text x="20" y="27" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">A</text><text x="260" y="27" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">B</text><text x="140" y="55" text-anchor="middle" font-size="10" fill="#6d28d9">AC : CB = m : n = ?</text></svg>`},
|
||
{desc:'<b>Шаг 2.</b> Проводим из $A$ луч $AK$ и откладываем $m+n$ равных единичных отрезков. Последняя точка — $P_{m+n}$, средняя (после $m$ шагов) — $P_m$.',
|
||
svg:`<svg viewBox="0 0 280 130" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><line x1="20" y1="40" x2="260" y2="40" stroke="#7c3aed" stroke-width="2"/><line x1="20" y1="40" x2="140" y2="120" stroke="#f59e0b" stroke-width="1.5"/><circle cx="44" cy="57" r="3" fill="#f59e0b"/><circle cx="68" cy="73" r="3" fill="#f59e0b"/><circle cx="92" cy="90" r="5" fill="#10b981"/><circle cx="116" cy="106" r="3" fill="#f59e0b"/><circle cx="140" cy="120" r="3" fill="#f59e0b"/><text x="96" y="88" font-size="8" fill="#047857" font-weight="700">P_m</text><text x="142" y="118" font-size="8" fill="#b45309">P_{m+n}</text><text x="20" y="32" font-size="10" fill="#6d28d9" font-weight="700">A</text><text x="256" y="32" font-size="10" fill="#6d28d9" font-weight="700">B</text></svg>`},
|
||
{desc:'<b>Шаг 3.</b> Соединяем $P_{m+n}$ с $B$. Через $P_m$ проводим прямую, параллельную $P_{m+n}B$. По теореме Фалеса она пересекает $AB$ в точке $C$, делящей $AB$ в отношении $m:n$.',
|
||
svg:`<svg viewBox="0 0 280 130" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><line x1="20" y1="40" x2="260" y2="40" stroke="#7c3aed" stroke-width="2"/><line x1="20" y1="40" x2="140" y2="120" stroke="#f59e0b" stroke-width="1.5"/><line x1="140" y1="120" x2="260" y2="40" stroke="#8b5cf6" stroke-width="1.3" stroke-dasharray="4,3"/><line x1="92" y1="90" x2="116" y2="40" stroke="#10b981" stroke-width="2" stroke-dasharray="4,3"/><circle cx="116" cy="40" r="6" fill="#10b981"/><text x="116" y="32" text-anchor="middle" font-size="11" fill="#047857" font-weight="700">C</text><circle cx="92" cy="90" r="4" fill="#10b981"/><circle cx="140" cy="120" r="4" fill="#f59e0b"/><text x="92" y="88" font-size="8" fill="#047857">P_m</text><text x="20" y="32" font-size="10" fill="#6d28d9" font-weight="700">A</text><text x="256" y="32" font-size="10" fill="#6d28d9" font-weight="700">B</text></svg>`},
|
||
{desc:'<b>Шаг 4.</b> Итог: по теореме Фалеса $\\dfrac{AC}{CB}=\\dfrac{m}{n}$. Координаты точки $C$: $C_x = \\dfrac{n\\,x_A+m\\,x_B}{m+n}$, $C_y = \\dfrac{n\\,y_A+m\\,y_B}{m+n}$. <b>Доказано.</b>',
|
||
svg:`<svg viewBox="0 0 280 70" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><line x1="20" y1="35" x2="260" y2="35" stroke="#7c3aed" stroke-width="2"/><circle cx="20" cy="35" r="4" fill="#7c3aed"/><circle cx="260" cy="35" r="4" fill="#7c3aed"/><circle cx="116" cy="35" r="6" fill="#10b981"/><text x="20" y="27" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">A</text><text x="116" y="27" text-anchor="middle" font-size="11" fill="#047857" font-weight="700">C</text><text x="260" y="27" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">B</text><text x="140" y="58" text-anchor="middle" font-size="10" fill="#047857" font-weight="700">C = (n·A + m·B) / (m+n)</text></svg>`},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p2-proof-svg');
|
||
const descEl=document.getElementById('p2-proof-desc');
|
||
function show(){
|
||
svgEl.innerHTML=steps[step].svg;
|
||
descEl.innerHTML=steps[step].desc;
|
||
renderMath(descEl);
|
||
}
|
||
document.getElementById('p2-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p2-proof-step');}
|
||
else{addXp(5,'p2-proof-done');bumpProgress('p2',10);}
|
||
});
|
||
document.getElementById('p2-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'Отрезок $AB=20$ делится точкой $C$ в отношении $1:4$. Найди $AC$.', ans:4, hint:'AC = 1/(1+4)·20 = 4.'},
|
||
{q:'$AB=15$, $AC:CB=2:3$. Найди $CB$.', ans:9, hint:'CB = 3/(2+3)·15 = 9.'},
|
||
{q:'$A=(0,0)$, $B=(8,0)$, деление $3:1$. Найди $x$-координату точки $C$.', ans:6, hint:'C_x = (1·0+3·8)/4 = 6.'},
|
||
{q:'Отрезок $AB=30$ делится в отношении $2:1$. Найди расстояние от $C$ до $B$.', ans:10, hint:'CB = 1/(2+1)·30 = 10.'},
|
||
{q:'$A=(0,0)$, $B=(0,12)$, деление $1:2$. Найди $y$-координату точки $C$.', ans:4, hint:'C_y = (2·0+1·12)/3 = 4.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p2-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p2-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p2-tr-ans').value='';
|
||
document.getElementById('p2-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p2-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p2-tr-score').textContent=0;show();});
|
||
document.getElementById('p2-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p2-tr-ans').value;
|
||
const fb=document.getElementById('p2-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.01){
|
||
score++;document.getElementById('p2-tr-score').textContent=score;
|
||
addXp(3,'p2-tr-'+idx);bumpProgress('p2',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p2-tr-all');bumpProgress('p2',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p2-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p2-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT: Босс §2 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'$AB=24$, деление в отношении $5:3$. Найди $AC$.', ans:15, hint:'AC = 5/8·24 = 15.'},
|
||
{q:'$A=(0,0)$, $B=(10,10)$, деление $3:2$. Найди $x_C+y_C$.', ans:12, hint:'C_x=6, C_y=6, сумма=12.'},
|
||
{q:'Точка $C$ делит $AB$ в отношении $AC:CB=4:1$. $CB=7$. Найди $AB$.', ans:35, hint:'AB = (4+1)·7 = 35.'},
|
||
{q:'$AB=100$, $C$ делит $AB$ в отношении $3:7$. Найди $BC$.', ans:70, hint:'BC = 7/10·100 = 70.'},
|
||
];
|
||
const bossBox=document.getElementById('p2-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p2b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p2b-a${i}').value;
|
||
const fb=document.getElementById('p2b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.01){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p2BossSolved.has(${i})){ window.p2BossSolved.add(${i}); addXp(5,'p2-boss${i}'); bumpProgress('p2',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p2b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p2BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
function buildP3(){
|
||
const box=document.getElementById('p3-body');
|
||
let html='';
|
||
|
||
html+=makeCard('theory','Определение подобных треугольников','3.1',`
|
||
<p><b>Определение.</b> Треугольники $\\triangle ABC$ и $\\triangle A'B'C'$ называются <b>подобными</b> ($\\triangle ABC \\sim \\triangle A'B'C'$), если:</p>
|
||
<ol style="margin-left:18px;margin-top:6px;line-height:2">
|
||
<li>Соответственные углы равны: $\\angle A = \\angle A'$, $\\angle B = \\angle B'$, $\\angle C = \\angle C'$.</li>
|
||
<li>Соответственные стороны пропорциональны: $\\dfrac{a}{a'} = \\dfrac{b}{b'} = \\dfrac{c}{c'} = k$,</li>
|
||
</ol>
|
||
<p style="margin-top:6px">где $k > 0$ — <b>коэффициент подобия</b>.</p>
|
||
<p style="margin-top:8px"><b>Обозначения:</b> стороны треугольника: $a=BC$, $b=CA$, $c=AB$ и $a'=B'C'$, $b'=C'A'$, $c'=A'B'$.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 360 155" style="max-width:380px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- большой треугольник ABC: A=(80,25), B=(20,135), C=(195,135) -->
|
||
<!-- BC=175, AB≈sqrt(60²+110²)≈125, AC≈sqrt(115²+110²)≈160 -->
|
||
<polygon points="80,25 20,135 195,135" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="2"/>
|
||
<text x="80" y="17" text-anchor="middle" font-size="11" font-weight="700" fill="#6d28d9">A</text>
|
||
<text x="8" y="148" font-size="11" font-weight="700" fill="#6d28d9">B</text>
|
||
<text x="198" y="148" font-size="11" font-weight="700" fill="#6d28d9">C</text>
|
||
<!-- малый треугольник A'B'C' (k=2.5): вправо от большого, нет перекрытий -->
|
||
<!-- B'=(245,135), C'=(315,135), A'=(B'+35,135-88)=(280,47) -->
|
||
<!-- B'C'=70=175/2.5✓, |A'B'|=sqrt(35²+88²)≈95/2.5=50≈50✓, |A'C'|=sqrt(35²+88²)≈64≈160/2.5=64✓ -->
|
||
<polygon points="280,47 245,135 315,135" fill="rgba(139,92,246,.15)" stroke="#8b5cf6" stroke-width="1.8"/>
|
||
<text x="280" y="39" text-anchor="middle" font-size="10" font-weight="700" fill="#8b5cf6">A'</text>
|
||
<text x="233" y="148" font-size="10" font-weight="700" fill="#8b5cf6">B'</text>
|
||
<text x="318" y="148" font-size="10" font-weight="700" fill="#8b5cf6">C'</text>
|
||
<!-- коэффициент подобия -->
|
||
<text x="178" y="14" text-anchor="middle" font-size="9" fill="#6d28d9">k≈2.5: a/a'=b/b'=c/c'</text>
|
||
<!-- равенство углов -->
|
||
<text x="28" y="128" font-size="8" fill="#6d28d9">∠B</text>
|
||
<text x="253" y="128" font-size="8" fill="#8b5cf6">∠B'</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Коэффициент подобия и свойства','3.2',`
|
||
<p><b>Коэффициент подобия</b> $k = \\dfrac{a}{a'} = \\dfrac{b}{b'} = \\dfrac{c}{c'}$ показывает, во сколько раз стороны одного треугольника больше соответственных сторон другого.</p>
|
||
<p style="margin-top:8px"><b>Свойства подобия (отношение эквивалентности):</b></p>
|
||
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
|
||
<li><b>Рефлексивность:</b> $\\triangle ABC \\sim \\triangle ABC$ (с $k=1$).</li>
|
||
<li><b>Симметричность:</b> если $\\triangle ABC \\sim \\triangle A'B'C'$ с коэффициентом $k$, то $\\triangle A'B'C' \\sim \\triangle ABC$ с коэффициентом $\\tfrac{1}{k}$.</li>
|
||
<li><b>Транзитивность:</b> если $\\triangle ABC \\sim \\triangle A'B'C'$ и $\\triangle A'B'C' \\sim \\triangle A''B''C''$, то $\\triangle ABC \\sim \\triangle A''B''C''$.</li>
|
||
</ul>`);
|
||
|
||
html+=makeCard('example','Пример','3.3',`
|
||
<p><b>Пример.</b> $\\triangle ABC$: стороны $6, 8, 10$. $\\triangle A'B'C'$: стороны $3, 4, 5$. Подобны ли треугольники?</p>
|
||
<p style="margin-top:6px">$\\dfrac{6}{3}=2,\\; \\dfrac{8}{4}=2,\\; \\dfrac{10}{5}=2$ — отношения равны. Значит, $\\triangle ABC \\sim \\triangle A'B'C'$ с коэффициентом $k=2$.</p>
|
||
<p style="margin-top:8px"><b>Пример 2.</b> Треугольники $5,7,9$ и $10,15,18$ — подобны ли?</p>
|
||
<p>$10/5=2$, $15/7\\approx 2.14$ — отношения неравны. <b>Не подобны.</b></p>`);
|
||
|
||
/* ИНТЕРАКТИВ 1 — SVG два треугольника с slider k */
|
||
html+=`<div class="wg" id="p3-sim-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Два подобных треугольника — коэффициент k</div></div>
|
||
<div class="wg-help">Меняй коэффициент подобия $k$ — второй треугольник масштабируется. Углы всегда равны, стороны пропорциональны.</div>
|
||
<div class="sliders">
|
||
<label>Коэффициент k = <b id="p3-k-val">1.5</b>
|
||
<input type="range" min="5" max="30" value="15" id="p3-k-sl" step="1">
|
||
</label>
|
||
</div>
|
||
<div id="p3-sim-svg" style="display:flex;justify-content:center"></div>
|
||
<div id="p3-sim-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 2 — Калькулятор */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор подобия</div></div>
|
||
<div class="wg-help">Введи стороны одного треугольника и коэффициент $k$ — получи стороны подобного.</div>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(80px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">a</span><input type="number" id="p3-ca" class="tinp" placeholder="a" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">b</span><input type="number" id="p3-cb" class="tinp" placeholder="b" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">c</span><input type="number" id="p3-cc" class="tinp" placeholder="c" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">k</span><input type="number" id="p3-ck" class="tinp" placeholder="k" style="width:100%" min="0.01"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p3-ccalc" style="width:100%">Вычислить</button></div>
|
||
</div>
|
||
<div id="p3-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 3 — DnD-сортер подобные / неподобные */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Подобные или нет? — Сортировка</div></div>
|
||
<div class="wg-help">Перетащи каждую пару треугольников в нужную колонку.</div>
|
||
<div id="p3-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p3-drop-yes"><h5>Подобные</h5><div class="drop-items" id="p3-drop-yes-items"></div></div>
|
||
<div class="drop-box" id="p3-drop-no"><h5>Не подобные</h5><div class="drop-items" id="p3-drop-no-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p3-dnd-check">Проверить</button><button class="btn" id="p3-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p3-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 4 — Тренажёр */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §3 — Подобные треугольники</div></div>
|
||
<div class="wg-help">5 задач на коэффициент подобия и неизвестные стороны.</div>
|
||
<div class="score-display"><span>Задача <b id="p3-tr-i">1</b> / 5</span><span>Очки: <b id="p3-tr-score">0</b></span></div>
|
||
<div id="p3-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p3-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
|
||
<button class="btn primary" id="p3-tr-go">Проверить</button>
|
||
<button class="btn" id="p3-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p3-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 5 — Мини-квиз */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Мини-квиз: теория подобия</div></div>
|
||
<div class="wg-help">4 вопроса на проверку понимания теории.</div>
|
||
<div id="p3-quiz-body"></div>
|
||
<div class="actions"><button class="btn primary" id="p3-quiz-check">Проверить квиз</button></div>
|
||
<div class="feedback" id="p3-quiz-fb" style="display:none;margin-top:8px"></div>
|
||
</div>`;
|
||
|
||
/* ИНТЕРАКТИВ 6 — Босс §3 */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §3</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p3-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p3-read-btn" onclick="addXp(10,'p3-read');bumpProgress('p3',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §3 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p2','p4');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: два треугольника == */
|
||
(function(){
|
||
const kSl=document.getElementById('p3-k-sl');
|
||
const kVal=document.getElementById('p3-k-val');
|
||
const svgWrap=document.getElementById('p3-sim-svg');
|
||
const infoEl=document.getElementById('p3-sim-info');
|
||
// базовый треугольник T1: B=(20,120), C=(160,120), A=(80,20)
|
||
const Ax=80,Ay=20,Bx=20,By=120,Cx=160,Cy=120;
|
||
const a=Math.hypot(Cx-Bx,Cy-By); // BC
|
||
const b=Math.hypot(Ax-Cx,Ay-Cy); // CA
|
||
const c=Math.hypot(Bx-Ax,By-Ay); // AB
|
||
function draw(){
|
||
const k=+kSl.value/10;
|
||
kVal.textContent=k.toFixed(1);
|
||
// второй треугольник — те же пропорции, масштаб 1/k
|
||
// T2 anchor: B2x = Cx + 50px gap, base2 = (Cx-Bx)/k
|
||
const base1=Cx-Bx; // 140
|
||
const base2=base1/k;
|
||
const B2x=Cx+50, B2y=120;
|
||
const C2x=B2x+base2, C2y=120;
|
||
// A2: same relative shape — horizontal offset of A from B in T1 = (Ax-Bx)/base1
|
||
const A2x=B2x+(Ax-Bx)*base2/base1;
|
||
const A2y=B2y+(Ay-By)*base2/base1;
|
||
const W=Math.max(380, Math.ceil(C2x+30));
|
||
const H=160;
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
// k-label at top centre
|
||
s+=`<text x="${W/2}" y="14" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="800">k = ${k.toFixed(1)}</text>`;
|
||
// большой треугольник T1
|
||
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Cx},${Cy}" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<text x="${Ax}" y="${Ay-6}" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">A</text>`;
|
||
s+=`<text x="${Bx-12}" y="${By+4}" font-size="11" fill="#6d28d9" font-weight="700">B</text>`;
|
||
s+=`<text x="${Cx+4}" y="${Cy+4}" font-size="11" fill="#6d28d9" font-weight="700">C</text>`;
|
||
// подписи сторон T1 — OUTSIDE
|
||
s+=`<text x="${(Bx+Cx)/2}" y="${By+16}" text-anchor="middle" font-size="9" fill="#6d28d9">a=${fmt(a/10)}</text>`;
|
||
s+=`<text x="${(Ax+Bx)/2-12}" y="${(Ay+By)/2}" text-anchor="end" font-size="9" fill="#6d28d9">c=${fmt(c/10)}</text>`;
|
||
s+=`<text x="${(Ax+Cx)/2+8}" y="${(Ay+Cy)/2}" font-size="9" fill="#6d28d9">b=${fmt(b/10)}</text>`;
|
||
// второй треугольник T2 — separated to the right
|
||
const a2=a/k,b2=b/k,c2=c/k;
|
||
s+=`<polygon points="${A2x},${A2y} ${B2x},${B2y} ${C2x},${C2y}" fill="rgba(139,92,246,.15)" stroke="#8b5cf6" stroke-width="1.8"/>`;
|
||
s+=`<text x="${A2x}" y="${A2y-6}" text-anchor="middle" font-size="10" fill="#8b5cf6" font-weight="700">A'</text>`;
|
||
s+=`<text x="${B2x-12}" y="${B2y+4}" font-size="10" fill="#8b5cf6" font-weight="700">B'</text>`;
|
||
s+=`<text x="${C2x+4}" y="${C2y+4}" font-size="10" fill="#8b5cf6" font-weight="700">C'</text>`;
|
||
// подписи сторон T2 — OUTSIDE
|
||
s+=`<text x="${(B2x+C2x)/2}" y="${B2y+16}" text-anchor="middle" font-size="9" fill="#8b5cf6">a'=${fmt(a2/10)}</text>`;
|
||
s+=`<text x="${(A2x+B2x)/2-10}" y="${(A2y+B2y)/2}" text-anchor="end" font-size="9" fill="#8b5cf6">c'=${fmt(c2/10)}</text>`;
|
||
s+=`<text x="${(A2x+C2x)/2+8}" y="${(A2y+C2y)/2}" font-size="9" fill="#8b5cf6">b'=${fmt(b2/10)}</text>`;
|
||
s+='</svg>';
|
||
svgWrap.innerHTML=s;
|
||
infoEl.innerHTML=`$k=${k.toFixed(1)}$: $a/a'=k=${k.toFixed(1)} \\to a'=${fmt(a/10/k)}$, $b'=${fmt(b/10/k)}$, $c'=${fmt(c/10/k)}$. Углы всегда равны: $\\angle A=\\angle A', \\angle B=\\angle B', \\angle C=\\angle C'$.`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p3-sim');
|
||
}
|
||
kSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: калькулятор == */
|
||
(function(){
|
||
document.getElementById('p3-ccalc').addEventListener('click',()=>{
|
||
const a=parseFloat(document.getElementById('p3-ca').value);
|
||
const b=parseFloat(document.getElementById('p3-cb').value);
|
||
const c=parseFloat(document.getElementById('p3-cc').value);
|
||
const k=parseFloat(document.getElementById('p3-ck').value);
|
||
const out=document.getElementById('p3-ccalc-out');
|
||
if([a,b,c,k].some(v=>!isFinite(v)||v<=0)){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи положительные числа для a, b, c, k.</span>';return;
|
||
}
|
||
out.style.display='block';
|
||
out.innerHTML=`Стороны подобного треугольника при $k=${fmt(k)}$:<br>$a'=a/k=${fmt(a/k)}$, $b'=b/k=${fmt(b/k)}$, $c'=c/k=${fmt(c/k)}$`;
|
||
renderMath(out);
|
||
addXp(2,'p3-calc');bumpProgress('p3',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: DnD == */
|
||
(function(){
|
||
const items=[
|
||
{text:'(3,4,5) и (6,8,10)',yes:true},
|
||
{text:'(5,7,9) и (10,15,18)',yes:false},
|
||
{text:'(2,3,4) и (4,6,8)',yes:true},
|
||
{text:'(1,2,3) и (2,4,7)',yes:false},
|
||
{text:'(6,8,10) и (3,4,5)',yes:true},
|
||
];
|
||
const pool=document.getElementById('p3-dnd-pool');
|
||
const yesBox=document.getElementById('p3-drop-yes-items');
|
||
const noBox=document.getElementById('p3-drop-no-items');
|
||
let dragging=null;
|
||
function makeChip(it,idx){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';
|
||
chip.dataset.idx=idx;
|
||
chip.textContent=it.text;
|
||
chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p3-drop-yes'),document.getElementById('p3-drop-no'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p3-drop-yes')?yesBox:box===document.getElementById('p3-drop-no')?noBox:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p3-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p3-dnd-fb');
|
||
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
|
||
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
|
||
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
|
||
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p3-dnd');bumpProgress('p3',8);}
|
||
else{feedback(fb,false,'Есть ошибки — проверь пропорциональность сторон.');}
|
||
});
|
||
document.getElementById('p3-dnd-reset').addEventListener('click',()=>{
|
||
[...yesBox.children].forEach(c=>pool.appendChild(c));
|
||
[...noBox.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p3-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'$\\triangle ABC$ со сторонами $6,8,10$ подобен $\\triangle A\'B\'C\'$ со сторонами $3,4,5$. Чему равен коэффициент подобия?', ans:2, hint:'k = 6/3 = 8/4 = 10/5 = 2.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, коэффициент $k=3$. Сторона $a=15$. Найди $a\'$.', ans:5, hint:'a\' = a/k = 15/3 = 5.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k=2$. Сторона $b\'=7$. Найди $b$.', ans:14, hint:'b = k·b\' = 2·7 = 14.'},
|
||
{q:'Стороны треугольников $4,6,8$ и $6,9,12$. Найди коэффициент подобия.', ans:1.5, hint:'k = 6/4 = 9/6 = 12/8 = 1.5.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $a=20$, $a\'=4$. Чему равен $k$?', ans:5, hint:'k = a/a\' = 20/4 = 5.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p3-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p3-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p3-tr-ans').value='';
|
||
document.getElementById('p3-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p3-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p3-tr-score').textContent=0;show();});
|
||
document.getElementById('p3-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p3-tr-ans').value;
|
||
const fb=document.getElementById('p3-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.05){
|
||
score++;document.getElementById('p3-tr-score').textContent=score;
|
||
addXp(3,'p3-tr-'+idx);bumpProgress('p3',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p3-tr-all');bumpProgress('p3',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p3-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p3-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: мини-квиз == */
|
||
(function(){
|
||
const qs=[
|
||
{q:'Коэффициент подобия равен 1. Что это означает?', opts:['Треугольники конгруэнтны','Треугольники не подобны','Треугольники равновелики по площади','Треугольники прямоугольные'], ans:0},
|
||
{q:'Если $\\triangle ABC \\sim \\triangle A\'B\'C\'$ с $k=3$, то $\\triangle A\'B\'C\' \\sim \\triangle ABC$ с коэффициентом:', opts:['3','1/3','9','1/9'], ans:1},
|
||
{q:'Что является достаточным условием подобия треугольников?', opts:['Равенство двух углов','Равенство одной стороны','Равенство периметров','Равенство площадей'], ans:0},
|
||
{q:'Подобие — это:', opts:['Отношение эквивалентности','Только рефлексивное отношение','Только транзитивное отношение','Отношение порядка'], ans:0},
|
||
];
|
||
const body=document.getElementById('p3-quiz-body');
|
||
body.innerHTML=qs.map((q,qi)=>`
|
||
<div style="margin-bottom:14px;padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border)">
|
||
<div style="font-weight:700;margin-bottom:8px;font-size:.95rem">${qi+1}. ${q.q}</div>
|
||
${q.opts.map((o,oi)=>`<label style="display:flex;align-items:center;gap:8px;margin-bottom:6px;cursor:pointer;font-size:.92rem"><input type="radio" name="p3q${qi}" value="${oi}" style="accent-color:var(--sec-acc,var(--pri))"> ${o}</label>`).join('')}
|
||
</div>`).join('');
|
||
document.getElementById('p3-quiz-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p3-quiz-fb');
|
||
let correct=0;
|
||
qs.forEach((q,qi)=>{
|
||
const sel=document.querySelector(`input[name="p3q${qi}"]:checked`);
|
||
if(sel&&+sel.value===q.ans)correct++;
|
||
});
|
||
if(correct===qs.length){
|
||
feedback(fb,true,`Все ${qs.length} верно! +10 XP`);
|
||
addXp(10,'p3-quiz');bumpProgress('p3',10);confetti();
|
||
} else {
|
||
feedback(fb,false,`Верно ${correct} из ${qs.length}. Перечитай карточки теории.`);
|
||
}
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §3 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'$\\triangle ABC$ со сторонами $9,12,15$. Коэффициент подобия с $\\triangle A\'B\'C\'$ равен $3$. Найди наименьшую сторону $\\triangle A\'B\'C\'$.', ans:3, hint:'a\' = 9/3 = 3.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$. Стороны $\\triangle A\'B\'C\'$: $5,7,x$, стороны $\\triangle ABC$: $10,14,16$. Найди $x$.', ans:8, hint:'k=2, x = 16/2 = 8.'},
|
||
{q:'Периметр $\\triangle ABC = 36$, $k=3$. Найди периметр подобного треугольника $\\triangle A\'B\'C\'$.', ans:12, hint:'P\' = P/k = 36/3 = 12.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k=4$. Сторона $c=20$. Найди $c\'$.', ans:5, hint:'c\' = c/k = 20/4 = 5.'},
|
||
];
|
||
const bossBox=document.getElementById('p3-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p3b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p3b-a${i}').value;
|
||
const fb=document.getElementById('p3b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.05){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p3BossSolved.has(${i})){ window.p3BossSolved.add(${i}); addXp(5,'p3-boss${i}'); bumpProgress('p3',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p3b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p3BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
function buildP4(){
|
||
const box=document.getElementById('p4-body');
|
||
let html='';
|
||
|
||
/* ---- Theory cards ---- */
|
||
html+=makeCard('theory','Теорема о прямой, параллельной стороне треугольника','4.1',`
|
||
<p><b>Теорема.</b> Прямая, параллельная одной из сторон треугольника и пересекающая две другие стороны, отсекает треугольник, подобный исходному.</p>
|
||
<p style="margin-top:8px"><b>Формально:</b> в $\\triangle ABC$ прямая $MN \\parallel BC$ пересекает $AB$ в точке $M$ и $AC$ в точке $N$. Тогда $\\triangle AMN \\sim \\triangle ABC$ с коэффициентом подобия:</p>
|
||
$$k = \\dfrac{AM}{AB} = \\dfrac{AN}{AC} = \\dfrac{MN}{BC}$$
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 280 175" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- triangle ABC -->
|
||
<polygon points="140,15 30,155 250,155" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="2"/>
|
||
<!-- MN line at t=0.45 -->
|
||
<!-- M on AB: M = A + 0.45*(B-A) = (140+0.45*(30-140), 15+0.45*(155-15)) = (89.5, 78) -->
|
||
<!-- N on AC: N = A + 0.45*(C-A) = (140+0.45*(250-140), 15+0.45*(155-15)) = (189.5, 78) -->
|
||
<polygon points="140,15 89.5,78 189.5,78" fill="rgba(99,102,241,.22)" stroke="#4f46e5" stroke-width="2"/>
|
||
<line x1="72" y1="78" x2="210" y2="78" stroke="#4f46e5" stroke-width="1.8" stroke-dasharray="5,3"/>
|
||
<!-- labels -->
|
||
<text x="140" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text>
|
||
<text x="22" y="165" font-size="11" font-weight="700" fill="#4338ca">B</text>
|
||
<text x="253" y="165" font-size="11" font-weight="700" fill="#4338ca">C</text>
|
||
<text x="82" y="76" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text>
|
||
<text x="196" y="76" font-size="10" font-weight="700" fill="#4f46e5">N</text>
|
||
<text x="140" y="95" text-anchor="middle" font-size="9" fill="#4f46e5">MN ∥ BC</text>
|
||
<text x="140" y="170" text-anchor="middle" font-size="9" fill="#4338ca" font-style="italic">△AMN ∼ △ABC</text>
|
||
<!-- k label -->
|
||
<text x="265" y="30" font-size="10" fill="#4f46e5" font-weight="700">k=AM/AB</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Следствие — теорема Фалеса для треугольника','4.2',`
|
||
<p><b>Следствие.</b> Если $MN \\parallel BC$ в $\\triangle ABC$, то:</p>
|
||
$$\\dfrac{AM}{MB} = \\dfrac{AN}{NC}$$
|
||
<p style="margin-top:8px">То есть прямая, параллельная стороне треугольника, делит две другие стороны пропорционально.</p>
|
||
<p style="margin-top:8px">Это прямое следствие обобщённой теоремы Фалеса: прямые $BC$, $MN$ и $A$ порождают пропорциональное деление сторон $AB$ и $AC$.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:12px">
|
||
<svg viewBox="0 0 280 155" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<polygon points="140,12 30,140 250,140" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/>
|
||
<!-- MN at t=0.5 -->
|
||
<line x1="85" y1="76" x2="195" y2="76" stroke="#4f46e5" stroke-width="2"/>
|
||
<circle cx="85" cy="76" r="3.5" fill="#4f46e5"/>
|
||
<circle cx="195" cy="76" r="3.5" fill="#4f46e5"/>
|
||
<text x="140" y="8" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text>
|
||
<text x="22" y="150" font-size="11" font-weight="700" fill="#4338ca">B</text>
|
||
<text x="253" y="150" font-size="11" font-weight="700" fill="#4338ca">C</text>
|
||
<text x="78" y="74" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text>
|
||
<text x="200" y="74" font-size="10" font-weight="700" fill="#4f46e5">N</text>
|
||
<!-- AM, MB labels -->
|
||
<text x="62" y="44" text-anchor="middle" font-size="9" fill="#4f46e5">AM</text>
|
||
<text x="56" y="112" text-anchor="middle" font-size="9" fill="#6366f1">MB</text>
|
||
<!-- AN, NC labels -->
|
||
<text x="221" y="44" text-anchor="middle" font-size="9" fill="#4f46e5">AN</text>
|
||
<text x="228" y="112" text-anchor="middle" font-size="9" fill="#6366f1">NC</text>
|
||
<text x="140" y="148" text-anchor="middle" font-size="9" fill="#4338ca" font-style="italic">AM/MB = AN/NC</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('example','Пример вычисления','4.3',`
|
||
<p><b>Пример.</b> В $\\triangle ABC$ прямая $MN \\parallel BC$. $AM = 6$, $AB = 10$, $BC = 15$. Найти $MN$.</p>
|
||
<p style="margin-top:8px"><b>Решение:</b> коэффициент подобия $k = AM/AB = 6/10 = 0{,}6$.</p>
|
||
<p style="margin-top:4px">$MN = k \\cdot BC = 0{,}6 \\cdot 15 = 9$.</p>
|
||
<p style="margin-top:8px"><b>Пример 2.</b> $AM = 4$, $MB = 6$. Найти $AN/NC$.</p>
|
||
<p style="margin-top:4px">По следствию: $AN/NC = AM/MB = 4/6 = 2/3$.</p>`);
|
||
|
||
/* ---- ИНТЕРАКТИВ 1: SVG треугольник со slider ---- */
|
||
html+=`<div class="wg" id="p4-par-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Параллельная прямая отсекает подобный треугольник</div></div>
|
||
<div class="wg-help">Перемещай прямую $MN \\parallel BC$ по высоте треугольника. Коэффициент подобия $k$ меняется — $\\triangle AMN \\sim \\triangle ABC$.</div>
|
||
<div class="sliders">
|
||
<label>Положение $MN$ (t = AM/AB): <b id="p4-t-val">0.50</b>
|
||
<input type="range" min="10" max="90" value="50" id="p4-t-sl" step="1">
|
||
</label>
|
||
</div>
|
||
<div id="p4-par-svg" style="display:flex;justify-content:center"></div>
|
||
<div id="p4-par-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
|
||
html+=`<div class="wg" id="p4-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство — по шагам</div></div>
|
||
<div class="wg-help">Нажимай «Далее» — каждый шаг раскрывает ключевую идею доказательства.</div>
|
||
<div id="p4-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p4-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p4-proof-next">Далее</button>
|
||
<button class="btn" id="p4-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 3: Калькулятор ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: параллельная сторона</div></div>
|
||
<div class="wg-help">Введи $AM$, $AB$, $BC$ → найди $MN = BC \\cdot AM/AB$. Или задай $MN$, $BC$ → найди $AM/AB$.</div>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(80px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">AM</span><input type="number" id="p4-cAM" class="tinp" placeholder="AM" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">AB</span><input type="number" id="p4-cAB" class="tinp" placeholder="AB" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">BC</span><input type="number" id="p4-cBC" class="tinp" placeholder="BC" style="width:100%"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p4-ccalc" style="width:100%">Вычислить MN</button></div>
|
||
</div>
|
||
<div id="p4-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 4: Тренажёр ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §4</div></div>
|
||
<div class="wg-help">5 задач на нахождение MN, AN, AM и отношений.</div>
|
||
<div class="score-display"><span>Задача <b id="p4-tr-i">1</b> / 5</span><span>Очки: <b id="p4-tr-score">0</b></span></div>
|
||
<div id="p4-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p4-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
|
||
<button class="btn primary" id="p4-tr-go">Проверить</button>
|
||
<button class="btn" id="p4-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p4-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 5: DnD-сортер ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Соотнеси параллельные прямые и пропорции</div></div>
|
||
<div class="wg-help">Перетащи каждую карточку: «Пропорция верна» или «Пропорция неверна».</div>
|
||
<div id="p4-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p4-drop-yes"><h5>Пропорция верна</h5><div class="drop-items" id="p4-drop-yes-items"></div></div>
|
||
<div class="drop-box" id="p4-drop-no"><h5>Пропорция неверна</h5><div class="drop-items" id="p4-drop-no-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p4-dnd-check">Проверить</button><button class="btn" id="p4-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p4-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 6: Босс §4 ---- */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §4</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p4-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p4-read-btn" onclick="addXp(10,'p4-read');bumpProgress('p4',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §4 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p3','p5');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: slider параллельной прямой == */
|
||
(function(){
|
||
const tSl=document.getElementById('p4-t-sl');
|
||
const tVal=document.getElementById('p4-t-val');
|
||
const svgWrap=document.getElementById('p4-par-svg');
|
||
const infoEl=document.getElementById('p4-par-info');
|
||
// base triangle: A=(140,15), B=(30,155), C=(250,155)
|
||
const Ax=140,Ay=15,Bx=30,By=155,Cx=250,Cy=155;
|
||
const BC=Math.hypot(Cx-Bx,Cy-By);
|
||
const AB=Math.hypot(Bx-Ax,By-Ay);
|
||
const AC=Math.hypot(Cx-Ax,Cy-Ay);
|
||
function draw(){
|
||
const t=+tSl.value/100;
|
||
tVal.textContent=t.toFixed(2);
|
||
const Mx=Ax+t*(Bx-Ax), My=Ay+t*(By-Ay);
|
||
const Nx=Ax+t*(Cx-Ax), Ny=Ay+t*(Cy-Ay);
|
||
const MN=Math.hypot(Nx-Mx,Ny-My);
|
||
const AM=Math.hypot(Mx-Ax,My-Ay);
|
||
const AN=Math.hypot(Nx-Ax,Ny-Ay);
|
||
const W=300, H=180;
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
// full triangle light
|
||
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Cx},${Cy}" fill="rgba(99,102,241,.07)" stroke="#6366f1" stroke-width="1.5"/>`;
|
||
// inner triangle AMN highlighted
|
||
s+=`<polygon points="${Ax},${Ay} ${Mx},${My} ${Nx},${Ny}" fill="rgba(79,70,229,.22)" stroke="#4f46e5" stroke-width="2"/>`;
|
||
// MN line
|
||
s+=`<line x1="${Mx}" y1="${My}" x2="${Nx}" y2="${Ny}" stroke="#4f46e5" stroke-width="2"/>`;
|
||
// points
|
||
s+=`<circle cx="${Mx}" cy="${My}" r="4" fill="#4f46e5"/>`;
|
||
s+=`<circle cx="${Nx}" cy="${Ny}" r="4" fill="#4f46e5"/>`;
|
||
// labels
|
||
s+=`<text x="${Ax}" y="${Ay-5}" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text>`;
|
||
s+=`<text x="${Bx-8}" y="${By+2}" font-size="11" font-weight="700" fill="#4338ca">B</text>`;
|
||
s+=`<text x="${Cx+4}" y="${Cy+2}" font-size="11" font-weight="700" fill="#4338ca">C</text>`;
|
||
s+=`<text x="${Mx-8}" y="${My}" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text>`;
|
||
s+=`<text x="${Nx+4}" y="${Ny}" font-size="10" font-weight="700" fill="#4f46e5">N</text>`;
|
||
// k badge
|
||
s+=`<text x="${W/2}" y="14" text-anchor="middle" font-size="11" font-weight="800" fill="#4338ca">k = ${t.toFixed(2)}</text>`;
|
||
s+='</svg>';
|
||
svgWrap.innerHTML=s;
|
||
infoEl.innerHTML=`$k = AM/AB = ${t.toFixed(3)}$. $MN = k \\cdot BC = ${t.toFixed(3)} \\cdot ${fmt(BC/10)} = ${fmt(MN/10)}$. <br> $AM/MB = ${fmt(t/(1-t+1e-9))}$. По следствию: $AN/NC = AM/MB = ${fmt(t/(1-t+1e-9))}$.`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p4-par');
|
||
}
|
||
tSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Дан $\\triangle ABC$. Прямая $MN \\parallel BC$ пересекает $AB$ в $M$ и $AC$ в $N$. Требуется доказать $\\triangle AMN \\sim \\triangle ABC$.',
|
||
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/><line x1="78" y1="81" x2="182" y2="81" stroke="#4f46e5" stroke-width="2" stroke-dasharray="5,3"/><circle cx="78" cy="81" r="3.5" fill="#4f46e5"/><circle cx="182" cy="81" r="3.5" fill="#4f46e5"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><text x="130" y="97" text-anchor="middle" font-size="9" fill="#4f46e5">MN ∥ BC</text></svg>`},
|
||
{desc:'<b>Шаг 2.</b> $\\angle AMN = \\angle ABC$, так как $MN \\parallel BC$ и $AB$ — секущая: это соответственные углы при параллельных прямых и секущей.',
|
||
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/><line x1="78" y1="81" x2="182" y2="81" stroke="#4f46e5" stroke-width="2"/><circle cx="78" cy="81" r="3.5" fill="#4f46e5"/><circle cx="182" cy="81" r="3.5" fill="#4f46e5"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><path d="M78,81 Q88,88 83,95" fill="none" stroke="#f59e0b" stroke-width="2"/><path d="M25,148 Q38,138 33,128" fill="none" stroke="#f59e0b" stroke-width="2"/><text x="96" y="100" font-size="9" fill="#b45309" font-weight="700">∠AMN = ∠ABC</text></svg>`},
|
||
{desc:'<b>Шаг 3.</b> Аналогично $\\angle ANM = \\angle ACB$: $MN \\parallel BC$ и $AC$ — секущая, получаем соответственные углы.',
|
||
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/><line x1="78" y1="81" x2="182" y2="81" stroke="#4f46e5" stroke-width="2"/><circle cx="78" cy="81" r="3.5" fill="#4f46e5"/><circle cx="182" cy="81" r="3.5" fill="#4f46e5"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><path d="M182,81 Q172,88 177,95" fill="none" stroke="#10b981" stroke-width="2"/><path d="M235,148 Q222,138 227,128" fill="none" stroke="#10b981" stroke-width="2"/><text x="130" y="100" text-anchor="middle" font-size="9" fill="#047857" font-weight="700">∠ANM = ∠ACB</text></svg>`},
|
||
{desc:'<b>Шаг 4.</b> Угол $\\angle A$ общий у $\\triangle AMN$ и $\\triangle ABC$. Два угла $\\triangle AMN$ равны соответствующим двум углам $\\triangle ABC$ → по признаку по двум углам $\\triangle AMN \\sim \\triangle ABC$.',
|
||
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="1.5"/><polygon points="130,14 78,81 182,81" fill="rgba(79,70,229,.22)" stroke="#4f46e5" stroke-width="2"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><text x="130" y="95" text-anchor="middle" font-size="9" fill="#4f46e5">△AMN ∼ △ABC</text></svg>`},
|
||
{desc:'<b>Шаг 5.</b> Из подобия следует пропорциональность сторон: $AM/AB = AN/AC = MN/BC = k$. Следствие: $AM/MB = AN/NC$ — прямое следствие теоремы Фалеса. <b>Доказано.</b>',
|
||
svg:`<svg viewBox="0 0 260 80" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="130" y="24" text-anchor="middle" font-size="11" font-weight="800" fill="#4338ca">AM/AB = AN/AC = MN/BC = k</text><text x="130" y="46" text-anchor="middle" font-size="10" fill="#4f46e5" font-weight="700">AM/MB = AN/NC</text><text x="130" y="68" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">QED ∎</text></svg>`},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p4-proof-svg');
|
||
const descEl=document.getElementById('p4-proof-desc');
|
||
function show(){
|
||
svgEl.innerHTML=steps[step].svg;
|
||
descEl.innerHTML=steps[step].desc;
|
||
renderMath(descEl);
|
||
}
|
||
document.getElementById('p4-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p4-proof-step');}
|
||
else{addXp(5,'p4-proof-done');bumpProgress('p4',10);}
|
||
});
|
||
document.getElementById('p4-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: калькулятор == */
|
||
(function(){
|
||
document.getElementById('p4-ccalc').addEventListener('click',()=>{
|
||
const AM=parseFloat(document.getElementById('p4-cAM').value);
|
||
const AB=parseFloat(document.getElementById('p4-cAB').value);
|
||
const BC=parseFloat(document.getElementById('p4-cBC').value);
|
||
const out=document.getElementById('p4-ccalc-out');
|
||
if(!isFinite(AM)||!isFinite(AB)||!isFinite(BC)||AM<=0||AB<=0||BC<=0||AM>AB){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи положительные числа; AM должно быть ≤ AB.</span>';return;
|
||
}
|
||
const k=AM/AB;
|
||
const MN=k*BC;
|
||
const AN_over_NC=AM/(AB-AM);
|
||
out.style.display='block';
|
||
out.innerHTML=`$k = AM/AB = ${fmt(AM)}/${fmt(AB)} = ${fmt(k)}$<br>$MN = k \\cdot BC = ${fmt(k)} \\cdot ${fmt(BC)} = ${fmt(MN)}$<br>Следствие: $AM/MB = AN/NC = ${fmt(AM)}/${fmt(AB-AM)} = ${fmt(AN_over_NC)}$`;
|
||
renderMath(out);
|
||
addXp(2,'p4-calc');bumpProgress('p4',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'В $\\triangle ABC$ прямая $MN \\parallel BC$, $AM=4$, $AB=10$, $BC=20$. Найди $MN$.',ans:8,hint:'k=4/10=0.4; MN=0.4·20=8.'},
|
||
{q:'В $\\triangle ABC$ прямая $MN \\parallel BC$, $AM=6$, $AB=9$, $BC=12$. Найди $MN$.',ans:8,hint:'k=6/9=2/3; MN=2/3·12=8.'},
|
||
{q:'$MN \\parallel BC$, $AM=5$, $MB=10$. Найди $AN/NC$.',ans:0.5,hint:'AN/NC = AM/MB = 5/10 = 0.5.'},
|
||
{q:'$MN \\parallel BC$, $k=0.4$, $BC=30$. Найди $MN$.',ans:12,hint:'MN=k·BC=0.4·30=12.'},
|
||
{q:'$MN \\parallel BC$, $AM=3$, $MB=6$. Чему равно $AN/AC$?',ans:0.333,hint:'AN/AC = AM/AB = 3/(3+6) = 1/3 ≈ 0.333.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p4-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p4-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p4-tr-ans').value='';
|
||
document.getElementById('p4-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p4-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p4-tr-score').textContent=0;show();});
|
||
document.getElementById('p4-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p4-tr-ans').value;
|
||
const fb=document.getElementById('p4-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.01){
|
||
score++;document.getElementById('p4-tr-score').textContent=score;
|
||
addXp(3,'p4-tr-'+idx);bumpProgress('p4',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p4-tr-all');bumpProgress('p4',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p4-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p4-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: DnD-сортер == */
|
||
(function(){
|
||
const items=[
|
||
{text:'MN∥BC, AM=3, AB=6, AN=4, AC=8 → AM/MB=AN/NC',yes:true},
|
||
{text:'MN∥BC, AM=4, MB=6, AN=3, NC=5 → AM/MB≠AN/NC',yes:false},
|
||
{text:'MN∥BC, AM/AB=0.5, MN/BC=0.5',yes:true},
|
||
{text:'MN∥BC, AM=2, MB=4, AN=3, NC=6 → AM/MB=AN/NC',yes:true},
|
||
{text:'MN∥BC, k=1/3, MN=BC/2',yes:false},
|
||
];
|
||
const pool=document.getElementById('p4-dnd-pool');
|
||
const yesBox=document.getElementById('p4-drop-yes-items');
|
||
const noBox=document.getElementById('p4-drop-no-items');
|
||
let dragging=null;
|
||
function makeChip(it,idx){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';
|
||
chip.dataset.idx=idx;
|
||
chip.textContent=it.text;
|
||
chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p4-drop-yes'),document.getElementById('p4-drop-no'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p4-drop-yes')?yesBox:box===document.getElementById('p4-drop-no')?noBox:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p4-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p4-dnd-fb');
|
||
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
|
||
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
|
||
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
|
||
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p4-dnd');bumpProgress('p4',8);}
|
||
else{feedback(fb,false,'Есть ошибки. Проверь: MN∥BC → AM/MB=AN/NC и MN/BC=AM/AB.');}
|
||
});
|
||
document.getElementById('p4-dnd-reset').addEventListener('click',()=>{
|
||
[...yesBox.children].forEach(c=>pool.appendChild(c));
|
||
[...noBox.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p4-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §4 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'<svg viewBox="0 0 240 140" style="display:block;max-width:240px;margin:0 auto 8px;background:#e0e7ff;border:1px solid #a5b4fc;border-radius:8px"><polygon points="120,12 20,128 220,128" fill="rgba(99,102,241,.12)" stroke="#6366f1" stroke-width="2"/><line x1="70" y1="70" x2="170" y2="70" stroke="#4f46e5" stroke-width="2"/><text x="120" y="8" text-anchor="middle" font-size="10" fill="#4338ca" font-weight="700">A</text><text x="12" y="136" font-size="10" fill="#4338ca" font-weight="700">B</text><text x="222" y="136" font-size="10" fill="#4338ca" font-weight="700">C</text><text x="62" y="68" text-anchor="end" font-size="10" fill="#4f46e5" font-weight="700">M</text><text x="174" y="68" font-size="10" fill="#4f46e5" font-weight="700">N</text><text x="120" y="90" text-anchor="middle" font-size="9" fill="#4f46e5">AM=5, AB=8, BC=24</text></svg>$MN \\parallel BC$. $AM=5$, $AB=8$, $BC=24$. Найди $MN$.',ans:15,hint:'k=5/8; MN=5/8·24=15.'},
|
||
{q:'$MN \\parallel BC$, $AM=6$, $MB=9$. Найди $AN/NC$.',ans:0.667,hint:'AN/NC = AM/MB = 6/9 = 2/3 ≈ 0.667.'},
|
||
{q:'$MN \\parallel BC$, $MN=8$, $BC=12$. Найди $AM/AB$.',ans:0.667,hint:'AM/AB = MN/BC = 8/12 = 2/3 ≈ 0.667.'},
|
||
{q:'В $\\triangle ABC$ прямая $MN \\parallel BC$, $AM=3$, $AB=9$, $BC=18$. Найди $MN$.',ans:6,hint:'k=3/9=1/3; MN=1/3·18=6.'},
|
||
];
|
||
const bossBox=document.getElementById('p4-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p4b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p4b-a${i}').value;
|
||
const fb=document.getElementById('p4b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.01){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p4BossSolved.has(${i})){ window.p4BossSolved.add(${i}); addXp(5,'p4-boss${i}'); bumpProgress('p4',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p4b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p4BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
|
||
function buildP5(){
|
||
const box=document.getElementById('p5-body');
|
||
let html='';
|
||
|
||
/* ---- Theory cards ---- */
|
||
html+=makeCard('theory','Первый признак подобия треугольников — по двум углам (УУ)','5.1',`
|
||
<p><b>Теорема (1-й признак подобия).</b> Если два угла одного треугольника соответственно равны двум углам другого треугольника, то такие треугольники подобны.</p>
|
||
<p style="margin-top:8px">Если $\\angle A = \\angle A'$ и $\\angle B = \\angle B'$, то $\\triangle ABC \\sim \\triangle A'B'C'$.</p>
|
||
<p style="margin-top:8px"><b>Почему достаточно двух углов?</b> Сумма углов треугольника равна $180°$. Если два угла равны, третий автоматически тоже равен: $\\angle C = 180° - \\angle A - \\angle B = 180° - \\angle A' - \\angle B' = \\angle C'$.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 360 160" style="max-width:380px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- большой треугольник ABC: A=(100,30), B=(30,145), C=(195,145) -->
|
||
<!-- BC=165, AB≈sqrt(70²+115²)≈135, AC≈sqrt(95²+115²)≈149 -->
|
||
<polygon points="100,30 30,145 195,145" fill="rgba(79,70,229,.11)" stroke="#4f46e5" stroke-width="2"/>
|
||
<text x="100" y="22" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text>
|
||
<text x="18" y="155" font-size="11" font-weight="700" fill="#4338ca">B</text>
|
||
<text x="198" y="155" font-size="11" font-weight="700" fill="#4338ca">C</text>
|
||
<!-- угловые метки (∠A orange, ∠B green) -->
|
||
<path d="M100,30 Q112,42 105,52" fill="none" stroke="#f59e0b" stroke-width="2"/>
|
||
<path d="M30,145 Q44,134 52,140" fill="none" stroke="#10b981" stroke-width="2"/>
|
||
<!-- малый треугольник A'B'C' (k=2.5), well separated to the right -->
|
||
<!-- B'=(240,145), C'=(306,145), A'=B'+(27,46)=(267,99) -->
|
||
<!-- B'C'=66=165/2.5✓, |A'B'|=sqrt(27²+46²)≈54=135/2.5✓ -->
|
||
<polygon points="267,99 240,145 306,145" fill="rgba(99,102,241,.15)" stroke="#6366f1" stroke-width="1.8"/>
|
||
<text x="267" y="91" text-anchor="middle" font-size="10" font-weight="700" fill="#4f46e5">A'</text>
|
||
<text x="228" y="155" font-size="10" font-weight="700" fill="#4f46e5">B'</text>
|
||
<text x="309" y="155" font-size="10" font-weight="700" fill="#4f46e5">C'</text>
|
||
<!-- угловые метки (∠A'=∠A orange, ∠B'=∠B green) -->
|
||
<path d="M267,99 Q275,108 270,116" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
|
||
<path d="M240,145 Q253,135 259,140" fill="none" stroke="#10b981" stroke-width="1.5"/>
|
||
<text x="178" y="14" text-anchor="middle" font-size="9" fill="#4338ca">∠A=∠A', ∠B=∠B' → △ABC∼△A'B'C'</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Следствие: прямоугольные треугольники','5.2',`
|
||
<p><b>Следствие.</b> Два прямоугольных треугольника подобны, если у них равны острые углы (достаточно одной пары).</p>
|
||
<p style="margin-top:8px">Если $\\angle C = \\angle C' = 90°$ и $\\angle A = \\angle A'$, то $\\triangle ABC \\sim \\triangle A'B'C'$.</p>
|
||
<p style="margin-top:8px">Это потому, что прямой угол — один из двух равных углов, а второй угол задан условием.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:12px">
|
||
<svg viewBox="0 0 280 130" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- прямоугольный треугольник 1: A=(40,20), B=(40,110), C=(160,110) -->
|
||
<polygon points="40,20 40,110 160,110" fill="rgba(79,70,229,.10)" stroke="#4f46e5" stroke-width="2"/>
|
||
<!-- marker угла B (прямой) — inside polygon -->
|
||
<polyline points="40,100 50,100 50,110" fill="none" stroke="#4f46e5" stroke-width="1.5"/>
|
||
<text x="34" y="16" font-size="11" font-weight="700" fill="#4338ca">A</text>
|
||
<text x="28" y="120" font-size="11" font-weight="700" fill="#4338ca">B</text>
|
||
<text x="163" y="120" font-size="11" font-weight="700" fill="#4338ca">C</text>
|
||
<text x="36" y="116" font-size="8" fill="#4f46e5">90°</text>
|
||
<!-- прямоугольный треугольник 2: A'=(185,50), B'=(185,110), C'=(250,110) -->
|
||
<polygon points="185,50 185,110 250,110" fill="rgba(99,102,241,.15)" stroke="#6366f1" stroke-width="1.8"/>
|
||
<!-- marker прямого угла B' -->
|
||
<polyline points="185,100 195,100 195,110" fill="none" stroke="#6366f1" stroke-width="1.5"/>
|
||
<text x="178" y="46" font-size="10" font-weight="700" fill="#4f46e5">A'</text>
|
||
<text x="172" y="120" font-size="10" font-weight="700" fill="#4f46e5">B'</text>
|
||
<text x="253" y="120" font-size="10" font-weight="700" fill="#4f46e5">C'</text>
|
||
<text x="140" y="14" text-anchor="middle" font-size="9" fill="#4338ca">∠B=∠B'=90°, ∠A=∠A' → подобны</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('example','Пример применения — признак по двум углам','5.3',`
|
||
<p><b>Пример 1.</b> В $\\triangle ABC$: $\\angle A = 50°$, $\\angle B = 70°$. В $\\triangle A'B'C'$: $\\angle A' = 50°$, $\\angle C' = 60°$. Подобны ли треугольники?</p>
|
||
<p style="margin-top:6px">$\\angle C = 180° - 50° - 70° = 60°$. $\\angle B' = 180° - 50° - 60° = 70°$. Углы: $50°, 70°, 60°$ в обоих. По признаку по двум углам: $\\triangle ABC \\sim \\triangle A'C'B'$.</p>
|
||
<p style="margin-top:8px"><b>Пример 2.</b> Два прямоугольных треугольника, у одного острый угол $35°$, у другого $35°$. Подобны ли?</p>
|
||
<p style="margin-top:4px">Да. Оба имеют $90°$ и $35°$ — два совпадающих угла.</p>`);
|
||
|
||
/* ---- ИНТЕРАКТИВ 1: SVG два треугольника, слайдер углов ---- */
|
||
html+=`<div class="wg" id="p5-ang-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Два угла задают форму — первый признак</div></div>
|
||
<div class="wg-help">Задай углы $\\alpha$ и $\\beta$. Оба треугольника строятся с этими углами — они подобны. Коэффициент $k$ определяется масштабом.</div>
|
||
<div class="sliders">
|
||
<label>Угол $\\alpha$: <b id="p5-a-val">50</b>°
|
||
<input type="range" min="20" max="130" value="50" id="p5-a-sl" step="1">
|
||
</label>
|
||
<label>Угол $\\beta$: <b id="p5-b-val">60</b>°
|
||
<input type="range" min="20" max="130" value="60" id="p5-b-sl" step="1">
|
||
</label>
|
||
<label>Масштаб $k$: <b id="p5-k-val">1.8</b>
|
||
<input type="range" min="12" max="30" value="18" id="p5-k-sl" step="1">
|
||
</label>
|
||
</div>
|
||
<div id="p5-ang-svg" style="display:flex;justify-content:center"></div>
|
||
<div id="p5-ang-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
|
||
html+=`<div class="wg" id="p5-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство 1-го признака — по шагам</div></div>
|
||
<div class="wg-help">Нажимай «Далее» — шаг за шагом увидишь логику доказательства.</div>
|
||
<div id="p5-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p5-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p5-proof-next">Далее</button>
|
||
<button class="btn" id="p5-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 3: Тренажёр ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Тренажёр §5 — Признак по двум углам</div></div>
|
||
<div class="wg-help">5 задач на подобие по углам и нахождение сторон.</div>
|
||
<div class="score-display"><span>Задача <b id="p5-tr-i">1</b> / 5</span><span>Очки: <b id="p5-tr-score">0</b></span></div>
|
||
<div id="p5-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p5-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
|
||
<button class="btn primary" id="p5-tr-go">Проверить</button>
|
||
<button class="btn" id="p5-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p5-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 4: DnD-сортер ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Подобные пары или нет? — Сортировка по углам</div></div>
|
||
<div class="wg-help">Перетащи каждую пару треугольников в нужную колонку.</div>
|
||
<div id="p5-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p5-drop-yes"><h5>Подобны (по двум углам)</h5><div class="drop-items" id="p5-drop-yes-items"></div></div>
|
||
<div class="drop-box" id="p5-drop-no"><h5>Не подобны</h5><div class="drop-items" id="p5-drop-no-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p5-dnd-check">Проверить</button><button class="btn" id="p5-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p5-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 5: Калькулятор ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Калькулятор: найти сторону через подобие по двум углам</div></div>
|
||
<div class="wg-help">Введи два угла обоих треугольников и одну сторону первого — получи соответствующую сторону второго.</div>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(100px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠A₁ (°)</span><input type="number" id="p5-cA1" class="tinp" placeholder="напр. 50" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠B₁ (°)</span><input type="number" id="p5-cB1" class="tinp" placeholder="напр. 70" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠A₂ (°)</span><input type="number" id="p5-cA2" class="tinp" placeholder="напр. 50" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠B₂ (°)</span><input type="number" id="p5-cB2" class="tinp" placeholder="напр. 70" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">сторона a₁</span><input type="number" id="p5-ca1" class="tinp" placeholder="напр. 12" style="width:100%"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p5-ccalc" style="width:100%">Найти a₂</button></div>
|
||
</div>
|
||
<div id="p5-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 6: Босс §5 ---- */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §5</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p5-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p5-read-btn" onclick="addXp(10,'p5-read');bumpProgress('p5',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §5 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p4','p6');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: слайдер углов == */
|
||
(function(){
|
||
const aSl=document.getElementById('p5-a-sl');
|
||
const bSl=document.getElementById('p5-b-sl');
|
||
const kSl=document.getElementById('p5-k-sl');
|
||
const aVal=document.getElementById('p5-a-val');
|
||
const bVal=document.getElementById('p5-b-val');
|
||
const kVal=document.getElementById('p5-k-val');
|
||
const svgWrap=document.getElementById('p5-ang-svg');
|
||
const infoEl=document.getElementById('p5-ang-info');
|
||
|
||
function buildTriFromAngles(alpha,beta,baseLen,ox,oy){
|
||
// alpha at A (left), beta at B (right)
|
||
// base AB horizontal, C above
|
||
const gamma=Math.PI-alpha-beta;
|
||
if(gamma<=0.05) return null;
|
||
// by sine rule: a/sin(alpha) = base/sin(gamma)
|
||
const sinG=Math.sin(gamma);
|
||
const AB=baseLen;
|
||
const BC=AB*Math.sin(alpha)/sinG;
|
||
const AC=AB*Math.sin(beta)/sinG;
|
||
// place A at (ox,oy), B at (ox+AB,oy)
|
||
const Ax=ox, Ay=oy;
|
||
const Bx=ox+AB, By=oy;
|
||
// C: from A at angle alpha above AB
|
||
const Cx=Ax+AC*Math.cos(alpha);
|
||
const Cy=Ay-AC*Math.sin(alpha);
|
||
return {Ax,Ay,Bx,By,Cx,Cy,AB,BC,AC};
|
||
}
|
||
|
||
function draw(){
|
||
const alpha=+aSl.value*Math.PI/180;
|
||
const beta=+bSl.value*Math.PI/180;
|
||
const k=+kSl.value/10;
|
||
aVal.textContent=+aSl.value;
|
||
bVal.textContent=+bSl.value;
|
||
kVal.textContent=k.toFixed(1);
|
||
|
||
const gamma=(Math.PI-alpha-beta)*180/Math.PI;
|
||
if(gamma<=3){
|
||
svgWrap.innerHTML='<div style="color:var(--bad);padding:10px">Сумма углов превышает 180°. Уменьши углы.</div>';
|
||
infoEl.innerHTML='Сумма углов не должна превышать 180°.';
|
||
return;
|
||
}
|
||
|
||
const W=360, H=170;
|
||
const t1=buildTriFromAngles(alpha,beta,90,20,145);
|
||
if(!t1){svgWrap.innerHTML='';return;}
|
||
const t2=buildTriFromAngles(alpha,beta,90/k,240,145);
|
||
if(!t2){svgWrap.innerHTML='';return;}
|
||
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
// triangle 1
|
||
s+=`<polygon points="${t1.Ax},${t1.Ay} ${t1.Bx},${t1.By} ${t1.Cx},${t1.Cy}" fill="rgba(79,70,229,.12)" stroke="#4f46e5" stroke-width="2"/>`;
|
||
s+=`<text x="${t1.Cx}" y="${t1.Cy-5}" text-anchor="middle" font-size="10" font-weight="700" fill="#4338ca">A</text>`;
|
||
s+=`<text x="${t1.Ax-8}" y="${t1.Ay+4}" font-size="10" font-weight="700" fill="#4338ca">B</text>`;
|
||
s+=`<text x="${t1.Bx+4}" y="${t1.By+4}" font-size="10" font-weight="700" fill="#4338ca">C</text>`;
|
||
// angle markers t1
|
||
s+=`<path d="M${t1.Cx},${t1.Cy} Q${t1.Cx+(t1.Ax-t1.Cx)*0.18+3},${t1.Cy+(t1.Ay-t1.Cy)*0.18} ${t1.Cx+(t1.Ax-t1.Cx)*0.22},${t1.Cy+(t1.Ay-t1.Cy)*0.22}" fill="none" stroke="#f59e0b" stroke-width="1.5"/>`;
|
||
s+=`<path d="M${t1.Ax},${t1.Ay} Q${t1.Ax+(t1.Cx-t1.Ax)*0.12+(t1.Bx-t1.Ax)*0.08},${t1.Ay+(t1.Cy-t1.Ay)*0.12} ${t1.Ax+(t1.Bx-t1.Ax)*0.15},${t1.Ay}" fill="none" stroke="#10b981" stroke-width="1.5"/>`;
|
||
// triangle 2 (smaller)
|
||
s+=`<polygon points="${t2.Ax},${t2.Ay} ${t2.Bx},${t2.By} ${t2.Cx},${t2.Cy}" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/>`;
|
||
s+=`<text x="${t2.Cx}" y="${t2.Cy-5}" text-anchor="middle" font-size="10" font-weight="700" fill="#4f46e5">A'</text>`;
|
||
s+=`<text x="${t2.Ax-10}" y="${t2.Ay+4}" font-size="10" font-weight="700" fill="#4f46e5">B'</text>`;
|
||
s+=`<text x="${t2.Bx+4}" y="${t2.By+4}" font-size="10" font-weight="700" fill="#4f46e5">C'</text>`;
|
||
// angle markers t2
|
||
s+=`<path d="M${t2.Cx},${t2.Cy} Q${t2.Cx+(t2.Ax-t2.Cx)*0.22+2},${t2.Cy+(t2.Ay-t2.Cy)*0.22} ${t2.Cx+(t2.Ax-t2.Cx)*0.28},${t2.Cy+(t2.Ay-t2.Cy)*0.28}" fill="none" stroke="#f59e0b" stroke-width="1.5"/>`;
|
||
s+=`<path d="M${t2.Ax},${t2.Ay} Q${t2.Ax+(t2.Cx-t2.Ax)*0.14+(t2.Bx-t2.Ax)*0.10},${t2.Ay+(t2.Cy-t2.Ay)*0.14} ${t2.Ax+(t2.Bx-t2.Ax)*0.18},${t2.Ay}" fill="none" stroke="#10b981" stroke-width="1.5"/>`;
|
||
// label
|
||
s+=`<text x="${W/2}" y="12" text-anchor="middle" font-size="10" font-weight="800" fill="#4338ca">k = ${k.toFixed(1)}</text>`;
|
||
s+='</svg>';
|
||
svgWrap.innerHTML=s;
|
||
infoEl.innerHTML=`$\\alpha=${+aSl.value}°$, $\\beta=${+bSl.value}°$, $\\gamma=${fmt(gamma)}°$. Оба треугольника имеют одинаковые углы → по признаку по двум углам они подобны. Коэффициент подобия $k=${k.toFixed(1)}$.`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p5-ang');
|
||
}
|
||
aSl.addEventListener('input',draw);
|
||
bSl.addEventListener('input',draw);
|
||
kSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Даны $\\triangle ABC$ и $\\triangle A\'B\'C\'$ с $\\angle A = \\angle A\'$ и $\\angle B = \\angle B\'$. Требуется доказать $\\triangle ABC \\sim \\triangle A\'B\'C\'$.',
|
||
svg:`<svg viewBox="0 0 320 170" style="max-width:320px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="160" y="14" text-anchor="middle" font-size="9" fill="#4338ca" font-weight="700">∠A=∠A\', ∠B=∠B\' — условие, k≈5/3</text><polygon points="82,34 22,148 168,148" fill="rgba(79,70,229,.10)" stroke="#4f46e5" stroke-width="2"/><polygon points="238,78 205,148 280,148" fill="rgba(99,102,241,.15)" stroke="#6366f1" stroke-width="1.8"/><text x="82" y="27" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="10" y="160" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="170" y="160" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="238" y="71" text-anchor="middle" font-size="10" font-weight="700" fill="#4f46e5">A\'</text><text x="193" y="160" font-size="10" font-weight="700" fill="#4f46e5">B\'</text><text x="282" y="160" font-size="10" font-weight="700" fill="#4f46e5">C\'</text></svg>`},
|
||
{desc:'<b>Шаг 2.</b> Из суммы углов треугольника: $\\angle C = 180° - \\angle A - \\angle B$ и $\\angle C\' = 180° - \\angle A\' - \\angle B\'$. Так как $\\angle A=\\angle A\'$ и $\\angle B=\\angle B\'$, получаем $\\angle C = \\angle C\'$.',
|
||
svg:`<svg viewBox="0 0 280 90" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="11" fill="#4338ca" font-weight="700">∠A+∠B+∠C = 180°</text><text x="140" y="46" text-anchor="middle" font-size="11" fill="#4f46e5" font-weight="700">∠A'+∠B'+∠C' = 180°</text><text x="140" y="72" text-anchor="middle" font-size="11" fill="#10b981" font-weight="800">∠C = 180°−∠A−∠B = 180°−∠A'−∠B' = ∠C'</text></svg>`},
|
||
{desc:'<b>Шаг 3.</b> На луче $A\'B\'$ откладываем отрезок $A\'M = AB$. Через $M$ проводим прямую, параллельную $B\'C\'$ — она встречает $A\'C\'$ в точке $N$. По теореме §4: $\\triangle A\'MN \\sim \\triangle A\'B\'C\'$.',
|
||
svg:`<svg viewBox="0 0 280 145" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="185,130 255,130 220,68" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="1.5"/><polygon points="185,130 230,130 207,99" fill="rgba(79,70,229,.22)" stroke="#4f46e5" stroke-width="2"/><line x1="207" y1="99" x2="230" y2="130" stroke="#4f46e5" stroke-width="1.5" stroke-dasharray="4,3"/><text x="218" y="63" font-size="10" font-weight="700" fill="#4f46e5">A'</text><text x="177" y="140" font-size="10" font-weight="700" fill="#4338ca">B'</text><text x="257" y="140" font-size="10" font-weight="700" fill="#4338ca">C'</text><text x="228" y="138" font-size="9" font-weight="700" fill="#4f46e5">M</text><text x="209" y="97" font-size="9" font-weight="700" fill="#4f46e5">N</text><text x="50" y="80" font-size="9" fill="#4338ca">△A'MN∼△A'B'C'</text></svg>`},
|
||
{desc:'<b>Шаг 4.</b> Поскольку $A\'M = AB$ и углы треугольников $\\triangle A\'MN$ и $\\triangle ABC$ попарно равны (все три угла), а $\\angle A\' = \\angle A$ — вершины совпадают, то $\\triangle A\'MN \\cong \\triangle ABC$ (по условию и построению).',
|
||
svg:`<svg viewBox="0 0 280 90" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="11" fill="#4338ca" font-weight="700">A'M = AB, ∠A'=∠A, ∠B'=∠B</text><text x="140" y="46" text-anchor="middle" font-size="11" fill="#4f46e5" font-weight="700">→ △A'MN ≅ △ABC (признак у-с-у)</text><text x="140" y="70" text-anchor="middle" font-size="10" fill="#6366f1">Следовательно MN = BC, A'N = AC</text></svg>`},
|
||
{desc:'<b>Шаг 5.</b> Итог: $\\triangle A\'MN \\cong \\triangle ABC$ и $\\triangle A\'MN \\sim \\triangle A\'B\'C\'$ — отсюда $\\triangle ABC \\sim \\triangle A\'B\'C\'$ (транзитивность подобия). <b>Первый признак подобия доказан.</b>',
|
||
svg:`<svg viewBox="0 0 280 80" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="12" fill="#4338ca" font-weight="800">∠A=∠A', ∠B=∠B' → △ABC ∼ △A'B'C'</text><text x="140" y="50" text-anchor="middle" font-size="10" fill="#4f46e5">Признак по двум углам — первый признак подобия</text><text x="140" y="70" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">QED ∎</text></svg>`},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p5-proof-svg');
|
||
const descEl=document.getElementById('p5-proof-desc');
|
||
function show(){
|
||
svgEl.innerHTML=steps[step].svg;
|
||
descEl.innerHTML=steps[step].desc;
|
||
renderMath(descEl);
|
||
}
|
||
document.getElementById('p5-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p5-proof-step');}
|
||
else{addXp(5,'p5-proof-done');bumpProgress('p5',10);}
|
||
});
|
||
document.getElementById('p5-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'В $\\triangle ABC$: $\\angle A=40°$, $\\angle B=70°$. В $\\triangle A\'B\'C\'$: $\\angle A\'=40°$, $\\angle B\'=70°$. Чему равен $\\angle C\'$?',ans:70,hint:'∠C\'=180−40−70=70°.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по признаку по двум углам. $AB=12$, $A\'B\'=4$. Найди коэффициент подобия $k$.',ans:3,hint:'k=AB/A\'B\'=12/4=3.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k=2.5$. Сторона $a\'=6$. Найди $a$.',ans:15,hint:'a=k·a\'=2.5·6=15.'},
|
||
{q:'Два прямоугольных треугольника. В первом острый угол $37°$, во втором $37°$. Сторона при прямом угле в первом — $10$, во втором — $6$. Найди коэффициент подобия.',ans:1.667,hint:'k=10/6≈1.667.'},
|
||
{q:'$\\angle A=\\angle A\'=55°$, $\\angle B=\\angle B\'=65°$. Сторона $c=18$ в $\\triangle ABC$, $c\'=9$ в $\\triangle A\'B\'C\'$. Найди $k$.',ans:2,hint:'k=c/c\'=18/9=2.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p5-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p5-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p5-tr-ans').value='';
|
||
document.getElementById('p5-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p5-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p5-tr-score').textContent=0;show();});
|
||
document.getElementById('p5-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p5-tr-ans').value;
|
||
const fb=document.getElementById('p5-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.02){
|
||
score++;document.getElementById('p5-tr-score').textContent=score;
|
||
addXp(3,'p5-tr-'+idx);bumpProgress('p5',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p5-tr-all');bumpProgress('p5',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p5-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p5-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: DnD-сортер == */
|
||
(function(){
|
||
const items=[
|
||
{text:'(50°,70°,60°) и (50°,70°,60°)',yes:true},
|
||
{text:'(40°,60°,80°) и (40°,50°,90°)',yes:false},
|
||
{text:'(90°,35°,55°) и (90°,35°,55°)',yes:true},
|
||
{text:'(30°,60°,90°) и (45°,45°,90°)',yes:false},
|
||
{text:'(80°,60°,40°) и (80°,40°,60°)',yes:true},
|
||
];
|
||
const pool=document.getElementById('p5-dnd-pool');
|
||
const yesBox=document.getElementById('p5-drop-yes-items');
|
||
const noBox=document.getElementById('p5-drop-no-items');
|
||
let dragging=null;
|
||
function makeChip(it,idx){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';
|
||
chip.dataset.idx=idx;
|
||
chip.textContent=it.text;
|
||
chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p5-drop-yes'),document.getElementById('p5-drop-no'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p5-drop-yes')?yesBox:box===document.getElementById('p5-drop-no')?noBox:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p5-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p5-dnd-fb');
|
||
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
|
||
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
|
||
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
|
||
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p5-dnd');bumpProgress('p5',8);}
|
||
else{feedback(fb,false,'Есть ошибки. Два треугольника подобны, если у них есть хотя бы две пары равных углов.');}
|
||
});
|
||
document.getElementById('p5-dnd-reset').addEventListener('click',()=>{
|
||
[...yesBox.children].forEach(c=>pool.appendChild(c));
|
||
[...noBox.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p5-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: калькулятор == */
|
||
(function(){
|
||
document.getElementById('p5-ccalc').addEventListener('click',()=>{
|
||
const A1=parseFloat(document.getElementById('p5-cA1').value);
|
||
const B1=parseFloat(document.getElementById('p5-cB1').value);
|
||
const A2=parseFloat(document.getElementById('p5-cA2').value);
|
||
const B2=parseFloat(document.getElementById('p5-cB2').value);
|
||
const a1=parseFloat(document.getElementById('p5-ca1').value);
|
||
const out=document.getElementById('p5-ccalc-out');
|
||
if([A1,B1,A2,B2,a1].some(v=>!isFinite(v)||v<=0)){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи все поля.</span>';return;
|
||
}
|
||
const C1=180-A1-B1, C2=180-A2-B2;
|
||
if(C1<=0||C2<=0){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Сумма углов превышает 180°.</span>';return;
|
||
}
|
||
// check similarity: sort angles and compare
|
||
const ang1=[A1,B1,C1].sort((a,b)=>a-b);
|
||
const ang2=[A2,B2,C2].sort((a,b)=>a-b);
|
||
const similar=ang1.every((v,i)=>Math.abs(v-ang2[i])<0.5);
|
||
if(!similar){
|
||
out.style.display='block';out.innerHTML=`$\\angle C_1=${fmt(C1)}°$, $\\angle C_2=${fmt(C2)}°$. Наборы углов различаются — треугольники <b>не подобны</b>. Признак по двум углам не выполнен.`;
|
||
renderMath(out);return;
|
||
}
|
||
// find matching side using sine rule: a/sin(A)=b/sin(B)
|
||
// k = a1 / (2R sin(A)) ... use ratio of sides
|
||
// match angles: find which angle in t2 corresponds to A1
|
||
// simplification: by ratio of corresponding sides via sine rule
|
||
// a1/sin(A1) = a2/sin(A2) → a2 = a1*sin(A2*pi/180)/sin(A1*pi/180)
|
||
const a2=a1*Math.sin(A2*Math.PI/180)/Math.sin(A1*Math.PI/180);
|
||
const k=a1/a2;
|
||
out.style.display='block';
|
||
out.innerHTML=`Треугольники подобны по признаку по двум углам.<br>$\\angle C_1 = ${fmt(C1)}°$, $\\angle C_2 = ${fmt(C2)}°$.<br>По теореме синусов: $a_2 = a_1 \\cdot \\dfrac{\\sin \\angle A_2}{\\sin \\angle A_1} = ${fmt(a1)} \\cdot \\dfrac{${fmt(Math.sin(A2*Math.PI/180).toFixed(4))}}{${fmt(Math.sin(A1*Math.PI/180).toFixed(4))}} = ${fmt(a2)}$.<br>Коэффициент подобия $k = a_1/a_2 = ${fmt(k)}$.`;
|
||
renderMath(out);
|
||
addXp(3,'p5-calc');bumpProgress('p5',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §5 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'<svg viewBox="0 0 240 140" style="display:block;max-width:240px;margin:0 auto 8px;background:#e0e7ff;border:1px solid #a5b4fc;border-radius:8px"><polygon points="100,30 50,125 165,125" fill="rgba(79,70,229,.12)" stroke="#4f46e5" stroke-width="2"/><polygon points="192,93 175,125 213,125" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/><text x="100" y="24" text-anchor="middle" font-size="10" fill="#4338ca" font-weight="700">A</text><text x="41" y="134" font-size="10" fill="#4338ca" font-weight="700">B</text><text x="167" y="134" font-size="10" fill="#4338ca" font-weight="700">C</text><text x="192" y="87" text-anchor="middle" font-size="9" fill="#4f46e5" font-weight="700">A\'</text><text x="168" y="134" font-size="9" fill="#4f46e5" font-weight="700">B\'</text><text x="215" y="134" font-size="9" fill="#4f46e5" font-weight="700">C\'</text><text x="120" y="12" text-anchor="middle" font-size="8" fill="#4338ca">∠A=∠A\'=60°, ∠B=∠B\'=80°, k=3</text></svg>$\\angle A=\\angle A\'=60°$, $\\angle B=\\angle B\'=80°$. $AB=15$, $A\'B\'=5$. Найди $k$.',ans:3,hint:'k=AB/A\'B\'=15/5=3.'},
|
||
{q:'Два прямоугольных треугольника. Острый угол одного $42°$, другого $42°$. Подобны ли? Гипотенуза первого $13$, второго $6.5$. Найди $k$.',ans:2,hint:'Подобны по двум углам. k=13/6.5=2.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по двум углам. $k=4$. Периметр $\\triangle A\'B\'C\'=18$. Найди периметр $\\triangle ABC$.',ans:72,hint:'P=k·P\'=4·18=72.'},
|
||
{q:'В $\\triangle ABC$ и $\\triangle DEF$: $\\angle A=\\angle D=55°$, $\\angle B=\\angle E=75°$. $BC=20$, $EF=8$. Найди $k=BC/EF$.',ans:2.5,hint:'k=20/8=2.5.'},
|
||
];
|
||
const bossBox=document.getElementById('p5-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p5b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p5b-a${i}').value;
|
||
const fb=document.getElementById('p5b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.02){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p5BossSolved.has(${i})){ window.p5BossSolved.add(${i}); addXp(5,'p5-boss${i}'); bumpProgress('p5',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p5b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p5BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
function buildP6(){
|
||
const box=document.getElementById('p6-body');
|
||
let html='';
|
||
|
||
/* ---- Theory cards ---- */
|
||
html+=makeCard('theory','Второй признак подобия треугольников — по двум сторонам и углу (СУС — сторона-угол-сторона)','6.1',`
|
||
<p><b>Теорема (2-й признак подобия — по двум сторонам и углу, СУС).</b> Если две стороны одного треугольника пропорциональны двум сторонам другого треугольника, а углы между этими сторонами равны, то такие треугольники подобны.</p>
|
||
<p style="margin-top:8px">Если $\\dfrac{AB}{A'B'} = \\dfrac{AC}{A'C'} = k$ и $\\angle A = \\angle A'$, то $\\triangle ABC \\sim \\triangle A'B'C'$.</p>
|
||
<p style="margin-top:8px">Это означает: двух пропорциональных сторон и равного угла между ними <b>достаточно</b> для подобия — третью сторону и остальные углы можно не проверять.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 300 192" style="max-width:320px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- Triangle 1: A=(100,35), B=(30,155), C=(195,155) -->
|
||
<!-- AB≈138.9, AC≈153.1, ∠A≈68.6° -->
|
||
<polygon points="100,35 30,155 195,155" fill="rgba(124,58,237,.11)" stroke="#7c3aed" stroke-width="2"/>
|
||
<!-- Angle mark at A -->
|
||
<path d="M88,51 Q100,59 112,52" fill="none" stroke="#f59e0b" stroke-width="2"/>
|
||
<!-- Vertex labels outside polygon -->
|
||
<text x="100" y="27" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text>
|
||
<text x="18" y="165" font-size="11" font-weight="800" fill="#6d28d9">B</text>
|
||
<text x="198" y="165" font-size="11" font-weight="800" fill="#6d28d9">C</text>
|
||
<!-- Side labels -->
|
||
<text x="57" y="100" text-anchor="end" font-size="10" fill="#7c3aed" font-style="italic">AB</text>
|
||
<text x="155" y="98" font-size="10" fill="#7c3aed" font-style="italic">AC</text>
|
||
<!-- Triangle 2 (k=2): A'=(235,73), B'=(200,133), C'=(283,133) -->
|
||
<polygon points="235,73 200,133 283,133" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/>
|
||
<!-- Angle mark at A' -->
|
||
<path d="M226,87 Q235,93 244,88" fill="none" stroke="#f59e0b" stroke-width="1.8"/>
|
||
<text x="235" y="65" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text>
|
||
<text x="188" y="143" font-size="10" font-weight="800" fill="#4f46e5">B'</text>
|
||
<text x="285" y="143" font-size="10" font-weight="800" fill="#4f46e5">C'</text>
|
||
<text x="212" y="107" text-anchor="middle" font-size="9" fill="#6366f1" font-style="italic">A'B'</text>
|
||
<text x="263" y="102" font-size="9" fill="#6366f1" font-style="italic">A'C'</text>
|
||
<!-- Equal angle and ratio labels moved to bottom -->
|
||
<text x="150" y="170" text-anchor="middle" font-size="9" fill="#f59e0b" font-weight="800">∠A = ∠A' (равны)</text>
|
||
<text x="150" y="181" text-anchor="middle" font-size="8" fill="#7c3aed">AB/A'B' = AC/A'C' = k=2 → подобны</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Доказательство 2-го признака — схема','6.2',`
|
||
<p>На луче $A'B'$ откладываем $A'M = AB$. Через $M$ проводим прямую $MN \\parallel B'C'$, встречающую $A'C'$ в точке $N$.</p>
|
||
<p style="margin-top:6px">По теореме о прямой, параллельной стороне (§4): $\\dfrac{A'M}{A'B'} = \\dfrac{A'N}{A'C'}$, то есть $A'N = A'C' \\cdot \\dfrac{A'M}{A'B'} = A'C' \\cdot \\dfrac{AB}{A'B'} = AC$.</p>
|
||
<p style="margin-top:6px">Итак $A'M=AB$, $A'N=AC$, $\\angle A' = \\angle A$ → по признаку SAS: $\\triangle A'MN \\cong \\triangle ABC$.</p>
|
||
<p style="margin-top:6px">Также $\\triangle A'MN \\sim \\triangle A'B'C'$ (§4). Значит $\\triangle ABC \\sim \\triangle A'B'C'$. <b>QED.</b></p>
|
||
<div style="display:flex;justify-content:center;margin-top:12px">
|
||
<svg viewBox="0 0 280 140" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- large triangle A'B'C': A'=(140,15) B'=(30,130) C'=(250,130) -->
|
||
<polygon points="140,15 30,130 250,130" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="1.5"/>
|
||
<!-- inner triangle A'MN: M on A'B', N on A'C' -->
|
||
<!-- M on A'B' at ratio 0.55: M=(140+(30-140)*0.55, 15+(130-15)*0.55)=(79.5, 78.25) -->
|
||
<!-- N on A'C' at ratio 0.55: N=(140+(250-140)*0.55, 15+(130-15)*0.55)=(200.5, 78.25) -->
|
||
<polygon points="140,15 80,78 200,78" fill="rgba(124,58,237,.22)" stroke="#7c3aed" stroke-width="2"/>
|
||
<line x1="80" y1="78" x2="200" y2="78" stroke="#7c3aed" stroke-width="2" stroke-dasharray="5,3"/>
|
||
<text x="140" y="10" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text>
|
||
<text x="20" y="138" font-size="10" font-weight="800" fill="#4f46e5">B'</text>
|
||
<text x="252" y="138" font-size="10" font-weight="800" fill="#4f46e5">C'</text>
|
||
<text x="74" y="88" font-size="10" font-weight="800" fill="#7c3aed">M</text>
|
||
<text x="202" y="88" font-size="10" font-weight="800" fill="#7c3aed">N</text>
|
||
<text x="140" y="125" text-anchor="middle" font-size="8" fill="#6366f1">MN ∥ B'C'</text>
|
||
<text x="30" y="14" font-size="8" fill="#7c3aed">△A'MN≅△ABC и △A'MN∼△A'B'C'</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('example','Примеры применения признака по двум сторонам и углу (СУС)','6.3',`
|
||
<p><b>Пример 1.</b> $AB=6$, $AC=9$, $A'B'=4$, $A'C'=6$, $\\angle A=\\angle A'=50°$. Подобны ли треугольники?</p>
|
||
<p style="margin-top:4px">$\\dfrac{AB}{A'B'}=\\dfrac{6}{4}=1{,}5$; $\\dfrac{AC}{A'C'}=\\dfrac{9}{6}=1{,}5$. Отношения равны, углы между ними равны → по двум сторонам и углу (СУС): $\\triangle ABC \\sim \\triangle A'B'C'$, $k=1{,}5$.</p>
|
||
<p style="margin-top:8px"><b>Пример 2.</b> $PQ=10$, $PR=15$, $P'Q'=6$, $P'R'=9$, $\\angle P=\\angle P'$. $PQ/P'Q'=10/6=5/3$, $PR/P'R'=15/9=5/3$. Подобны ($k=5/3$).</p>
|
||
<p style="margin-top:8px"><b>Пример 3 (не подобны).</b> $AB=8$, $AC=6$, $A'B'=4$, $A'C'=5$, $\\angle A=\\angle A'$. $AB/A'B'=2$, $AC/A'C'=1{,}2$ — отношения неравны → <b>не подобны</b>.</p>`);
|
||
|
||
/* ---- ИНТЕРАКТИВ 1: SVG два треугольника, слайдер k ---- */
|
||
html+=`<div class="wg" id="p6-svg-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Два треугольника — признак СУС</div></div>
|
||
<div class="wg-help">Задай стороны $AB$, $AC$ и угол $\\angle A$ первого треугольника. Второй строится автоматически с тем же углом и пропорциональными сторонами. Меняй коэффициент $k$.</div>
|
||
<div class="sliders">
|
||
<label>Сторона $AB$: <b id="p6-ab-val">8</b>
|
||
<input type="range" min="4" max="14" value="8" id="p6-ab-sl" step="1">
|
||
</label>
|
||
<label>Сторона $AC$: <b id="p6-ac-val">10</b>
|
||
<input type="range" min="4" max="14" value="10" id="p6-ac-sl" step="1">
|
||
</label>
|
||
<label>Угол $\\angle A$ (°): <b id="p6-ang-val">55</b>°
|
||
<input type="range" min="20" max="140" value="55" id="p6-ang-sl" step="1">
|
||
</label>
|
||
<label>Коэффициент $k$: <b id="p6-k-val">2.0</b>
|
||
<input type="range" min="12" max="35" value="20" id="p6-k-sl" step="1">
|
||
</label>
|
||
</div>
|
||
<div id="p6-svg-out" style="display:flex;justify-content:center"></div>
|
||
<div id="p6-svg-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
|
||
html+=`<div class="wg" id="p6-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство 2-го признака — по шагам</div></div>
|
||
<div class="wg-help">Нажимай «Далее» для каждого шага доказательства.</div>
|
||
<div id="p6-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p6-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p6-proof-next">Далее</button>
|
||
<button class="btn" id="p6-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 3: Калькулятор СУС ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор признака СУС</div></div>
|
||
<div class="wg-help">Введи $AB, AC, \\angle A$ первого треугольника и коэффициент $k$ — получи стороны и угол второго. Или введи стороны двух треугольников и угол — система проверит подобие.</div>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">AB</span><input type="number" id="p6-cAB" class="tinp" placeholder="напр. 6" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">AC</span><input type="number" id="p6-cAC" class="tinp" placeholder="напр. 9" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠A (°)</span><input type="number" id="p6-cAng" class="tinp" placeholder="напр. 55" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">k</span><input type="number" id="p6-ck" class="tinp" placeholder="напр. 1.5" style="width:100%"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p6-ccalc" style="width:100%">Найти</button></div>
|
||
</div>
|
||
<div id="p6-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.7"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 4: Тренажёр ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §6 — Признак по двум сторонам и углу (СУС)</div></div>
|
||
<div class="wg-help">5 задач на подобие по признаку по двум сторонам и углу.</div>
|
||
<div class="score-display"><span>Задача <b id="p6-tr-i">1</b> / 5</span><span>Очки: <b id="p6-tr-score">0</b></span></div>
|
||
<div id="p6-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p6-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
|
||
<button class="btn primary" id="p6-tr-go">Проверить</button>
|
||
<button class="btn" id="p6-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p6-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 5: DnD-сортер ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Подобны по двум сторонам и углу (СУС) или нет? — Сортировка</div></div>
|
||
<div class="wg-help">Перетащи каждую пару в нужную колонку.</div>
|
||
<div id="p6-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p6-drop-yes"><h5>Подобны (по двум сторонам и углу)</h5><div class="drop-items" id="p6-drop-yes-items"></div></div>
|
||
<div class="drop-box" id="p6-drop-no"><h5>Не подобны</h5><div class="drop-items" id="p6-drop-no-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p6-dnd-check">Проверить</button><button class="btn" id="p6-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p6-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 6: Босс §6 ---- */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §6</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p6-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p6-read-btn" onclick="addXp(10,'p6-read');bumpProgress('p6',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §6 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p5','p7');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: SVG слайдеры СУС == */
|
||
(function(){
|
||
const abSl=document.getElementById('p6-ab-sl');
|
||
const acSl=document.getElementById('p6-ac-sl');
|
||
const angSl=document.getElementById('p6-ang-sl');
|
||
const kSl=document.getElementById('p6-k-sl');
|
||
const abVal=document.getElementById('p6-ab-val');
|
||
const acVal=document.getElementById('p6-ac-val');
|
||
const angVal=document.getElementById('p6-ang-val');
|
||
const kVal=document.getElementById('p6-k-val');
|
||
const svgOut=document.getElementById('p6-svg-out');
|
||
const infoEl=document.getElementById('p6-svg-info');
|
||
|
||
function triFromSAS(ab,ac,angRad,ox,oy){
|
||
const Ax=ox, Ay=oy;
|
||
const Bx=ox+ab, By=oy;
|
||
const Cx=ox+ac*Math.cos(angRad);
|
||
const Cy=oy-ac*Math.sin(angRad);
|
||
return {Ax,Ay,Bx,By,Cx,Cy};
|
||
}
|
||
|
||
function draw(){
|
||
const ab=+abSl.value;
|
||
const ac=+acSl.value;
|
||
const angDeg=+angSl.value;
|
||
const k=+kSl.value/10;
|
||
abVal.textContent=ab;
|
||
acVal.textContent=ac;
|
||
angVal.textContent=angDeg;
|
||
kVal.textContent=k.toFixed(1);
|
||
|
||
const scale=14;
|
||
const angRad=angDeg*Math.PI/180;
|
||
const W=380, H=180;
|
||
|
||
const t1=triFromSAS(ab*scale,ac*scale,angRad,24,155);
|
||
const ab2=ab/k, ac2=ac/k;
|
||
const t2=triFromSAS(ab2*scale,ac2*scale,angRad,220,155);
|
||
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
s+=`<polygon points="${t1.Ax},${t1.Ay} ${t1.Bx},${t1.By} ${t1.Cx},${t1.Cy}" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<text x="${t1.Ax-3}" y="${t1.Ay+4}" text-anchor="end" font-size="11" font-weight="800" fill="#6d28d9">A</text>`;
|
||
s+=`<text x="${t1.Bx+4}" y="${t1.By+4}" font-size="11" font-weight="800" fill="#6d28d9">B</text>`;
|
||
s+=`<text x="${t1.Cx}" y="${t1.Cy-5}" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">C</text>`;
|
||
const mABx1=(t1.Ax+t1.Bx)/2, mABx1y=(t1.Ay+t1.By)/2;
|
||
const mACx1=(t1.Ax+t1.Cx)/2, mACy1=(t1.Ay+t1.Cy)/2;
|
||
s+=`<text x="${mABx1}" y="${mABx1y+12}" text-anchor="middle" font-size="9" fill="#7c3aed">${ab}</text>`;
|
||
s+=`<text x="${mACx1-8}" y="${mACy1}" text-anchor="end" font-size="9" fill="#7c3aed">${ac}</text>`;
|
||
s+=`<path d="M${t1.Ax+14},${t1.Ay} Q${t1.Ax+10+8*Math.cos(angRad/2)},${t1.Ay-8*Math.sin(angRad/2)} ${t1.Ax+8*Math.cos(angRad)},${t1.Ay-8*Math.sin(angRad)}" fill="none" stroke="#f59e0b" stroke-width="1.8"/>`;
|
||
|
||
s+=`<polygon points="${t2.Ax},${t2.Ay} ${t2.Bx},${t2.By} ${t2.Cx},${t2.Cy}" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/>`;
|
||
s+=`<text x="${t2.Ax-3}" y="${t2.Ay+4}" text-anchor="end" font-size="10" font-weight="800" fill="#4f46e5">A'</text>`;
|
||
s+=`<text x="${t2.Bx+4}" y="${t2.By+4}" font-size="10" font-weight="800" fill="#4f46e5">B'</text>`;
|
||
s+=`<text x="${t2.Cx}" y="${t2.Cy-5}" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">C'</text>`;
|
||
const mABx2=(t2.Ax+t2.Bx)/2, mABy2=(t2.Ay+t2.By)/2;
|
||
const mACx2=(t2.Ax+t2.Cx)/2, mACy2=(t2.Ay+t2.Cy)/2;
|
||
s+=`<text x="${mABx2}" y="${mABy2+12}" text-anchor="middle" font-size="9" fill="#6366f1">${fmt(ab2)}</text>`;
|
||
s+=`<text x="${mACx2-6}" y="${mACy2}" text-anchor="end" font-size="9" fill="#6366f1">${fmt(ac2)}</text>`;
|
||
s+=`<path d="M${t2.Ax+10},${t2.Ay} Q${t2.Ax+8+6*Math.cos(angRad/2)},${t2.Ay-6*Math.sin(angRad/2)} ${t2.Ax+6*Math.cos(angRad)},${t2.Ay-6*Math.sin(angRad)}" fill="none" stroke="#f59e0b" stroke-width="1.5"/>`;
|
||
|
||
s+=`<text x="${W/2}" y="12" text-anchor="middle" font-size="10" font-weight="800" fill="#7c3aed">k = ${k.toFixed(1)}</text>`;
|
||
s+='</svg>';
|
||
svgOut.innerHTML=s;
|
||
infoEl.innerHTML=`$AB=${ab}$, $AC=${ac}$, $\\angle A=${angDeg}°$. Второй треугольник: $A'B'=${fmt(ab2)}$, $A'C'=${fmt(ac2)}$, $\\angle A'=${angDeg}°$. Отношение сторон $k=${k.toFixed(1)}$ — треугольники подобны по признаку по двум сторонам и углу (СУС).`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p6-svg');
|
||
}
|
||
abSl.addEventListener('input',draw);
|
||
acSl.addEventListener('input',draw);
|
||
angSl.addEventListener('input',draw);
|
||
kSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Дано: $\\dfrac{AB}{A\'B\'} = \\dfrac{AC}{A\'C\'} = k$ и $\\angle A = \\angle A\'$. Нужно доказать: $\\triangle ABC \\sim \\triangle A\'B\'C\'$.',
|
||
svg:`<svg viewBox="0 0 330 165" style="max-width:330px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="165" y="13" text-anchor="middle" font-size="9" fill="#f59e0b" font-weight="800">AB/A\'B\'=AC/A\'C\'=k=2, ∠A=∠A\'</text><polygon points="88,24 22,142 198,142" fill="rgba(124,58,237,.10)" stroke="#7c3aed" stroke-width="2"/><polygon points="265,68 237,130 312,130" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/><text x="88" y="17" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text><text x="10" y="153" font-size="11" font-weight="800" fill="#6d28d9">B</text><text x="200" y="153" font-size="11" font-weight="800" fill="#6d28d9">C</text><text x="265" y="61" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A\'</text><text x="225" y="142" font-size="10" font-weight="800" fill="#4f46e5">B\'</text><text x="314" y="142" font-size="10" font-weight="800" fill="#4f46e5">C\'</text></svg>`},
|
||
{desc:'<b>Шаг 2.</b> На луче $A\'B\'$ откладываем точку $M$ так, что $A\'M = AB$. Через $M$ проводим прямую $MN \\parallel B\'C\'$, где $N$ на луче $A\'C\'$.',
|
||
svg:`<svg viewBox="0 0 280 140" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="140,15 30,130 250,130" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="1.5"/><polygon points="140,15 80,78 200,78" fill="rgba(124,58,237,.22)" stroke="#7c3aed" stroke-width="2"/><line x1="80" y1="78" x2="200" y2="78" stroke="#7c3aed" stroke-width="2" stroke-dasharray="5,3"/><text x="140" y="10" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text><text x="20" y="138" font-size="10" font-weight="800" fill="#4f46e5">B'</text><text x="252" y="138" font-size="10" font-weight="800" fill="#4f46e5">C'</text><text x="74" y="88" font-size="10" font-weight="800" fill="#7c3aed">M</text><text x="202" y="88" font-size="10" font-weight="800" fill="#7c3aed">N</text><text x="140" y="110" text-anchor="middle" font-size="9" fill="#7c3aed">A'M=AB, MN∥B'C'</text></svg>`},
|
||
{desc:'<b>Шаг 3.</b> По теореме о прямой, параллельной стороне (§4): $\\dfrac{A\'M}{A\'B\'} = \\dfrac{A\'N}{A\'C\'}$. Так как $A\'M = AB$ и $\\dfrac{AB}{A\'B\'} = k$, получаем $A\'N = A\'C\' \\cdot \\dfrac{AB}{A\'B\'}= AC$.',
|
||
svg:`<svg viewBox="0 0 280 90" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="22" text-anchor="middle" font-size="11" fill="#4f46e5" font-weight="700">A'M/A'B' = A'N/A'C' (§4, пропорция)</text><text x="140" y="44" text-anchor="middle" font-size="11" fill="#7c3aed" font-weight="700">A'M=AB → A'N=AC</text><text x="140" y="70" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">Итак: A'M=AB, A'N=AC, ∠A'=∠A</text></svg>`},
|
||
{desc:'<b>Шаг 4.</b> Теперь: $A\'M = AB$, $A\'N = AC$, $\\angle A\' = \\angle A$. По признаку равенства треугольников (SAS): $\\triangle A\'MN \\cong \\triangle ABC$. Кроме того, $\\triangle A\'MN \\sim \\triangle A\'B\'C\'$ (§4).',
|
||
svg:`<svg viewBox="0 0 280 80" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="22" text-anchor="middle" font-size="11" fill="#4338ca" font-weight="700">△A'MN ≅ △ABC (SAS)</text><text x="140" y="44" text-anchor="middle" font-size="11" fill="#7c3aed" font-weight="700">△A'MN ∼ △A'B'C' (§4)</text><text x="140" y="66" text-anchor="middle" font-size="10" fill="#6366f1">По транзитивности подобия:</text></svg>`},
|
||
{desc:'<b>Шаг 5.</b> По транзитивности: $\\triangle ABC \\cong \\triangle A\'MN \\sim \\triangle A\'B\'C\'$ → $\\triangle ABC \\sim \\triangle A\'B\'C\'$. <b>Второй признак подобия (по двум сторонам и углу, СУС) доказан.</b>',
|
||
svg:`<svg viewBox="0 0 280 80" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="12" fill="#7c3aed" font-weight="800">AB/A'B'=AC/A'C'=k, ∠A=∠A' → △ABC∼△A'B'C'</text><text x="140" y="50" text-anchor="middle" font-size="10" fill="#6366f1">Признак по двум сторонам и углу (СУС) — второй признак подобия</text><text x="140" y="70" text-anchor="middle" font-size="12" fill="#10b981" font-weight="900">QED ∎</text></svg>`},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p6-proof-svg');
|
||
const descEl=document.getElementById('p6-proof-desc');
|
||
function show(){svgEl.innerHTML=steps[step].svg;descEl.innerHTML=steps[step].desc;renderMath(descEl);}
|
||
document.getElementById('p6-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p6-proof-step');}
|
||
else{addXp(5,'p6-proof-done');bumpProgress('p6',10);}
|
||
});
|
||
document.getElementById('p6-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: калькулятор == */
|
||
(function(){
|
||
document.getElementById('p6-ccalc').addEventListener('click',()=>{
|
||
const AB=parseFloat(document.getElementById('p6-cAB').value);
|
||
const AC=parseFloat(document.getElementById('p6-cAC').value);
|
||
const ang=parseFloat(document.getElementById('p6-cAng').value);
|
||
const k=parseFloat(document.getElementById('p6-ck').value);
|
||
const out=document.getElementById('p6-ccalc-out');
|
||
if([AB,AC,ang,k].some(v=>!isFinite(v)||v<=0)){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи все поля (положительные числа).</span>';return;
|
||
}
|
||
if(ang>=180){out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Угол должен быть меньше 180°.</span>';return;}
|
||
const AB2=AB/k, AC2=AC/k;
|
||
const angRad=ang*Math.PI/180;
|
||
const BC=Math.sqrt(AB*AB+AC*AC-2*AB*AC*Math.cos(angRad));
|
||
const BC2=BC/k;
|
||
out.style.display='block';
|
||
out.innerHTML=`Второй треугольник: $A'B'=\\dfrac{AB}{k}=\\dfrac{${fmt(AB)}}{${fmt(k)}}=${fmt(AB2)}$, $A'C'=\\dfrac{AC}{k}=\\dfrac{${fmt(AC)}}{${fmt(k)}}=${fmt(AC2)}$, $\\angle A'=${fmt(ang)}°$.<br>По теореме косинусов: $BC=${fmt(BC)}$, $B'C'=${fmt(BC2)}$.<br>Треугольники подобны по признаку по двум сторонам и углу (СУС) с $k=${fmt(k)}$.`;
|
||
renderMath(out);
|
||
addXp(3,'p6-calc');bumpProgress('p6',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'$AB=12$, $AC=8$, $A\'B\'=6$, $A\'C\'=4$, $\\angle A=\\angle A\'=40°$. Найди коэффициент подобия $k=AB/A\'B\'$.',ans:2,hint:'k=12/6=2. Проверь: AC/A\'C\'=8/4=2. ✓'},
|
||
{q:'$PQ=15$, $PR=9$, $P\'Q\'=5$, $P\'R\'=3$, $\\angle P=\\angle P\'$. Подобны ли треугольники? Введи $k$ (или 0 если не подобны).',ans:3,hint:'PQ/P\'Q\'=15/5=3, PR/P\'R\'=9/3=3. Подобны, k=3.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по двум сторонам и углу (СУС), $k=2.5$. $A\'B\'=6$. Найди $AB$.',ans:15,hint:'AB=k·A\'B\'=2.5·6=15.'},
|
||
{q:'$AB=10$, $AC=6$, $A\'B\'=4$, $A\'C\'=3$, $\\angle A=\\angle A\'$. Проверь подобие: $AB/A\'B\'=?$ (введи значение)',ans:2.5,hint:'AB/A\'B\'=10/4=2.5, AC/A\'C\'=6/3=2. Отношения разные → не подобны по двум сторонам и углу (СУС).'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по двум сторонам и углу (СУС), $k=3$. Стороны второго: $A\'B\'=4$, $A\'C\'=5$. Найди $AB+AC$.',ans:27,hint:'AB=3·4=12, AC=3·5=15. AB+AC=27.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p6-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p6-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p6-tr-ans').value='';
|
||
document.getElementById('p6-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p6-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p6-tr-score').textContent=0;show();});
|
||
document.getElementById('p6-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p6-tr-ans').value;
|
||
const fb=document.getElementById('p6-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.05){
|
||
score++;document.getElementById('p6-tr-score').textContent=score;
|
||
addXp(3,'p6-tr-'+idx);bumpProgress('p6',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p6-tr-all');bumpProgress('p6',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p6-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p6-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: DnD-сортер == */
|
||
(function(){
|
||
const items=[
|
||
{text:'AB=6,AC=9,A\'B\'=4,A\'C\'=6, ∠A=∠A\'',yes:true},
|
||
{text:'AB=8,AC=6,A\'B\'=4,A\'C\'=4, ∠A=∠A\'',yes:false},
|
||
{text:'PQ=15,PR=10,P\'Q\'=6,P\'R\'=4, ∠P=∠P\'',yes:true},
|
||
{text:'AB=10,AC=6,A\'B\'=5,A\'C\'=4, ∠A=∠A\'',yes:false},
|
||
{text:'MK=12,ML=8,M\'K\'=9,M\'L\'=6, ∠M=∠M\'',yes:true},
|
||
];
|
||
const pool=document.getElementById('p6-dnd-pool');
|
||
const yesBox=document.getElementById('p6-drop-yes-items');
|
||
const noBox=document.getElementById('p6-drop-no-items');
|
||
let dragging=null;
|
||
function makeChip(it,idx){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';
|
||
chip.dataset.idx=idx;
|
||
chip.textContent=it.text;
|
||
chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p6-drop-yes'),document.getElementById('p6-drop-no'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p6-drop-yes')?yesBox:box===document.getElementById('p6-drop-no')?noBox:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p6-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p6-dnd-fb');
|
||
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
|
||
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
|
||
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
|
||
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p6-dnd');bumpProgress('p6',8);}
|
||
else{feedback(fb,false,'Есть ошибки. Проверь равенство отношений двух пар сторон и равенство углов между ними.');}
|
||
});
|
||
document.getElementById('p6-dnd-reset').addEventListener('click',()=>{
|
||
[...yesBox.children].forEach(c=>pool.appendChild(c));
|
||
[...noBox.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p6-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §6 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'<svg viewBox="0 0 300 130" style="display:block;max-width:300px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="85,15 20,110 160,110" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="2"/><polygon points="228,47 185,110 278,110" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/><path d="M73,30 Q85,38 97,32" fill="none" stroke="#f59e0b" stroke-width="1.8"/><path d="M219,60 Q228,67 237,61" fill="none" stroke="#f59e0b" stroke-width="1.5"/><text x="85" y="10" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="800">A</text><text x="12" y="119" font-size="10" fill="#6d28d9" font-weight="800">B</text><text x="163" y="119" font-size="10" fill="#6d28d9" font-weight="800">C</text><text x="228" y="42" text-anchor="middle" font-size="9" fill="#4f46e5" font-weight="800">A\'</text><text x="177" y="119" font-size="9" fill="#4f46e5" font-weight="800">B\'</text><text x="280" y="119" font-size="9" fill="#4f46e5" font-weight="800">C\'</text><text x="150" y="10" text-anchor="middle" font-size="8" fill="#7c3aed">AB=9,AC=12,A\'B\'=6,A\'C\'=8,∠A=∠A\',k=1.5</text></svg>$AB=9$, $AC=12$, $A\'B\'=6$, $A\'C\'=8$, $\\angle A=\\angle A\'$. Найди $k=AB/A\'B\'$.',ans:1.5,hint:'k=9/6=1.5. Проверь: 12/8=1.5. ✓ Признак по двум сторонам и углу (СУС) выполнен.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по СУС, $k=4$. Стороны второго: $A\'B\'=3$, $A\'C\'=5$. Чему равно $AB+AC$?',ans:32,hint:'AB=4·3=12, AC=4·5=20. Сумма 32.'},
|
||
{q:'$AB=10$, $AC=15$, $\\angle A=60°$. По признаку СУС треугольник подобен другому с $k=2.5$. Найди $A\'B\'$.',ans:4,hint:'A\'B\'=AB/k=10/2.5=4.'},
|
||
{q:'Даны два треугольника: $AB=18$, $AC=12$, $A\'B\'=6$, $A\'C\'=4$, $\\angle A=\\angle A\'=75°$. Найди $BC$, если $B\'C\'=5$.',ans:15,hint:'k=18/6=3. BC=k·B\'C\'=3·5=15.'},
|
||
];
|
||
const bossBox=document.getElementById('p6-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p6b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p6b-a${i}').value;
|
||
const fb=document.getElementById('p6b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.05){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p6BossSolved.has(${i})){ window.p6BossSolved.add(${i}); addXp(5,'p6-boss${i}'); bumpProgress('p6',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p6b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p6BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
|
||
function buildP7(){
|
||
const box=document.getElementById('p7-body');
|
||
let html='';
|
||
|
||
/* ---- Theory cards ---- */
|
||
html+=makeCard('theory','Третий признак подобия треугольников — по трём сторонам (ССС)','7.1',`
|
||
<p><b>Теорема (3-й признак подобия — по трём сторонам, ССС).</b> Если три стороны одного треугольника пропорциональны трём сторонам другого треугольника, то такие треугольники подобны.</p>
|
||
<p style="margin-top:8px">Если $\\dfrac{a}{a'} = \\dfrac{b}{b'} = \\dfrac{c}{c'} = k$, то $\\triangle ABC \\sim \\triangle A'B'C'$.</p>
|
||
<p style="margin-top:8px">Здесь $a=BC$, $b=AC$, $c=AB$ и аналогично для второго треугольника. Это самый сильный признак — он <b>не требует</b> проверки углов.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 310 185" style="max-width:330px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- Triangle 1 (large): A=(86,28), B=(14,155), C=(192,155) -->
|
||
<!-- BC=178, AB≈141.6, AC≈160.8 — similar proportions -->
|
||
<polygon points="86,28 14,155 192,155" fill="rgba(124,58,237,.11)" stroke="#7c3aed" stroke-width="2"/>
|
||
<text x="86" y="20" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text>
|
||
<text x="2" y="166" font-size="11" font-weight="800" fill="#6d28d9">B</text>
|
||
<text x="194" y="166" font-size="11" font-weight="800" fill="#6d28d9">C</text>
|
||
<!-- Side labels t1 — OUTSIDE polygon -->
|
||
<text x="40" y="100" text-anchor="end" font-size="10" fill="#7c3aed" font-style="italic">c=AB</text>
|
||
<text x="103" y="170" text-anchor="middle" font-size="10" fill="#7c3aed" font-style="italic">a=BC</text>
|
||
<text x="148" y="97" font-size="10" fill="#7c3aed" font-style="italic">b=AC</text>
|
||
<!-- Triangle 2 (small, k=2.5): B'=(232,120), C'=(303,120), A'=(260,77) -->
|
||
<!-- B'C'=71≈178/2.5✓ -->
|
||
<polygon points="260,77 232,120 303,120" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/>
|
||
<text x="260" y="70" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text>
|
||
<text x="220" y="131" font-size="10" font-weight="800" fill="#4f46e5">B'</text>
|
||
<text x="305" y="131" font-size="10" font-weight="800" fill="#4f46e5">C'</text>
|
||
<!-- Side labels t2 — OUTSIDE polygon -->
|
||
<text x="242" y="102" text-anchor="end" font-size="9" fill="#6366f1" font-style="italic">c'</text>
|
||
<text x="268" y="130" text-anchor="middle" font-size="9" fill="#6366f1" font-style="italic">a'</text>
|
||
<text x="288" y="101" font-size="9" fill="#6366f1" font-style="italic">b'</text>
|
||
<!-- Ratio text — at BOTTOM, well below figures -->
|
||
<text x="155" y="178" text-anchor="middle" font-size="9" fill="#f59e0b" font-weight="800">a/a'=b/b'=c/c'=k≈2.5 → △ABC∼△A'B'C'</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Доказательство 3-го признака — схема','7.2',`
|
||
<p>Доказательство сводится к 2-му признаку (по двум сторонам и углу, СУС).</p>
|
||
<p style="margin-top:6px">Пусть $\\dfrac{a}{a'}=\\dfrac{b}{b'}=\\dfrac{c}{c'}=k$. На стороне $A'B'$ откладываем $A'M=AB=kA'B'$. Через $M \\parallel B'C'$ строим точку $N$ на $A'C'$, тогда $\\triangle A'MN \\sim \\triangle A'B'C'$ и все стороны $\\triangle A'MN$ равны сторонам $\\triangle ABC$.</p>
|
||
<p style="margin-top:6px">По признаку равенства SSS: $\\triangle A'MN \\cong \\triangle ABC$. Значит $\\triangle ABC \\sim \\triangle A'B'C'$ (транзитивность). <b>QED.</b></p>
|
||
<div style="display:flex;justify-content:center;margin-top:10px">
|
||
<svg viewBox="0 0 280 130" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<polygon points="140,14 30,122 250,122" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="1.5"/>
|
||
<polygon points="140,14 82,72 198,72" fill="rgba(124,58,237,.22)" stroke="#7c3aed" stroke-width="2"/>
|
||
<line x1="82" y1="72" x2="198" y2="72" stroke="#7c3aed" stroke-width="2" stroke-dasharray="5,3"/>
|
||
<text x="140" y="9" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text>
|
||
<text x="20" y="130" font-size="10" font-weight="800" fill="#4f46e5">B'</text>
|
||
<text x="252" y="130" font-size="10" font-weight="800" fill="#4f46e5">C'</text>
|
||
<text x="76" y="82" font-size="10" font-weight="800" fill="#7c3aed">M</text>
|
||
<text x="200" y="82" font-size="10" font-weight="800" fill="#7c3aed">N</text>
|
||
<text x="140" y="105" text-anchor="middle" font-size="8" fill="#6366f1">△A'MN∼△A'B'C', △A'MN≅△ABC → △ABC∼△A'B'C'</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('example','Примеры применения признака по трём сторонам (ССС)','7.3',`
|
||
<p><b>Пример 1.</b> $a=6$, $b=8$, $c=10$; $a'=3$, $b'=4$, $c'=5$. Подобны ли треугольники?</p>
|
||
<p style="margin-top:4px">$a/a'=6/3=2$, $b/b'=8/4=2$, $c/c'=10/5=2$. Все отношения равны $k=2$ → по трём сторонам (ССС): подобны.</p>
|
||
<p style="margin-top:8px"><b>Пример 2.</b> $a=9$, $b=12$, $c=6$; $a'=6$, $b'=8$, $c'=4$. $9/6=1{,}5$, $12/8=1{,}5$, $6/4=1{,}5$. $k=1{,}5$ — подобны.</p>
|
||
<p style="margin-top:8px"><b>Пример 3 (не подобны).</b> $a=5$, $b=7$, $c=9$; $a'=5$, $b'=7$, $c'=10$. $5/5=1$, $7/7=1$, $9/10=0{,}9$. Отношения различны → <b>не подобны</b>.</p>`);
|
||
|
||
/* ---- ИНТЕРАКТИВ 1: SVG три стороны + слайдер k ---- */
|
||
html+=`<div class="wg" id="p7-svg-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Два треугольника — признак по трём сторонам (ССС)</div></div>
|
||
<div class="wg-help">Задай три стороны первого треугольника и коэффициент $k$. Второй строится автоматически: все стороны уменьшены в $k$ раз. Треугольное неравенство проверяется автоматически.</div>
|
||
<div class="sliders">
|
||
<label>Сторона $a$: <b id="p7-a-val">6</b>
|
||
<input type="range" min="3" max="14" value="6" id="p7-a-sl" step="1">
|
||
</label>
|
||
<label>Сторона $b$: <b id="p7-b-val">8</b>
|
||
<input type="range" min="3" max="14" value="8" id="p7-b-sl" step="1">
|
||
</label>
|
||
<label>Сторона $c$: <b id="p7-c-val">9</b>
|
||
<input type="range" min="3" max="14" value="9" id="p7-c-sl" step="1">
|
||
</label>
|
||
<label>Коэффициент $k$: <b id="p7-k-val">2.0</b>
|
||
<input type="range" min="12" max="35" value="20" id="p7-k-sl" step="1">
|
||
</label>
|
||
</div>
|
||
<div id="p7-svg-out" style="display:flex;justify-content:center"></div>
|
||
<div id="p7-svg-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
|
||
html+=`<div class="wg" id="p7-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство 3-го признака — по шагам</div></div>
|
||
<div class="wg-help">Нажимай «Далее» для каждого шага доказательства признака по трём сторонам (ССС).</div>
|
||
<div id="p7-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p7-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p7-proof-next">Далее</button>
|
||
<button class="btn" id="p7-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 3: Калькулятор ССС ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: проверка подобия по трём сторонам</div></div>
|
||
<div class="wg-help">Введи стороны двух треугольников — система проверит пропорциональность и найдёт $k$.</div>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">a (BC)</span><input type="number" id="p7-ca" class="tinp" placeholder="напр. 6" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">b (AC)</span><input type="number" id="p7-cb" class="tinp" placeholder="напр. 8" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">c (AB)</span><input type="number" id="p7-cc" class="tinp" placeholder="напр. 10" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">a' (B'C')</span><input type="number" id="p7-ca2" class="tinp" placeholder="напр. 3" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">b' (A'C')</span><input type="number" id="p7-cb2" class="tinp" placeholder="напр. 4" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">c' (A'B')</span><input type="number" id="p7-cc2" class="tinp" placeholder="напр. 5" style="width:100%"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p7-ccalc" style="width:100%">Проверить</button></div>
|
||
</div>
|
||
<div id="p7-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.7"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 4: Тренажёр ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §7 — Признак по трём сторонам (ССС)</div></div>
|
||
<div class="wg-help">5 задач на проверку подобия по сторонам и нахождение коэффициента.</div>
|
||
<div class="score-display"><span>Задача <b id="p7-tr-i">1</b> / 5</span><span>Очки: <b id="p7-tr-score">0</b></span></div>
|
||
<div id="p7-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p7-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
|
||
<button class="btn primary" id="p7-tr-go">Проверить</button>
|
||
<button class="btn" id="p7-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p7-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 5: DnD-сортер ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Подобны по трём сторонам (ССС) или нет? — Сортировка</div></div>
|
||
<div class="wg-help">Перетащи каждую пару троек сторон в нужную колонку.</div>
|
||
<div id="p7-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p7-drop-yes"><h5>Подобны (по трём сторонам)</h5><div class="drop-items" id="p7-drop-yes-items"></div></div>
|
||
<div class="drop-box" id="p7-drop-no"><h5>Не подобны</h5><div class="drop-items" id="p7-drop-no-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p7-dnd-check">Проверить</button><button class="btn" id="p7-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p7-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 6: Мини-квиз (три признака) ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 6</span><div class="wg-title">Мини-квиз: все три признака подобия</div></div>
|
||
<div class="wg-help">5 вопросов о трёх признаках подобия. Выбери правильный ответ.</div>
|
||
<div id="p7-quiz-wrap"></div>
|
||
<div class="actions"><button class="btn primary" id="p7-quiz-check">Проверить</button></div>
|
||
<div class="feedback" id="p7-quiz-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 7: Босс §7 ---- */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §7</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p7-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p7-read-btn" onclick="addXp(10,'p7-read');bumpProgress('p7',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §7 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p6','p8');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: SVG по трём сторонам == */
|
||
(function(){
|
||
const aSl=document.getElementById('p7-a-sl');
|
||
const bSl=document.getElementById('p7-b-sl');
|
||
const cSl=document.getElementById('p7-c-sl');
|
||
const kSl=document.getElementById('p7-k-sl');
|
||
const aVal=document.getElementById('p7-a-val');
|
||
const bVal=document.getElementById('p7-b-val');
|
||
const cVal=document.getElementById('p7-c-val');
|
||
const kVal=document.getElementById('p7-k-val');
|
||
const svgOut=document.getElementById('p7-svg-out');
|
||
const infoEl=document.getElementById('p7-svg-info');
|
||
|
||
function triFromSSS(aa,bb,cc,ox,oy){
|
||
// a=BC, b=AC, c=AB. Place B=(ox,oy), C=(ox+a,oy)
|
||
// Find A using law of cosines: cosB=(c²+a²-b²)/(2ca)
|
||
const cosB=(cc*cc+aa*aa-bb*bb)/(2*cc*aa);
|
||
if(cosB<-1||cosB>1) return null;
|
||
const Bx=ox, By=oy;
|
||
const Cx=ox+aa, Cy=oy;
|
||
const Ax=ox+cc*cosB;
|
||
const Ay=oy-cc*Math.sqrt(1-cosB*cosB);
|
||
return {Ax,Ay,Bx,By,Cx,Cy};
|
||
}
|
||
|
||
function draw(){
|
||
const a=+aSl.value, b=+bSl.value, c=+cSl.value;
|
||
const k=+kSl.value/10;
|
||
aVal.textContent=a; bVal.textContent=b; cVal.textContent=c;
|
||
kVal.textContent=k.toFixed(1);
|
||
|
||
// Triangle inequality check
|
||
if(a+b<=c||a+c<=b||b+c<=a){
|
||
svgOut.innerHTML='<div style="color:var(--bad);padding:10px">Нарушено треугольное неравенство. Измени стороны.</div>';
|
||
infoEl.innerHTML='Треугольное неравенство нарушено.';
|
||
return;
|
||
}
|
||
|
||
const scale=13;
|
||
const a2=a/k, b2=b/k, c2=c/k;
|
||
const W=400, H=185;
|
||
|
||
const t1=triFromSSS(a*scale,b*scale,c*scale,18,165);
|
||
if(!t1){svgOut.innerHTML='';return;}
|
||
const t2=triFromSSS(a2*scale,b2*scale,c2*scale,230,165);
|
||
if(!t2){svgOut.innerHTML='';return;}
|
||
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
s+=`<polygon points="${t1.Ax},${t1.Ay} ${t1.Bx},${t1.By} ${t1.Cx},${t1.Cy}" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="2"/>`;
|
||
s+=`<text x="${t1.Ax}" y="${t1.Ay-5}" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text>`;
|
||
s+=`<text x="${t1.Bx-8}" y="${t1.By+4}" font-size="11" font-weight="800" fill="#6d28d9">B</text>`;
|
||
s+=`<text x="${t1.Cx+4}" y="${t1.Cy+4}" font-size="11" font-weight="800" fill="#6d28d9">C</text>`;
|
||
const mBCx=(t1.Bx+t1.Cx)/2, mBCy=(t1.By+t1.Cy)/2;
|
||
const mACx=(t1.Ax+t1.Cx)/2, mACy=(t1.Ay+t1.Cy)/2;
|
||
const mABx=(t1.Ax+t1.Bx)/2, mABy=(t1.Ay+t1.By)/2;
|
||
s+=`<text x="${mBCx}" y="${mBCy+11}" text-anchor="middle" font-size="9" fill="#7c3aed">a=${a}</text>`;
|
||
s+=`<text x="${mACx+8}" y="${mACy}" font-size="9" fill="#7c3aed">b=${b}</text>`;
|
||
s+=`<text x="${mABx-8}" y="${mABy}" text-anchor="end" font-size="9" fill="#7c3aed">c=${c}</text>`;
|
||
|
||
s+=`<polygon points="${t2.Ax},${t2.Ay} ${t2.Bx},${t2.By} ${t2.Cx},${t2.Cy}" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/>`;
|
||
s+=`<text x="${t2.Ax}" y="${t2.Ay-5}" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text>`;
|
||
s+=`<text x="${t2.Bx-10}" y="${t2.By+4}" font-size="10" font-weight="800" fill="#4f46e5">B'</text>`;
|
||
s+=`<text x="${t2.Cx+4}" y="${t2.Cy+4}" font-size="10" font-weight="800" fill="#4f46e5">C'</text>`;
|
||
const mBCx2=(t2.Bx+t2.Cx)/2, mBCy2=(t2.By+t2.Cy)/2;
|
||
const mACx2=(t2.Ax+t2.Cx)/2, mACy2=(t2.Ay+t2.Cy)/2;
|
||
const mABx2=(t2.Ax+t2.Bx)/2, mABy2=(t2.Ay+t2.By)/2;
|
||
s+=`<text x="${mBCx2}" y="${mBCy2+11}" text-anchor="middle" font-size="9" fill="#6366f1">a'=${fmt(a2)}</text>`;
|
||
s+=`<text x="${mACx2+6}" y="${mACy2}" font-size="9" fill="#6366f1">b'=${fmt(b2)}</text>`;
|
||
s+=`<text x="${mABx2-6}" y="${mABy2}" text-anchor="end" font-size="9" fill="#6366f1">c'=${fmt(c2)}</text>`;
|
||
|
||
s+=`<text x="${W/2}" y="12" text-anchor="middle" font-size="10" font-weight="800" fill="#7c3aed">k = ${k.toFixed(1)}</text>`;
|
||
s+='</svg>';
|
||
svgOut.innerHTML=s;
|
||
infoEl.innerHTML=`$a=${a}$, $b=${b}$, $c=${c}$. Второй: $a'=${fmt(a2)}$, $b'=${fmt(b2)}$, $c'=${fmt(c2)}$. $\\dfrac{a}{a'}=\\dfrac{b}{b'}=\\dfrac{c}{c'}=${k.toFixed(1)}$ → по признаку по трём сторонам (ССС) треугольники подобны.`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p7-svg');
|
||
}
|
||
aSl.addEventListener('input',draw);
|
||
bSl.addEventListener('input',draw);
|
||
cSl.addEventListener('input',draw);
|
||
kSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Дано: $\\dfrac{a}{a\'}=\\dfrac{b}{b\'}=\\dfrac{c}{c\'}=k$. Нужно доказать: $\\triangle ABC \\sim \\triangle A\'B\'C\'$.',
|
||
svg:`<svg viewBox="0 0 310 160" style="max-width:310px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="155" y="13" text-anchor="middle" font-size="9" fill="#f59e0b" font-weight="800">a/a\'=b/b\'=c/c\'=k (k≈2) — условие</text><polygon points="88,24 18,145 205,145" fill="rgba(124,58,237,.10)" stroke="#7c3aed" stroke-width="2"/><polygon points="260,72 238,132 302,132" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/><text x="88" y="17" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text><text x="6" y="156" font-size="11" font-weight="800" fill="#6d28d9">B</text><text x="207" y="156" font-size="11" font-weight="800" fill="#6d28d9">C</text><text x="260" y="65" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A\'</text><text x="226" y="143" font-size="10" font-weight="800" fill="#4f46e5">B\'</text><text x="304" y="143" font-size="10" font-weight="800" fill="#4f46e5">C\'</text></svg>`},
|
||
{desc:'<b>Шаг 2.</b> На луче $A\'B\'$ откладываем $A\'M = AB = k \\cdot A\'B\'$. Через $M$ проводим $MN \\parallel B\'C\'$, $N$ на $A\'C\'$. По теореме §4: $\\triangle A\'MN \\sim \\triangle A\'B\'C\'$.',
|
||
svg:`<svg viewBox="0 0 280 140" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="140,14 30,126 250,126" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="1.5"/><polygon points="140,14 82,70 198,70" fill="rgba(124,58,237,.22)" stroke="#7c3aed" stroke-width="2"/><line x1="82" y1="70" x2="198" y2="70" stroke="#7c3aed" stroke-width="2" stroke-dasharray="5,3"/><text x="140" y="9" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text><text x="20" y="134" font-size="10" font-weight="800" fill="#4f46e5">B'</text><text x="252" y="134" font-size="10" font-weight="800" fill="#4f46e5">C'</text><text x="76" y="80" font-size="10" font-weight="800" fill="#7c3aed">M</text><text x="200" y="80" font-size="10" font-weight="800" fill="#7c3aed">N</text><text x="140" y="110" text-anchor="middle" font-size="9" fill="#7c3aed">A'M=AB, MN∥B'C'</text></svg>`},
|
||
{desc:'<b>Шаг 3.</b> Поскольку $\\triangle A\'MN \\sim \\triangle A\'B\'C\'$ с коэффициентом $k$, все стороны $\\triangle A\'MN$ равны соответствующим сторонам $\\triangle ABC$: $A\'M=AB$, $MN=a$, $A\'N=b$.',
|
||
svg:`<svg viewBox="0 0 280 90" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="22" text-anchor="middle" font-size="11" fill="#4f46e5" font-weight="700">△A'MN∼△A'B'C' с коэфф. k</text><text x="140" y="44" text-anchor="middle" font-size="11" fill="#7c3aed" font-weight="700">A'M=AB=c, MN=BC=a, A'N=AC=b</text><text x="140" y="68" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">Все стороны △A'MN = сторонам △ABC</text></svg>`},
|
||
{desc:'<b>Шаг 4.</b> По признаку равенства треугольников (SSS): $\\triangle A\'MN \\cong \\triangle ABC$ (у них равны все три пары сторон).',
|
||
svg:`<svg viewBox="0 0 280 80" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="12" fill="#4338ca" font-weight="800">△A'MN ≅ △ABC (SSS)</text><text x="140" y="52" text-anchor="middle" font-size="10" fill="#6366f1">Три стороны равны попарно → конгруэнтны</text><text x="140" y="70" text-anchor="middle" font-size="9" fill="#7c3aed">△A'MN∼△A'B'C' также выполнено</text></svg>`},
|
||
{desc:'<b>Шаг 5.</b> По транзитивности: $\\triangle ABC \\cong \\triangle A\'MN \\sim \\triangle A\'B\'C\'$ → $\\triangle ABC \\sim \\triangle A\'B\'C\'$. <b>Третий признак подобия (по трём сторонам, ССС) доказан.</b>',
|
||
svg:`<svg viewBox="0 0 280 80" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="12" fill="#7c3aed" font-weight="800">a/a'=b/b'=c/c'=k → △ABC∼△A'B'C'</text><text x="140" y="50" text-anchor="middle" font-size="10" fill="#6366f1">Признак по трём сторонам (ССС) — третий признак подобия</text><text x="140" y="70" text-anchor="middle" font-size="12" fill="#10b981" font-weight="900">QED ∎</text></svg>`},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p7-proof-svg');
|
||
const descEl=document.getElementById('p7-proof-desc');
|
||
function show(){svgEl.innerHTML=steps[step].svg;descEl.innerHTML=steps[step].desc;renderMath(descEl);}
|
||
document.getElementById('p7-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p7-proof-step');}
|
||
else{addXp(5,'p7-proof-done');bumpProgress('p7',10);}
|
||
});
|
||
document.getElementById('p7-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: калькулятор ССС == */
|
||
(function(){
|
||
document.getElementById('p7-ccalc').addEventListener('click',()=>{
|
||
const a=parseFloat(document.getElementById('p7-ca').value);
|
||
const b=parseFloat(document.getElementById('p7-cb').value);
|
||
const c=parseFloat(document.getElementById('p7-cc').value);
|
||
const a2=parseFloat(document.getElementById('p7-ca2').value);
|
||
const b2=parseFloat(document.getElementById('p7-cb2').value);
|
||
const c2=parseFloat(document.getElementById('p7-cc2').value);
|
||
const out=document.getElementById('p7-ccalc-out');
|
||
if([a,b,c,a2,b2,c2].some(v=>!isFinite(v)||v<=0)){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи все шесть сторон.</span>';return;
|
||
}
|
||
const k1=a/a2, k2=b/b2, k3=c/c2;
|
||
const tol=0.001;
|
||
const ok=Math.abs(k1-k2)<tol&&Math.abs(k2-k3)<tol;
|
||
out.style.display='block';
|
||
if(ok){
|
||
out.innerHTML=`$\\dfrac{a}{a'}=\\dfrac{${fmt(a)}}{${fmt(a2)}}=${fmt(k1)}$, $\\dfrac{b}{b'}=\\dfrac{${fmt(b)}}{${fmt(b2)}}=${fmt(k2)}$, $\\dfrac{c}{c'}=\\dfrac{${fmt(c)}}{${fmt(c2)}}=${fmt(k3)}$.<br><b>Все отношения равны $k=${fmt(k1)}$</b> → треугольники <b>подобны по признаку по трём сторонам (ССС)</b>.`;
|
||
addXp(3,'p7-calc');bumpProgress('p7',5);
|
||
} else {
|
||
out.innerHTML=`$\\dfrac{a}{a'}=${fmt(k1)}$, $\\dfrac{b}{b'}=${fmt(k2)}$, $\\dfrac{c}{c'}=${fmt(k3)}$.<br>Отношения <b>не равны</b> → треугольники <b>не подобны</b> по признаку по трём сторонам (ССС).`;
|
||
}
|
||
renderMath(out);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'$a=9$, $b=12$, $c=6$; $a\'=3$, $b\'=4$, $c\'=2$. Найди коэффициент подобия $k=a/a\'$.',ans:3,hint:'9/3=12/4=6/2=3. k=3.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по трём сторонам (ССС), $k=2.5$. Стороны первого: $a=10$, $b=15$. Найди $a\'$.',ans:4,hint:'a\'=a/k=10/2.5=4.'},
|
||
{q:'Стороны: $(6,8,10)$ и $(3,4,5)$. Подобны ли? Введи $k$ (или 0 если нет).',ans:2,hint:'6/3=8/4=10/5=2. Подобны по трём сторонам (ССС), k=2.'},
|
||
{q:'$a=5$, $b=7$, $c=9$; $a\'=5$, $b\'=7$, $c\'=10$. Подобны ли? Введи $k$ (или 0 если нет).',ans:0,hint:'5/5=1, 7/7=1, но 9/10≠1. Не подобны. Ответ 0.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по трём сторонам (ССС), $k=4$. Периметр $\\triangle A\'B\'C\'=21$. Найди периметр $\\triangle ABC$.',ans:84,hint:'P=k·P\'=4·21=84.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p7-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p7-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p7-tr-ans').value='';
|
||
document.getElementById('p7-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p7-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p7-tr-score').textContent=0;show();});
|
||
document.getElementById('p7-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p7-tr-ans').value;
|
||
const fb=document.getElementById('p7-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.05){
|
||
score++;document.getElementById('p7-tr-score').textContent=score;
|
||
addXp(3,'p7-tr-'+idx);bumpProgress('p7',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p7-tr-all');bumpProgress('p7',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p7-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p7-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: DnD-сортер ССС == */
|
||
(function(){
|
||
const items=[
|
||
{text:'(6,8,10) и (3,4,5)',yes:true},
|
||
{text:'(5,7,9) и (5,7,10)',yes:false},
|
||
{text:'(9,12,6) и (6,8,4)',yes:true},
|
||
{text:'(4,6,8) и (3,5,8)',yes:false},
|
||
{text:'(15,10,5) и (6,4,2)',yes:true},
|
||
];
|
||
const pool=document.getElementById('p7-dnd-pool');
|
||
const yesBox=document.getElementById('p7-drop-yes-items');
|
||
const noBox=document.getElementById('p7-drop-no-items');
|
||
let dragging=null;
|
||
function makeChip(it,idx){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';
|
||
chip.dataset.idx=idx;
|
||
chip.textContent=it.text;
|
||
chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p7-drop-yes'),document.getElementById('p7-drop-no'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p7-drop-yes')?yesBox:box===document.getElementById('p7-drop-no')?noBox:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p7-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p7-dnd-fb');
|
||
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
|
||
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
|
||
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
|
||
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p7-dnd');bumpProgress('p7',8);}
|
||
else{feedback(fb,false,'Есть ошибки. Проверь: все три отношения a/a\', b/b\', c/c\' должны быть равны.');}
|
||
});
|
||
document.getElementById('p7-dnd-reset').addEventListener('click',()=>{
|
||
[...yesBox.children].forEach(c=>pool.appendChild(c));
|
||
[...noBox.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p7-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 6: мини-квиз == */
|
||
(function(){
|
||
const qs=[
|
||
{q:'По какому признаку два угла одного треугольника равны двум углам другого?',opts:['По двум углам (УУ)','По двум сторонам и углу (СУС)','По трём сторонам (ССС)','Нет такого признака'],ans:0},
|
||
{q:'Сколько признаков подобия треугольников есть в курсе 8 класса?',opts:['1','2','3','4'],ans:2},
|
||
{q:'Признак по двум сторонам и углу (СУС) требует равенства...',opts:['двух углов','двух сторон и угла между ними','трёх сторон','двух сторон и угла напротив'],ans:1},
|
||
{q:'Если $a/a\'=2$, $b/b\'=2$, $c/c\'=2$, то треугольники подобны по признаку...',opts:['По двум углам (УУ)','По двум сторонам и углу (СУС)','По трём сторонам (ССС)','Нельзя определить'],ans:2},
|
||
{q:'По признаку по трём сторонам (ССС) требуется проверить...',opts:['2 угла','2 стороны и угол','3 стороны','1 угол и 2 стороны'],ans:2},
|
||
];
|
||
const wrap=document.getElementById('p7-quiz-wrap');
|
||
wrap.innerHTML=qs.map((q,qi)=>`
|
||
<div style="margin-bottom:14px;padding:12px;background:var(--card);border:1px solid var(--border);border-radius:10px">
|
||
<div style="font-weight:700;margin-bottom:8px;font-size:.95rem">${qi+1}. ${q.q}</div>
|
||
<div style="display:flex;flex-direction:column;gap:6px">
|
||
${q.opts.map((o,oi)=>`<label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-size:.92rem"><input type="radio" name="p7q${qi}" value="${oi}" style="accent-color:var(--sec-acc,var(--pri))"> ${o}</label>`).join('')}
|
||
</div>
|
||
</div>`).join('');
|
||
document.getElementById('p7-quiz-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p7-quiz-fb');
|
||
let correct=0;
|
||
qs.forEach((q,qi)=>{
|
||
const sel=document.querySelector(`input[name="p7q${qi}"]:checked`);
|
||
if(sel&&+sel.value===q.ans)correct++;
|
||
});
|
||
if(correct===qs.length){
|
||
feedback(fb,true,`Все ${qs.length} ответов верны! +8 XP`);
|
||
addXp(8,'p7-quiz');bumpProgress('p7',12);confetti();
|
||
} else {
|
||
feedback(fb,false,`Верных ответов: ${correct} из ${qs.length}. Повтори параграфы с признаками.`);
|
||
}
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §7 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'<svg viewBox="0 0 240 128" style="display:block;max-width:240px;margin:0 auto 8px;background:#ddd6fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="100,14 24,118 210,118" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="2"/><polygon points="196,40 168,108 252,108" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/><text x="100" y="9" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="800">A</text><text x="14" y="126" font-size="10" fill="#6d28d9" font-weight="800">B</text><text x="213" y="126" font-size="10" fill="#6d28d9" font-weight="800">C</text><text x="196" y="35" text-anchor="middle" font-size="9" fill="#4f46e5" font-weight="800">A\'</text><text x="160" y="116" font-size="9" fill="#4f46e5" font-weight="800">B\'</text><text x="254" y="116" font-size="9" fill="#4f46e5" font-weight="800">C\'</text><text x="120" y="9" text-anchor="middle" font-size="8" fill="#7c3aed">a=12,b=9,c=15; a\'=8,b\'=6,c\'=10</text></svg>$a=12$, $b=9$, $c=15$; $a\'=8$, $b\'=6$, $c\'=10$. Найди $k=a/a\'$.',ans:1.5,hint:'12/8=9/6=15/10=1.5. k=1.5. Признак по трём сторонам (ССС) выполнен.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по трём сторонам (ССС), $k=3$. Периметр $\\triangle A\'B\'C\'=28$. Найди периметр $\\triangle ABC$.',ans:84,hint:'P=3·28=84.'},
|
||
{q:'Стороны первого: $4, 6, 8$. Стороны второго: $6, 9, 12$. По какому признаку они подобны? Введи $k$ (большего к меньшему).',ans:1.5,hint:'6/4=9/6=12/8=1.5. Признак по трём сторонам (ССС). k=1.5.'},
|
||
{q:'$\\triangle DEF$: $DE=10$, $EF=24$, $DF=26$ (прямоугольный). $\\triangle D\'E\'F\'$: $D\'E\'=5$, $E\'F\'=12$, $D\'F\'=13$. Найди $k$.',ans:2,hint:'10/5=24/12=26/13=2. k=2. Признак по трём сторонам (ССС).'},
|
||
];
|
||
const bossBox=document.getElementById('p7-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p7b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p7b-a${i}').value;
|
||
const fb=document.getElementById('p7b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.05){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p7BossSolved.has(${i})){ window.p7BossSolved.add(${i}); addXp(5,'p7-boss${i}'); bumpProgress('p7',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p7b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p7BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
function buildP8(){
|
||
const box=document.getElementById('p8-body');
|
||
let html='';
|
||
|
||
/* ---- Theory cards ---- */
|
||
html+=makeCard('theory','Свойство биссектрисы треугольника','8.1',`
|
||
<p><b>Теорема.</b> Биссектриса угла треугольника делит противоположную сторону на отрезки, пропорциональные двум другим сторонам.</p>
|
||
<p style="margin-top:8px">В $\\triangle ABC$, $AD$ — биссектриса $\\angle A$ ($D \\in BC$). Тогда:</p>
|
||
$$\\dfrac{BD}{DC} = \\dfrac{AB}{AC} = \\dfrac{c}{b}$$
|
||
<p style="margin-top:8px">Здесь $c = AB$, $b = AC$. Биссектриса делит отрезок $BC$ в отношении смежных (прилежащих к нему) сторон.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 300 180" style="max-width:320px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- Triangle: A=(150,18), B=(30,162), C=(270,162) -->
|
||
<!-- Bisector of angle A: splits BC in ratio AB:AC -->
|
||
<!-- AB = sqrt((150-30)^2+(18-162)^2) = sqrt(14400+20736) = sqrt(35136) ≈ 187.4 -->
|
||
<!-- AC = sqrt((150-270)^2+(18-162)^2) = sqrt(14400+20736) ≈ 187.4 (isoceles here) -->
|
||
<!-- Let's use asymmetric: A=(120,18), B=(30,162), C=(260,162) -->
|
||
<!-- AB = sqrt(90^2+144^2)=sqrt(8100+20736)=sqrt(28836)≈169.8, AC=sqrt(140^2+144^2)=sqrt(19600+20736)=sqrt(40336)≈200.8 -->
|
||
<!-- D divides BC: BD/DC = AB/AC = 169.8/200.8 ≈ 0.846 → BD = 230*0.846/1.846 ≈ 105.5, D=(30+105.5,162)=(135.5,162) -->
|
||
<polygon points="120,18 30,162 260,162" fill="rgba(192,38,211,.1)" stroke="#c026d3" stroke-width="2"/>
|
||
<!-- bisector AD -->
|
||
<line x1="120" y1="18" x2="136" y2="162" stroke="#f59e0b" stroke-width="2.5" stroke-dasharray="6,3"/>
|
||
<!-- D point -->
|
||
<circle cx="136" cy="162" r="4" fill="#f59e0b"/>
|
||
<!-- BD in green, DC in blue -->
|
||
<line x1="30" y1="162" x2="136" y2="162" stroke="#10b981" stroke-width="3"/>
|
||
<line x1="136" y1="162" x2="260" y2="162" stroke="#6366f1" stroke-width="3"/>
|
||
<!-- Labels -->
|
||
<text x="120" y="12" text-anchor="middle" font-size="11" font-weight="800" fill="#a21caf">A</text>
|
||
<text x="18" y="170" font-size="11" font-weight="800" fill="#a21caf">B</text>
|
||
<text x="262" y="170" font-size="11" font-weight="800" fill="#a21caf">C</text>
|
||
<text x="136" y="175" text-anchor="middle" font-size="10" font-weight="800" fill="#b45309">D</text>
|
||
<!-- Side labels -->
|
||
<text x="66" y="90" text-anchor="middle" font-size="10" fill="#c026d3" font-style="italic" font-weight="700">c=AB</text>
|
||
<text x="198" y="90" text-anchor="middle" font-size="10" fill="#c026d3" font-style="italic" font-weight="700">b=AC</text>
|
||
<!-- BD, DC labels -->
|
||
<text x="83" y="155" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">BD</text>
|
||
<text x="198" y="155" text-anchor="middle" font-size="10" fill="#6366f1" font-weight="800">DC</text>
|
||
<!-- AD label -->
|
||
<text x="135" y="85" text-anchor="start" font-size="9" fill="#b45309" font-weight="700">AD — биссектриса</text>
|
||
<text x="150" y="12" text-anchor="middle" font-size="9" fill="#c026d3" font-weight="800">BD/DC = AB/AC = c/b</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Доказательство — через параллельную прямую','8.2',`
|
||
<p><b>Метод доказательства:</b> через точку $C$ проводим прямую, параллельную биссектрисе $AD$, до пересечения с продолжением стороны $AB$ в точке $E$.</p>
|
||
<ol style="margin-left:18px;margin-top:8px;line-height:2">
|
||
<li>$CE \\parallel AD$, $AD$ — биссектриса $\\angle A$ → $\\angle 1 = \\angle 2$ (смежно-внутренние при секущей $AB$).</li>
|
||
<li>$\\angle 2 = \\angle 3$ (вертикальные углы при пересечении $CE$ и $AB$ ... скорректировано: соответственные углы при параллельных). Значит $\\angle 1 = \\angle 3$, т.е. $\\triangle ACE$ — равнобедренный: $AE = AC = b$.</li>
|
||
<li>По теореме Фалеса (прямая $AD \\parallel CE$, секущие $BA$ и $BC$): $\\dfrac{BD}{DC} = \\dfrac{BA}{AE} = \\dfrac{c}{b}$.</li>
|
||
</ol>
|
||
<p style="margin-top:8px"><b>Итог:</b> $\\dfrac{BD}{DC} = \\dfrac{c}{b} = \\dfrac{AB}{AC}$. <b>Теорема доказана.</b></p>
|
||
<div style="display:flex;justify-content:center;margin-top:12px">
|
||
<svg viewBox="0 0 340 250" style="max-width:360px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!--
|
||
Layout (all within viewBox 0 0 340 250):
|
||
Triangle ABC: A=(150,80), B=(30,210), C=(295,210)
|
||
Bisector AD: D on BC at BD/DC = AB/AC ≈ 0.857 → D=(153,210)
|
||
E on extension of BA beyond A: place E at (230,30) — visually above-right of A.
|
||
CE dashed from C(295,210) to E(230,30).
|
||
Parallel tick marks on AD and CE to show CE∥AD.
|
||
-->
|
||
<!-- Main triangle -->
|
||
<polygon points="150,80 30,210 295,210" fill="rgba(192,38,211,.08)" stroke="#c026d3" stroke-width="1.8"/>
|
||
<!-- Bisector AD (orange dashed) -->
|
||
<line x1="150" y1="80" x2="153" y2="210" stroke="#f59e0b" stroke-width="2.5" stroke-dasharray="6,3"/>
|
||
<!-- Parallel tick marks on AD midpoint -->
|
||
<line x1="149" y1="143" x2="153" y2="151" stroke="#f59e0b" stroke-width="2.5"/>
|
||
<line x1="153" y1="141" x2="157" y2="149" stroke="#f59e0b" stroke-width="2.5"/>
|
||
<!-- D point on BC -->
|
||
<circle cx="153" cy="210" r="4.5" fill="#f59e0b" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- BD green, DC blue on baseline -->
|
||
<line x1="30" y1="210" x2="153" y2="210" stroke="#10b981" stroke-width="3.5"/>
|
||
<line x1="153" y1="210" x2="295" y2="210" stroke="#6366f1" stroke-width="3.5"/>
|
||
<!-- E above A — extension of BA beyond A -->
|
||
<circle cx="220" cy="32" r="4.5" fill="#4f46e5" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- Extension BA → E (thin dashed blue) -->
|
||
<line x1="30" y1="210" x2="222" y2="32" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="4,2"/>
|
||
<!-- CE (green dashed, parallel to AD) -->
|
||
<line x1="295" y1="210" x2="220" y2="32" stroke="#10b981" stroke-width="2" stroke-dasharray="5,3"/>
|
||
<!-- Parallel tick marks on CE midpoint -->
|
||
<line x1="254" y1="119" x2="258" y2="127" stroke="#10b981" stroke-width="2.2"/>
|
||
<line x1="258" y1="117" x2="262" y2="125" stroke="#10b981" stroke-width="2.2"/>
|
||
<!-- Vertex circles -->
|
||
<circle cx="150" cy="80" r="4" fill="#c026d3" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="30" cy="210" r="4" fill="#c026d3" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="295" cy="210" r="4" fill="#c026d3" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- Vertex labels -->
|
||
<text x="150" y="73" text-anchor="middle" font-size="11" font-weight="800" fill="#a21caf">A</text>
|
||
<text x="18" y="222" font-size="11" font-weight="800" fill="#a21caf">B</text>
|
||
<text x="298" y="222" font-size="11" font-weight="800" fill="#a21caf">C</text>
|
||
<text x="153" y="224" text-anchor="middle" font-size="10" font-weight="800" fill="#b45309">D</text>
|
||
<text x="228" y="27" text-anchor="middle" font-size="11" font-weight="800" fill="#4f46e5">E</text>
|
||
<!-- Side labels AB, AC — outside -->
|
||
<text x="76" y="140" text-anchor="end" font-size="10" fill="#c026d3" font-style="italic" font-weight="700">c=AB</text>
|
||
<text x="234" y="138" font-size="10" fill="#c026d3" font-style="italic" font-weight="700">b=AC</text>
|
||
<!-- CE∥AD label -->
|
||
<text x="308" y="108" font-size="9" fill="#10b981" font-weight="700">CE∥AD</text>
|
||
<!-- BD DC labels -->
|
||
<text x="92" y="204" text-anchor="middle" font-size="9" fill="#10b981" font-weight="800">BD</text>
|
||
<text x="224" y="204" text-anchor="middle" font-size="9" fill="#6366f1" font-weight="800">DC</text>
|
||
<!-- AE=AC=b label near E -->
|
||
<text x="218" y="48" text-anchor="end" font-size="9" fill="#4f46e5" font-weight="700">AE=AC=b</text>
|
||
<!-- Bottom caption -->
|
||
<text x="170" y="242" text-anchor="middle" font-size="9" fill="#c026d3" font-weight="800">BD/DC = BA/AE = c/b (теорема Фалеса)</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('example','Примеры применения','8.3',`
|
||
<p><b>Пример 1.</b> В $\\triangle ABC$ биссектриса $\\angle A$ делит $BC$. $AB=6$, $AC=9$, $BC=15$. Найти $BD$ и $DC$.</p>
|
||
<p style="margin-top:6px">$\\dfrac{BD}{DC} = \\dfrac{AB}{AC} = \\dfrac{6}{9} = \\dfrac{2}{3}$. Сумма $BD+DC=15$. Тогда $BD = \\dfrac{2}{5} \\cdot 15 = 6$, $DC = 9$.</p>
|
||
<p style="margin-top:10px"><b>Пример 2.</b> $AB=8$, $AC=12$, $BD=4$. Найти $DC$.</p>
|
||
<p style="margin-top:6px">$\\dfrac{4}{DC} = \\dfrac{8}{12}$ → $DC = \\dfrac{4 \\cdot 12}{8} = 6$.</p>
|
||
<p style="margin-top:10px"><b>Пример 3.</b> $BD=5$, $DC=7$. Найти $AB$, если $AC=14$.</p>
|
||
<p style="margin-top:6px">$\\dfrac{AB}{AC} = \\dfrac{BD}{DC} = \\dfrac{5}{7}$ → $AB = \\dfrac{5 \\cdot 14}{7} = 10$.</p>`);
|
||
|
||
/* ---- ИНТЕРАКТИВ 1: SVG с биссектрисой (слайдеры AB, AC) ---- */
|
||
html+=`<div class="wg" id="p8-svg-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Биссектриса $AD$ — живая пропорция</div></div>
|
||
<div class="wg-help">Меняй стороны $AB$ и $AC$ — точка $D$ автоматически делит $BC$ в отношении $AB:AC$. Цвета: BD — зелёный, DC — синий.</div>
|
||
<div class="sliders">
|
||
<label>$AB = c$: <b id="p8-c-val">6</b>
|
||
<input type="range" min="2" max="14" value="6" id="p8-c-sl" step="1">
|
||
</label>
|
||
<label>$AC = b$: <b id="p8-b-val">9</b>
|
||
<input type="range" min="2" max="14" value="9" id="p8-b-sl" step="1">
|
||
</label>
|
||
<label>$BC$: <b id="p8-a-val">12</b>
|
||
<input type="range" min="4" max="20" value="12" id="p8-a-sl" step="1">
|
||
</label>
|
||
</div>
|
||
<div id="p8-svg-out" style="display:flex;justify-content:center"></div>
|
||
<div id="p8-svg-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
|
||
html+=`<div class="wg" id="p8-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство — по шагам</div></div>
|
||
<div class="wg-help">Нажимай «Далее» для каждого шага. Доказательство через параллельную прямую.</div>
|
||
<div id="p8-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p8-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p8-proof-next">Далее</button>
|
||
<button class="btn" id="p8-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 3: Калькулятор биссектрисы ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: AB, AC, BC → BD и DC</div></div>
|
||
<div class="wg-help">Введи три стороны треугольника и получи отрезки $BD$, $DC$, которые образует биссектриса.</div>
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">AB = c</span><input type="number" id="p8-kc" class="tinp" placeholder="напр. 6" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">AC = b</span><input type="number" id="p8-kb" class="tinp" placeholder="напр. 9" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">BC</span><input type="number" id="p8-ka" class="tinp" placeholder="напр. 15" style="width:100%"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p8-kcalc" style="width:100%">Вычислить</button></div>
|
||
</div>
|
||
<div id="p8-kcalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.7"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 4: Тренажёр ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §8 — Биссектриса</div></div>
|
||
<div class="wg-help">5 задач на нахождение отрезков BD, DC и сторон по свойству биссектрисы.</div>
|
||
<div class="score-display"><span>Задача <b id="p8-tr-i">1</b> / 5</span><span>Очки: <b id="p8-tr-score">0</b></span></div>
|
||
<div id="p8-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p8-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
|
||
<button class="btn primary" id="p8-tr-go">Проверить</button>
|
||
<button class="btn" id="p8-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p8-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 5: DnD-сортер ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Верное деление или нет? — Сортировка</div></div>
|
||
<div class="wg-help">Перетащи каждую карточку: если биссектриса с данными $AB$, $AC$ действительно делит $BC$ в указанном отношении — в «Верно», иначе — «Неверно».</div>
|
||
<div id="p8-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p8-drop-yes"><h5>Верно (BD/DC = AB/AC)</h5><div class="drop-items" id="p8-drop-yes-items"></div></div>
|
||
<div class="drop-box" id="p8-drop-no"><h5>Неверно</h5><div class="drop-items" id="p8-drop-no-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p8-dnd-check">Проверить</button><button class="btn" id="p8-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p8-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 6: Босс §8 ---- */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §8</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p8-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p8-read-btn" onclick="addXp(10,'p8-read');bumpProgress('p8',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §8 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p7','p9');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: живой SVG биссектрисы == */
|
||
(function(){
|
||
const cSl=document.getElementById('p8-c-sl');
|
||
const bSl=document.getElementById('p8-b-sl');
|
||
const aSl=document.getElementById('p8-a-sl');
|
||
const cVal=document.getElementById('p8-c-val');
|
||
const bVal=document.getElementById('p8-b-val');
|
||
const aVal=document.getElementById('p8-a-val');
|
||
const svgOut=document.getElementById('p8-svg-out');
|
||
const infoEl=document.getElementById('p8-svg-info');
|
||
|
||
function draw(){
|
||
const c=+cSl.value, b=+bSl.value, a=+aSl.value;
|
||
cVal.textContent=c; bVal.textContent=b; aVal.textContent=a;
|
||
|
||
// Triangle: B=(40,170), C=(40+a*16,170) — scaled horizontally
|
||
// A somewhere above — use fixed A position for clear view
|
||
// Place B at left, C at right on baseline, A above
|
||
const W=400, H=200;
|
||
const scale=Math.min(14, Math.floor(320/a));
|
||
const Bx=40, By=170;
|
||
const Cx=Bx+a*scale, Cy=170;
|
||
// A: place using sides c=AB, b=AC
|
||
// AB=c, AC=b. Place A using cosine rule for angle B:
|
||
// cos B = (c^2 + a^2 - b^2)/(2*c*a)
|
||
const cosB=(c*c+a*a-b*b)/(2*c*a);
|
||
if(cosB<-0.999||cosB>0.999||!isFinite(cosB)){
|
||
svgOut.innerHTML='<div style="color:var(--bad);padding:10px">Нарушено треугольное неравенство. Измени стороны.</div>';
|
||
infoEl.innerHTML='Некорректные стороны.';
|
||
return;
|
||
}
|
||
const sinB=Math.sqrt(1-cosB*cosB);
|
||
const Ax=Bx+c*scale*cosB;
|
||
const Ay=By-c*scale*sinB;
|
||
|
||
// D divides BC: BD/DC = c/b → BD = a*c/(b+c)
|
||
const BD=a*c/(b+c);
|
||
const DC=a*b/(b+c);
|
||
const Dx=Bx+BD*scale;
|
||
const Dy=By;
|
||
|
||
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
// triangle
|
||
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Cx},${Cy}" fill="rgba(192,38,211,.09)" stroke="#c026d3" stroke-width="2"/>`;
|
||
// BD segment green
|
||
s+=`<line x1="${Bx}" y1="${By}" x2="${Dx}" y2="${Dy}" stroke="#10b981" stroke-width="3.5"/>`;
|
||
// DC segment blue
|
||
s+=`<line x1="${Dx}" y1="${Dy}" x2="${Cx}" y2="${Cy}" stroke="#6366f1" stroke-width="3.5"/>`;
|
||
// bisector AD
|
||
s+=`<line x1="${Ax}" y1="${Ay}" x2="${Dx}" y2="${Dy}" stroke="#f59e0b" stroke-width="2.5" stroke-dasharray="6,3"/>`;
|
||
// D point
|
||
s+=`<circle cx="${Dx}" cy="${Dy}" r="5" fill="#f59e0b"/>`;
|
||
// Vertices
|
||
s+=`<circle cx="${Ax}" cy="${Ay}" r="4.5" fill="#c026d3"/>`;
|
||
s+=`<circle cx="${Bx}" cy="${By}" r="4.5" fill="#c026d3"/>`;
|
||
s+=`<circle cx="${Cx}" cy="${Cy}" r="4.5" fill="#c026d3"/>`;
|
||
// Labels
|
||
const ax=Ax, ay=Ay;
|
||
s+=`<text x="${ax}" y="${ay-7}" text-anchor="middle" font-size="12" font-weight="800" fill="#a21caf">A</text>`;
|
||
s+=`<text x="${Bx-10}" y="${By+4}" font-size="12" font-weight="800" fill="#a21caf">B</text>`;
|
||
s+=`<text x="${Cx+4}" y="${Cy+4}" font-size="12" font-weight="800" fill="#a21caf">C</text>`;
|
||
s+=`<text x="${Dx}" y="${Dy+16}" text-anchor="middle" font-size="11" font-weight="800" fill="#b45309">D</text>`;
|
||
// Side labels
|
||
const mABx=(ax+Bx)/2, mABy=(ay+By)/2;
|
||
const mACx=(ax+Cx)/2, mACy=(ay+Cy)/2;
|
||
s+=`<text x="${mABx-10}" y="${mABy}" text-anchor="end" font-size="10" fill="#c026d3" font-weight="700">c=${c}</text>`;
|
||
s+=`<text x="${mACx+10}" y="${mACy}" font-size="10" fill="#c026d3" font-weight="700">b=${b}</text>`;
|
||
// BD DC midpoints
|
||
const mBDx=(Bx+Dx)/2, mDCx=(Dx+Cx)/2;
|
||
s+=`<text x="${mBDx}" y="${By-7}" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">BD=${fmt(BD)}</text>`;
|
||
s+=`<text x="${mDCx}" y="${Cy-7}" text-anchor="middle" font-size="10" fill="#6366f1" font-weight="800">DC=${fmt(DC)}</text>`;
|
||
s+=`<text x="${W/2}" y="14" text-anchor="middle" font-size="10" fill="#c026d3" font-weight="800">BD/DC = ${fmt(BD)}/${fmt(DC)} = ${fmt(c)}/${fmt(b)} = ${fmt(c/b)}</text>`;
|
||
s+='</svg>';
|
||
svgOut.innerHTML=s;
|
||
infoEl.innerHTML=`$AB=c=${c}$, $AC=b=${b}$, $BC=${a}$. Биссектриса $AD$ делит $BC$: $BD=${fmt(BD)}$, $DC=${fmt(DC)}$. $\\dfrac{BD}{DC}=\\dfrac{${c}}{${b}}=${fmt(c/b)}$ — совпадает с $\\dfrac{AB}{AC}$.`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p8-svg');
|
||
}
|
||
cSl.addEventListener('input',draw);
|
||
bSl.addEventListener('input',draw);
|
||
aSl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Дано: $\\triangle ABC$, $AD$ — биссектриса $\\angle A$ ($D \\in BC$). Нужно доказать: $\\dfrac{BD}{DC} = \\dfrac{AB}{AC}$.',
|
||
svg:`<svg viewBox="0 0 280 155" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="120,18 30,145 250,145" fill="rgba(192,38,211,.09)" stroke="#c026d3" stroke-width="2"/><line x1="120" y1="18" x2="140" y2="145" stroke="#f59e0b" stroke-width="2.5" stroke-dasharray="5,3"/><circle cx="140" cy="145" r="4" fill="#f59e0b"/><text x="120" y="13" text-anchor="middle" font-size="11" font-weight="800" fill="#a21caf">A</text><text x="20" y="152" font-size="11" font-weight="800" fill="#a21caf">B</text><text x="252" y="152" font-size="11" font-weight="800" fill="#a21caf">C</text><text x="140" y="158" text-anchor="middle" font-size="10" font-weight="800" fill="#b45309">D</text><text x="140" y="12" text-anchor="middle" font-size="9" fill="#c026d3" font-weight="700">AD — биссектриса ∠A, D ∈ BC</text></svg>`},
|
||
{desc:'<b>Шаг 2.</b> Через вершину $C$ проводим прямую $CE \\parallel AD$ до пересечения с продолжением стороны $AB$ в точке $E$.',
|
||
svg:`<svg viewBox="0 0 280 165" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="110,22 30,150 240,150" fill="rgba(192,38,211,.08)" stroke="#c026d3" stroke-width="1.5"/><line x1="110" y1="22" x2="130" y2="150" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5,3"/><line x1="240" y1="150" x2="190" y2="22" stroke="#10b981" stroke-width="2" stroke-dasharray="6,2"/><line x1="30" y1="150" x2="210" y2="22" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="3,2"/><circle cx="190" cy="22" r="4" fill="#6366f1"/><circle cx="130" cy="150" r="4" fill="#f59e0b"/><text x="110" y="16" text-anchor="middle" font-size="10" font-weight="800" fill="#a21caf">A</text><text x="20" y="158" font-size="10" font-weight="800" fill="#a21caf">B</text><text x="242" y="158" font-size="10" font-weight="800" fill="#a21caf">C</text><text x="130" y="162" text-anchor="middle" font-size="9" font-weight="800" fill="#b45309">D</text><text x="192" y="16" font-size="10" font-weight="800" fill="#4f46e5">E</text><text x="210" y="100" font-size="9" fill="#10b981" font-weight="700">CE ∥ AD</text></svg>`},
|
||
{desc:'<b>Шаг 3.</b> Так как $CE \\parallel AD$ и $AD$ — биссектриса: $\\angle 1 = \\angle DAB$ (смежно-внутренние при секущей $AB$), $\\angle 2 = \\angle DAC$ (соответственные при секущей $AC$). Поскольку $\\angle DAB = \\angle DAC$ (биссектриса!), то $\\angle 1 = \\angle 2$. В $\\triangle ACE$: $\\angle AEC = \\angle 1$, $\\angle ACE = \\angle 2$ → $\\angle AEC = \\angle ACE$ → $\\triangle ACE$ равнобедренный, $AE = AC = b$.',
|
||
svg:`<svg viewBox="0 0 280 100" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="22" text-anchor="middle" font-size="11" fill="#c026d3" font-weight="700">CE ∥ AD, AD — биссектриса ∠A</text><text x="140" y="42" text-anchor="middle" font-size="11" fill="#10b981" font-weight="700">∠AEC = ∠ACE → △ACE равнобедренный</text><text x="140" y="62" text-anchor="middle" font-size="12" fill="#a21caf" font-weight="800">AE = AC = b</text><text x="140" y="85" text-anchor="middle" font-size="10" fill="#6366f1">Ключевой шаг доказательства</text></svg>`},
|
||
{desc:'<b>Шаг 4.</b> По теореме Фалеса (параллельные $AD \\parallel CE$, секущие $BA$ и $BC$):<br>$\\dfrac{BD}{DC} = \\dfrac{BA}{AE}$.',
|
||
svg:`<svg viewBox="0 0 280 90" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="24" text-anchor="middle" font-size="11" fill="#4338ca" font-weight="800">Теорема Фалеса: AD ∥ CE</text><text x="140" y="46" text-anchor="middle" font-size="12" fill="#c026d3" font-weight="800">BD/DC = BA/AE</text><text x="140" y="68" text-anchor="middle" font-size="10" fill="#6366f1">секущие BA и BC пересекают параллельные AD и CE</text><text x="140" y="85" text-anchor="middle" font-size="9" fill="#10b981">Теорема Фалеса — §1 этой главы</text></svg>`},
|
||
{desc:'<b>Шаг 5.</b> Подставляем $AE = AC = b$ (шаг 3): $\\dfrac{BD}{DC} = \\dfrac{BA}{AE} = \\dfrac{c}{b} = \\dfrac{AB}{AC}$. <b>Теорема доказана.</b>',
|
||
svg:`<svg viewBox="0 0 280 80" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="12" fill="#c026d3" font-weight="800">BD/DC = BA/AE = c/b = AB/AC</text><text x="140" y="50" text-anchor="middle" font-size="10" fill="#6366f1">Биссектриса делит BC в отношении AB:AC</text><text x="140" y="70" text-anchor="middle" font-size="14" fill="#10b981" font-weight="900">QED ∎</text></svg>`},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p8-proof-svg');
|
||
const descEl=document.getElementById('p8-proof-desc');
|
||
function show(){svgEl.innerHTML=steps[step].svg;descEl.innerHTML=steps[step].desc;renderMath(descEl);}
|
||
document.getElementById('p8-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p8-proof-step');}
|
||
else{addXp(5,'p8-proof-done');bumpProgress('p8',10);}
|
||
});
|
||
document.getElementById('p8-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: калькулятор == */
|
||
(function(){
|
||
document.getElementById('p8-kcalc').addEventListener('click',()=>{
|
||
const c=parseFloat(document.getElementById('p8-kc').value);
|
||
const b=parseFloat(document.getElementById('p8-kb').value);
|
||
const a=parseFloat(document.getElementById('p8-ka').value);
|
||
const out=document.getElementById('p8-kcalc-out');
|
||
if([c,b,a].some(v=>!isFinite(v)||v<=0)){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи все три значения (положительные числа).</span>';return;
|
||
}
|
||
const BD=a*c/(b+c);
|
||
const DC=a*b/(b+c);
|
||
out.style.display='block';
|
||
out.innerHTML=`$\\dfrac{BD}{DC} = \\dfrac{AB}{AC} = \\dfrac{${fmt(c)}}{${fmt(b)}}$.<br>$BC = ${fmt(a)}$, поэтому:<br>$BD = \\dfrac{c}{b+c} \\cdot BC = \\dfrac{${fmt(c)}}{${fmt(b+c)}} \\cdot ${fmt(a)} = <b>${fmt(BD)}</b>$.<br>$DC = \\dfrac{b}{b+c} \\cdot BC = \\dfrac{${fmt(b)}}{${fmt(b+c)}} \\cdot ${fmt(a)} = <b>${fmt(DC)}</b>$.`;
|
||
renderMath(out);
|
||
addXp(3,'p8-calc');bumpProgress('p8',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'$\\triangle ABC$: $AB=6$, $AC=9$, $BC=15$. Биссектриса $\\angle A$ делит $BC$ в точке $D$. Найди $BD$.',ans:6,hint:'BD/DC = AB/AC = 6/9 = 2/3. BD = 2/(2+3)·15 = 6.'},
|
||
{q:'$\\triangle ABC$: $AB=8$, $AC=12$, $BD=4$. Биссектриса $\\angle A$ делит $BC$ в точке $D$. Найди $DC$.',ans:6,hint:'BD/DC = AB/AC → 4/DC = 8/12 → DC = 4·12/8 = 6.'},
|
||
{q:'Биссектриса $\\angle A$ делит $BC$: $BD=5$, $DC=7$, $AC=14$. Найди $AB$.',ans:10,hint:'AB/AC = BD/DC = 5/7 → AB = 5·14/7 = 10.'},
|
||
{q:'$\\triangle ABC$: $AB=10$, $AC=15$, $BC=20$. Найди $DC$ (биссектриса $\\angle A$).',ans:12,hint:'DC = b/(b+c)·BC = 15/25·20 = 12.'},
|
||
{q:'Биссектриса $\\angle A$: $AB=4$, $AC=6$, $BD=8$. Найди $BC$.',ans:20,hint:'BD/DC = AB/AC = 4/6 = 2/3 → DC = BD·3/2 = 12. BC = BD+DC = 8+12 = 20.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p8-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p8-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p8-tr-ans').value='';
|
||
document.getElementById('p8-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p8-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p8-tr-score').textContent=0;show();});
|
||
document.getElementById('p8-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p8-tr-ans').value;
|
||
const fb=document.getElementById('p8-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.05){
|
||
score++;document.getElementById('p8-tr-score').textContent=score;
|
||
addXp(3,'p8-tr-'+idx);bumpProgress('p8',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p8-tr-all');bumpProgress('p8',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p8-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p8-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: DnD-сортер == */
|
||
(function(){
|
||
const items=[
|
||
{text:'AB=6, AC=9, BD=4, DC=6',yes:true},
|
||
{text:'AB=5, AC=8, BD=5, DC=8',yes:true},
|
||
{text:'AB=4, AC=6, BD=3, DC=5',yes:false},
|
||
{text:'AB=10, AC=15, BD=8, DC=12',yes:true},
|
||
{text:'AB=3, AC=7, BD=3, DC=5',yes:false},
|
||
];
|
||
const pool=document.getElementById('p8-dnd-pool');
|
||
const yesBox=document.getElementById('p8-drop-yes-items');
|
||
const noBox=document.getElementById('p8-drop-no-items');
|
||
let dragging=null;
|
||
function makeChip(it,i){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';chip.dataset.idx=i;chip.textContent=it.text;chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p8-drop-yes'),document.getElementById('p8-drop-no'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p8-drop-yes')?yesBox:box===document.getElementById('p8-drop-no')?noBox:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p8-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p8-dnd-fb');
|
||
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
|
||
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
|
||
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
|
||
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p8-dnd');bumpProgress('p8',8);}
|
||
else{feedback(fb,false,'Есть ошибки. Проверь: BD/DC должно равняться AB/AC.');}
|
||
});
|
||
document.getElementById('p8-dnd-reset').addEventListener('click',()=>{
|
||
[...yesBox.children].forEach(c=>pool.appendChild(c));
|
||
[...noBox.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p8-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §8 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'<svg viewBox="0 0 280 145" style="display:block;max-width:280px;margin:0 auto 8px;background:#fae8ff;border:1px solid #e879f9;border-radius:8px"><polygon points="120,18 30,135 250,135" fill="rgba(192,38,211,.10)" stroke="#c026d3" stroke-width="2"/><line x1="120" y1="18" x2="140" y2="135" stroke="#f59e0b" stroke-width="2.5" stroke-dasharray="5,3"/><line x1="30" y1="135" x2="140" y2="135" stroke="#10b981" stroke-width="3"/><line x1="140" y1="135" x2="250" y2="135" stroke="#6366f1" stroke-width="3"/><circle cx="140" cy="135" r="4" fill="#f59e0b"/><text x="120" y="12" text-anchor="middle" font-size="10" fill="#a21caf" font-weight="800">A</text><text x="20" y="143" font-size="10" fill="#a21caf" font-weight="800">B</text><text x="252" y="143" font-size="10" fill="#a21caf" font-weight="800">C</text><text x="140" y="148" text-anchor="middle" font-size="9" fill="#b45309" font-weight="800">D</text><text x="140" y="10" text-anchor="middle" font-size="8" fill="#c026d3">AB=9, AC=12, BC=21</text></svg>$AB=9$, $AC=12$, $BC=21$. Биссектриса $\\angle A$ делит $BC$ в точке $D$. Найди $BD$.',ans:9,hint:'BD/DC = AB/AC = 9/12 = 3/4. BD = 3/7·21 = 9.'},
|
||
{q:'Биссектриса $\\angle A$ делит $BC$: $BD=6$, $DC=10$, $BC=16$. $AB=9$. Найди $AC$.',ans:15,hint:'BD/DC = AB/AC → 6/10 = 9/AC → AC = 9·10/6 = 15.'},
|
||
{q:'В $\\triangle ABC$: $AB=7$, $AC=14$, биссектриса $\\angle A$ делит $BC$ на $BD$ и $DC$. Чему равно $BD$, если $BC=12$?',ans:4,hint:'BD = AB/(AB+AC)·BC = 7/21·12 = 4.'},
|
||
{q:'Биссектриса $\\angle B$ треугольника $ABC$ делит сторону $AC$ в точке $E$: $AE=6$, $EC=9$. $BC=15$. Найди $AB$.',ans:10,hint:'AE/EC = AB/BC → 6/9 = AB/15 → AB = 6·15/9 = 10.'},
|
||
];
|
||
const bossBox=document.getElementById('p8-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p8b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p8b-a${i}').value;
|
||
const fb=document.getElementById('p8b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.05){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p8BossSolved.has(${i})){ window.p8BossSolved.add(${i}); addXp(5,'p8-boss${i}'); bumpProgress('p8',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p8b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p8BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
|
||
function buildP9(){
|
||
const box=document.getElementById('p9-body');
|
||
let html='';
|
||
|
||
/* ---- Theory cards ---- */
|
||
html+=makeCard('theory','Отношение площадей подобных треугольников','9.1',`
|
||
<p><b>Теорема.</b> Если $\\triangle ABC \\sim \\triangle A'B'C'$ с коэффициентом подобия $k$, то:</p>
|
||
$$\\dfrac{S_{ABC}}{S_{A'B'C'}} = k^2$$
|
||
<p style="margin-top:8px">Площади подобных треугольников относятся как <b>квадрат коэффициента подобия</b>. Это означает: при увеличении сторон в $k$ раз площадь вырастает в $k^2$ раз.</p>
|
||
<p style="margin-top:8px"><b>Обобщение:</b> отношение площадей любых подобных фигур (многоугольников, кругов) тоже равно $k^2$.</p>
|
||
<div style="display:flex;justify-content:center;margin-top:14px">
|
||
<svg viewBox="0 0 350 195" style="max-width:370px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
|
||
<!-- k label at top — clear of all figures -->
|
||
<text x="175" y="13" text-anchor="middle" font-size="10" fill="#f59e0b" font-weight="800">k = 2: S₁/S₂ = k² = 4</text>
|
||
<!-- Large triangle: A=(90,32), B=(14,172), C=(214,172) — S1 -->
|
||
<polygon points="90,32 14,172 214,172" fill="rgba(124,58,237,.15)" stroke="#7c3aed" stroke-width="2"/>
|
||
<text x="90" y="25" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text>
|
||
<text x="2" y="182" font-size="11" font-weight="800" fill="#6d28d9">B</text>
|
||
<text x="216" y="182" font-size="11" font-weight="800" fill="#6d28d9">C</text>
|
||
<text x="100" y="118" text-anchor="middle" font-size="10" fill="#7c3aed" font-weight="700">S₁</text>
|
||
<!-- Small triangle k=2: B'C'≈100, gap≥40px from C=(214,172) → B'=258 -->
|
||
<polygon points="286,97 258,172 332,172" fill="rgba(99,102,241,.22)" stroke="#6366f1" stroke-width="1.8"/>
|
||
<text x="286" y="90" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text>
|
||
<text x="246" y="182" font-size="10" font-weight="800" fill="#4f46e5">B'</text>
|
||
<text x="334" y="182" font-size="10" font-weight="800" fill="#4f46e5">C'</text>
|
||
<text x="294" y="148" text-anchor="middle" font-size="9" fill="#6366f1" font-weight="700">S₂</text>
|
||
</svg>
|
||
</div>`);
|
||
|
||
html+=makeCard('rule','Доказательство через формулу площади','9.2',`
|
||
<p>Пусть $\\triangle ABC \\sim \\triangle A'B'C'$, коэффициент подобия $k$: $AB = k \\cdot A'B'$, $BC = k \\cdot B'C'$ и т.д.</p>
|
||
<p style="margin-top:8px">Высоты подобных треугольников тоже относятся как $k$ (высота строится из вершины перпендикулярно к стороне, а все стороны уменьшены в $k$ раз). Обозначим $h$ и $h'$ — высоты к $BC$ и $B'C'$:</p>
|
||
$$h = k \\cdot h'$$
|
||
<p style="margin-top:8px">Тогда:</p>
|
||
$$\\dfrac{S_{ABC}}{S_{A'B'C'}} = \\dfrac{\\tfrac{1}{2} \\cdot BC \\cdot h}{\\tfrac{1}{2} \\cdot B'C' \\cdot h'} = \\dfrac{BC}{B'C'} \\cdot \\dfrac{h}{h'} = k \\cdot k = k^2$$
|
||
<p style="margin-top:8px">Обобщение: для любых подобных многоугольников с коэффициентом подобия $k$: $S_1/S_2 = k^2$.</p>`);
|
||
|
||
html+=makeCard('example','Примеры','9.3',`
|
||
<p><b>Пример 1.</b> $\\triangle ABC \\sim \\triangle A'B'C'$, $k=3$, $S_{A'B'C'} = 8$. Найти $S_{ABC}$.</p>
|
||
<p style="margin-top:6px">$S_{ABC} = k^2 \\cdot S_{A'B'C'} = 9 \\cdot 8 = 72$.</p>
|
||
<p style="margin-top:10px"><b>Пример 2.</b> Стороны двух подобных треугольников — $6$ и $10$. Площадь меньшего — $18$. Найти площадь большего.</p>
|
||
<p style="margin-top:6px">$k = 10/6 = 5/3$. $S_2 = k^2 \\cdot S_1 = (5/3)^2 \\cdot 18 = 25/9 \\cdot 18 = 50$.</p>
|
||
<p style="margin-top:10px"><b>Пример 3.</b> $S_1 = 48$, $S_2 = 75$. Найти $k = \\sqrt{S_1/S_2}$ ... нет, $k = \\sqrt{S_2/S_1} = \\sqrt{75/48} = \\sqrt{25/16} = 5/4 = 1{,}25$ (если $S_2$ у большего).</p>
|
||
<p style="margin-top:6px">$k = \\sqrt{75/48} = \\sqrt{25/16} = 1{,}25$.</p>`);
|
||
|
||
/* ---- ИНТЕРАКТИВ 1: SVG два треугольника со слайдером k ---- */
|
||
html+=`<div class="wg" id="p9-svg-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Два подобных треугольника: слайдер $k$</div></div>
|
||
<div class="wg-help">Меняй $k$ и наблюдай: второй треугольник подобен первому с коэффициентом $k$. Отношение площадей = $k^2$.</div>
|
||
<div class="sliders">
|
||
<label>Коэффициент $k$: <b id="p9-k-val">2.0</b>
|
||
<input type="range" min="10" max="30" value="20" id="p9-k-sl" step="1">
|
||
</label>
|
||
<label>Площадь $S_2$: <b id="p9-s2-val">12</b>
|
||
<input type="range" min="4" max="30" value="12" id="p9-s2-sl" step="1">
|
||
</label>
|
||
</div>
|
||
<div id="p9-svg-out" style="display:flex;justify-content:center"></div>
|
||
<div id="p9-svg-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
|
||
html+=`<div class="wg" id="p9-proof-wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство теоремы — по шагам</div></div>
|
||
<div class="wg-help">Нажимай «Далее» для каждого шага. Доказательство через формулу площади $S = \\frac{1}{2}ah$.</div>
|
||
<div id="p9-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
|
||
<div id="p9-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
|
||
<div style="display:flex;gap:8px">
|
||
<button class="btn primary" id="p9-proof-next">Далее</button>
|
||
<button class="btn" id="p9-proof-reset">Сначала</button>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 3: Калькулятор ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: $k$ и площади</div></div>
|
||
<div class="wg-help">Два режима: по $k$ и $S_2$ найти $S_1$; или по двум площадям найти $k$.</div>
|
||
<div style="display:flex;gap:14px;flex-wrap:wrap;margin-bottom:10px">
|
||
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:.88rem"><input type="radio" name="p9-mode" value="0" checked id="p9-m0" style="accent-color:var(--sec-acc,var(--pri))"> По $k$ и $S_2$ → $S_1$</label>
|
||
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:.88rem"><input type="radio" name="p9-mode" value="1" id="p9-m1" style="accent-color:var(--sec-acc,var(--pri))"> По $S_1$, $S_2$ → $k$</label>
|
||
</div>
|
||
<div id="p9-calc-mode0" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">Коэфф. $k$</span><input type="number" id="p9-ck" class="tinp" placeholder="напр. 3" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">$S_2$ (меньш.)</span><input type="number" id="p9-cs2" class="tinp" placeholder="напр. 8" style="width:100%"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p9-ccalc0" style="width:100%">Найти $S_1$</button></div>
|
||
</div>
|
||
<div id="p9-calc-mode1" style="display:none;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:8px;margin-bottom:10px">
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">$S_1$ (больш.)</span><input type="number" id="p9-cs1b" class="tinp" placeholder="напр. 72" style="width:100%"></div>
|
||
<div><span style="font-size:.8rem;color:var(--muted);display:block">$S_2$ (меньш.)</span><input type="number" id="p9-cs2b" class="tinp" placeholder="напр. 8" style="width:100%"></div>
|
||
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p9-ccalc1" style="width:100%">Найти $k$</button></div>
|
||
</div>
|
||
<div id="p9-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.7"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 4: Тренажёр ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §9 — Площади подобных треугольников</div></div>
|
||
<div class="wg-help">5 задач на применение формулы $S_1/S_2 = k^2$.</div>
|
||
<div class="score-display"><span>Задача <b id="p9-tr-i">1</b> / 5</span><span>Очки: <b id="p9-tr-score">0</b></span></div>
|
||
<div id="p9-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" id="p9-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
|
||
<button class="btn primary" id="p9-tr-go">Проверить</button>
|
||
<button class="btn" id="p9-tr-start">Начать</button>
|
||
</div>
|
||
<div class="feedback" id="p9-tr-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 5: DnD-сортер k → k² ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Соотнеси $k$ с отношением площадей $k^2$</div></div>
|
||
<div class="wg-help">Перетащи каждую карточку $k$ в колонку с верным $k^2$. Две колонки: «$k^2 = 4$» и «$k^2 = 9$».</div>
|
||
<div id="p9-dnd-pool" class="dnd-pool"></div>
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
|
||
<div class="drop-box" id="p9-drop-4"><h5>$k^2 = 4$</h5><div class="drop-items" id="p9-drop-4-items"></div></div>
|
||
<div class="drop-box" id="p9-drop-9"><h5>$k^2 = 9$</h5><div class="drop-items" id="p9-drop-9-items"></div></div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="p9-dnd-check">Проверить</button><button class="btn" id="p9-dnd-reset">Сбросить</button></div>
|
||
<div class="feedback" id="p9-dnd-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 6: Мини-квиз ---- */
|
||
html+=`<div class="wg">
|
||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 6</span><div class="wg-title">Мини-квиз: теория §9</div></div>
|
||
<div class="wg-help">5 вопросов о площадях подобных фигур. Выбери верный ответ.</div>
|
||
<div id="p9-quiz-wrap"></div>
|
||
<div class="actions"><button class="btn primary" id="p9-quiz-check">Проверить</button></div>
|
||
<div class="feedback" id="p9-quiz-fb" style="display:none"></div>
|
||
</div>`;
|
||
|
||
/* ---- ИНТЕРАКТИВ 7: Босс §9 ---- */
|
||
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
|
||
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §9</span><div class="wg-title">Итоговые задачи</div></div>
|
||
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
|
||
<div id="p9-boss-tasks"></div>
|
||
</div>`;
|
||
|
||
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="p9-read-btn" onclick="addXp(10,'p9-read');bumpProgress('p9',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я прочитал §9 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
html+=secNav('p8','final3');
|
||
box.innerHTML=html;
|
||
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
|
||
|
||
/* == INIT ИНТЕРАКТИВ 1: SVG два подобных треугольника == */
|
||
(function(){
|
||
const kSl=document.getElementById('p9-k-sl');
|
||
const s2Sl=document.getElementById('p9-s2-sl');
|
||
const kVal=document.getElementById('p9-k-val');
|
||
const s2Val=document.getElementById('p9-s2-val');
|
||
const svgOut=document.getElementById('p9-svg-out');
|
||
const infoEl=document.getElementById('p9-svg-info');
|
||
|
||
function draw(){
|
||
const k=+kSl.value/10;
|
||
const S2=+s2Sl.value;
|
||
const S1=S2*k*k;
|
||
kVal.textContent=k.toFixed(1);
|
||
s2Val.textContent=S2;
|
||
|
||
const H=220;
|
||
// Triangle 2 (smaller): fixed display size
|
||
const base2=100;
|
||
const h2=55;
|
||
const B2y=185;
|
||
|
||
// Large triangle T1 = k * T2, anchored at B1
|
||
const base1=base2*k;
|
||
const h1=h2*k;
|
||
const B1x=20, B1y=185;
|
||
const C1x=B1x+base1, C1y=185;
|
||
const A1x=B1x+base1*0.55, A1y=B1y-h1;
|
||
|
||
// Place T2 at least 30px to the right of T1
|
||
const B2x=Math.max(C1x+30, 200);
|
||
const C2x=B2x+base2, C2y=185;
|
||
const A2x=B2x+base2*0.55, A2y=B2y-h2;
|
||
|
||
// Safety: check bounds
|
||
const W=Math.max(C2x+20, 400);
|
||
const maxX=C2x+20;
|
||
const minY=Math.min(A1y, A2y)-14;
|
||
|
||
let s=`<svg viewBox="0 ${Math.min(0,minY)-5} ${Math.max(W,maxX+10)} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
|
||
// T1 large
|
||
s+=`<polygon points="${A1x},${A1y} ${B1x},${B1y} ${C1x},${C1y}" fill="rgba(124,58,237,.16)" stroke="#7c3aed" stroke-width="2.2"/>`;
|
||
// Height line T1 (from A1 perpendicular to B1C1)
|
||
s+=`<line x1="${A1x}" y1="${A1y}" x2="${A1x}" y2="${B1y}" stroke="#7c3aed" stroke-width="1.2" stroke-dasharray="4,2"/>`;
|
||
// right angle marker T1
|
||
s+=`<rect x="${A1x}" y="${B1y-12}" width="12" height="12" fill="none" stroke="#7c3aed" stroke-width="1.2"/>`;
|
||
s+=`<text x="${A1x}" y="${A1y-6}" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text>`;
|
||
s+=`<text x="${B1x-8}" y="${B1y+4}" font-size="11" font-weight="800" fill="#6d28d9">B</text>`;
|
||
s+=`<text x="${C1x+4}" y="${C1y+4}" font-size="11" font-weight="800" fill="#6d28d9">C</text>`;
|
||
const mBC1x=(B1x+C1x)/2;
|
||
s+=`<text x="${mBC1x}" y="${B1y+14}" text-anchor="middle" font-size="10" fill="#7c3aed" font-weight="700">a·k</text>`;
|
||
s+=`<text x="${A1x+6}" y="${(A1y+B1y)/2}" font-size="10" fill="#7c3aed" font-weight="700">h·k</text>`;
|
||
s+=`<text x="${mBC1x}" y="${A1y+(B1y-A1y)*0.55}" text-anchor="middle" font-size="13" fill="#7c3aed" font-weight="800">S₁=${fmt(S1)}</text>`;
|
||
|
||
// T2 small
|
||
s+=`<polygon points="${A2x},${A2y} ${B2x},${B2y} ${C2x},${C2y}" fill="rgba(99,102,241,.20)" stroke="#6366f1" stroke-width="1.8"/>`;
|
||
s+=`<line x1="${A2x}" y1="${A2y}" x2="${A2x}" y2="${B2y}" stroke="#6366f1" stroke-width="1.2" stroke-dasharray="4,2"/>`;
|
||
s+=`<rect x="${A2x}" y="${B2y-12}" width="10" height="10" fill="none" stroke="#6366f1" stroke-width="1.2"/>`;
|
||
s+=`<text x="${A2x}" y="${A2y-6}" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A'</text>`;
|
||
s+=`<text x="${B2x-10}" y="${B2y+4}" font-size="10" font-weight="800" fill="#4f46e5">B'</text>`;
|
||
s+=`<text x="${C2x+4}" y="${C2y+4}" font-size="10" font-weight="800" fill="#4f46e5">C'</text>`;
|
||
const mBC2x=(B2x+C2x)/2;
|
||
s+=`<text x="${mBC2x}" y="${B2y+14}" text-anchor="middle" font-size="9" fill="#6366f1" font-weight="700">a</text>`;
|
||
s+=`<text x="${A2x+5}" y="${(A2y+B2y)/2}" font-size="9" fill="#6366f1" font-weight="700">h</text>`;
|
||
s+=`<text x="${mBC2x}" y="${A2y+(B2y-A2y)*0.55}" text-anchor="middle" font-size="11" fill="#6366f1" font-weight="800">S₂=${S2}</text>`;
|
||
|
||
// top label
|
||
s+=`<text x="${W/2}" y="${Math.min(0,minY)+12}" text-anchor="middle" font-size="11" font-weight="800" fill="#7c3aed">k = ${k.toFixed(1)}, S₁/S₂ = k² = ${fmt(k*k)}</text>`;
|
||
s+='</svg>';
|
||
svgOut.innerHTML=s;
|
||
infoEl.innerHTML=`$k=${k.toFixed(1)}$, $S_2=${S2}$. Тогда $S_1 = k^2 \\cdot S_2 = ${k.toFixed(1)}^2 \\cdot ${S2} = ${fmt(k*k)} \\cdot ${S2} = ${fmt(S1)}$. Стороны первого в $${k.toFixed(1)}$ раз больше, площадь — в $${fmt(k*k)}$ раз больше.`;
|
||
renderMath(infoEl);
|
||
addXp(1,'p9-svg');
|
||
}
|
||
kSl.addEventListener('input',draw);
|
||
s2Sl.addEventListener('input',draw);
|
||
draw();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
|
||
(function(){
|
||
const steps=[
|
||
{desc:'<b>Шаг 1.</b> Дано: $\\triangle ABC \\sim \\triangle A\'B\'C\'$, коэффициент подобия $k$. Нужно доказать: $\\dfrac{S_{ABC}}{S_{A\'B\'C\'}} = k^2$.',
|
||
svg:`<svg viewBox="0 0 330 165" style="max-width:330px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="165" y="13" text-anchor="middle" font-size="10" fill="#f59e0b" font-weight="800">△ABC ∼ △A\'B\'C\', коэфф. k</text><polygon points="88,25 16,152 212,152" fill="rgba(124,58,237,.12)" stroke="#7c3aed" stroke-width="2"/><polygon points="272,85 250,152 316,152" fill="rgba(99,102,241,.20)" stroke="#6366f1" stroke-width="1.8"/><text x="88" y="18" text-anchor="middle" font-size="11" font-weight="800" fill="#6d28d9">A</text><text x="4" y="162" font-size="11" font-weight="800" fill="#6d28d9">B</text><text x="214" y="162" font-size="11" font-weight="800" fill="#6d28d9">C</text><text x="272" y="78" text-anchor="middle" font-size="10" font-weight="800" fill="#4f46e5">A\'</text><text x="238" y="162" font-size="10" font-weight="800" fill="#4f46e5">B\'</text><text x="318" y="162" font-size="10" font-weight="800" fill="#4f46e5">C\'</text></svg>`},
|
||
{desc:'<b>Шаг 2.</b> Из подобия: $BC = k \\cdot B\'C\'$ (основание). Проведём высоты $BH \\perp AC$ и $B\'H\' \\perp A\'C\'$. Так как $\\triangle ABH \\sim \\triangle A\'B\'H\'$ (тот же коэффициент $k$), то $BH = k \\cdot B\'H\'$.',
|
||
svg:`<svg viewBox="0 0 300 145" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="100,18 20,135 220,135" fill="rgba(124,58,237,.10)" stroke="#7c3aed" stroke-width="1.5"/><line x1="100" y1="18" x2="100" y2="135" stroke="#7c3aed" stroke-width="2" stroke-dasharray="5,3"/><text x="100" y="13" text-anchor="middle" font-size="10" font-weight="800" fill="#6d28d9">A</text><text x="10" y="143" font-size="10" font-weight="800" fill="#6d28d9">B</text><text x="222" y="143" font-size="10" font-weight="800" fill="#6d28d9">C</text><text x="104" y="70" font-size="9" fill="#7c3aed">h = k·h\'</text><rect x="100" y="127" width="10" height="10" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="100" y="143" text-anchor="middle" font-size="9" fill="#7c3aed">H</text><text x="150" y="12" text-anchor="middle" font-size="9" fill="#c026d3" font-weight="700">BC = k·B\'C\', BH = k·B\'H\'</text></svg>`},
|
||
{desc:'<b>Шаг 3.</b> Запишем формулу площади для каждого треугольника: $S_{ABC} = \\dfrac{1}{2} \\cdot BC \\cdot h$, $S_{A\'B\'C\'} = \\dfrac{1}{2} \\cdot B\'C\' \\cdot h\'$.',
|
||
svg:`<svg viewBox="0 0 300 90" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="150" y="22" text-anchor="middle" font-size="12" fill="#7c3aed" font-weight="700">S = ½ · BC · h</text><text x="150" y="44" text-anchor="middle" font-size="12" fill="#6366f1" font-weight="700">S\' = ½ · B\'C\' · h\'</text><text x="150" y="70" text-anchor="middle" font-size="10" fill="#6d28d9">Формула площади треугольника через основание и высоту</text></svg>`},
|
||
{desc:'<b>Шаг 4.</b> Составим отношение:<br>$\\dfrac{S_{ABC}}{S_{A\'B\'C\'}} = \\dfrac{\\frac{1}{2} \\cdot BC \\cdot h}{\\frac{1}{2} \\cdot B\'C\' \\cdot h\'} = \\dfrac{BC}{B\'C\'} \\cdot \\dfrac{h}{h\'} = k \\cdot k = k^2$.',
|
||
svg:`<svg viewBox="0 0 300 85" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="150" y="24" text-anchor="middle" font-size="11" fill="#4338ca" font-weight="800">S₁/S₂ = (BC/B\'C\')·(h/h\') = k·k = k²</text><text x="150" y="50" text-anchor="middle" font-size="10" fill="#6366f1">BC = k·B\'C\' и h = k·h\'</text><text x="150" y="72" text-anchor="middle" font-size="12" fill="#10b981" font-weight="800">S₁/S₂ = k²</text></svg>`},
|
||
{desc:'<b>Шаг 5.</b> <b>Обобщение:</b> для любых подобных многоугольников с коэффициентом $k$ разбиваем их на треугольники с тем же коэффициентом подобия. Сумма площадей каждого треугольника второй фигуры умножена на $k^2$. Значит $S_1/S_2 = k^2$ — верно для любых подобных фигур. <b>Теорема доказана.</b>',
|
||
svg:`<svg viewBox="0 0 300 80" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="150" y="28" text-anchor="middle" font-size="13" fill="#7c3aed" font-weight="800">S₁/S₂ = k² для подобных △</text><text x="150" y="52" text-anchor="middle" font-size="10" fill="#6366f1">Обобщается на любые подобные фигуры</text><text x="150" y="72" text-anchor="middle" font-size="14" fill="#10b981" font-weight="900">QED ∎</text></svg>`},
|
||
];
|
||
let step=0;
|
||
const svgEl=document.getElementById('p9-proof-svg');
|
||
const descEl=document.getElementById('p9-proof-desc');
|
||
function show(){svgEl.innerHTML=steps[step].svg;descEl.innerHTML=steps[step].desc;renderMath(descEl);}
|
||
document.getElementById('p9-proof-next').addEventListener('click',()=>{
|
||
if(step<steps.length-1){step++;show();addXp(1,'p9-proof-step');}
|
||
else{addXp(5,'p9-proof-done');bumpProgress('p9',10);}
|
||
});
|
||
document.getElementById('p9-proof-reset').addEventListener('click',()=>{step=0;show();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 3: калькулятор == */
|
||
(function(){
|
||
document.querySelectorAll('input[name="p9-mode"]').forEach(r=>{
|
||
r.addEventListener('change',()=>{
|
||
const m=+r.value;
|
||
document.getElementById('p9-calc-mode0').style.display=m===0?'grid':'none';
|
||
document.getElementById('p9-calc-mode1').style.display=m===1?'grid':'none';
|
||
document.getElementById('p9-ccalc-out').style.display='none';
|
||
});
|
||
});
|
||
document.getElementById('p9-ccalc0').addEventListener('click',()=>{
|
||
const k=parseFloat(document.getElementById('p9-ck').value);
|
||
const s2=parseFloat(document.getElementById('p9-cs2').value);
|
||
const out=document.getElementById('p9-ccalc-out');
|
||
if(!isFinite(k)||k<=0||!isFinite(s2)||s2<=0){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи $k > 0$ и $S_2 > 0$.</span>';renderMath(out);return;
|
||
}
|
||
const s1=s2*k*k;
|
||
out.style.display='block';
|
||
out.innerHTML=`$k = ${fmt(k)}$, $S_2 = ${fmt(s2)}$.<br>$S_1 = k^2 \\cdot S_2 = ${fmt(k)}^2 \\cdot ${fmt(s2)} = ${fmt(k*k)} \\cdot ${fmt(s2)} = <b>${fmt(s1)}</b>$.`;
|
||
renderMath(out);addXp(3,'p9-calc0');bumpProgress('p9',5);
|
||
});
|
||
document.getElementById('p9-ccalc1').addEventListener('click',()=>{
|
||
const s1=parseFloat(document.getElementById('p9-cs1b').value);
|
||
const s2=parseFloat(document.getElementById('p9-cs2b').value);
|
||
const out=document.getElementById('p9-ccalc-out');
|
||
if(!isFinite(s1)||s1<=0||!isFinite(s2)||s2<=0){
|
||
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи $S_1 > 0$ и $S_2 > 0$.</span>';renderMath(out);return;
|
||
}
|
||
const k=Math.sqrt(s1/s2);
|
||
out.style.display='block';
|
||
out.innerHTML=`$S_1 = ${fmt(s1)}$, $S_2 = ${fmt(s2)}$.<br>$k = \\sqrt{S_1/S_2} = \\sqrt{${fmt(s1)}/${fmt(s2)}} = \\sqrt{${fmt(s1/s2)}} = <b>${fmt(k)}</b>$.`;
|
||
renderMath(out);addXp(3,'p9-calc1');bumpProgress('p9',5);
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k=3$, $S_{A\'B\'C\'}=8$. Найди $S_{ABC}$.',ans:72,hint:'S = k²·S\' = 9·8 = 72.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $S_{ABC}=50$, $S_{A\'B\'C\'}=8$. Найди $k$.',ans:2.5,hint:'k = √(S/S\') = √(50/8) = √(6.25) = 2.5.'},
|
||
{q:'Стороны двух подобных треугольников — $6$ и $10$. Площадь меньшего — $18$. Найди площадь большего.',ans:50,hint:'k = 10/6 = 5/3. S₁ = (5/3)²·18 = 25/9·18 = 50.'},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k=4$. На сколько $S_{ABC}$ больше $S_{A\'B\'C\'}$? (Во сколько раз — введи число.)',ans:16,hint:'S₁/S₂ = k² = 16. Площадь больше в 16 раз.'},
|
||
{q:'Площади двух подобных треугольников: $S_1=48$, $S_2=75$. Найди $k = \\sqrt{S_2/S_1}$ (большего к меньшему).',ans:1.25,hint:'k = √(75/48) = √(25/16) = 5/4 = 1.25.'},
|
||
];
|
||
let idx=0,score=0;
|
||
function show(){
|
||
document.getElementById('p9-tr-i').textContent=idx+1;
|
||
const t=document.getElementById('p9-tr-task');
|
||
t.innerHTML=tasks[idx].q;
|
||
renderMath(t);
|
||
document.getElementById('p9-tr-ans').value='';
|
||
document.getElementById('p9-tr-fb').style.display='none';
|
||
}
|
||
document.getElementById('p9-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p9-tr-score').textContent=0;show();});
|
||
document.getElementById('p9-tr-go').addEventListener('click',()=>{
|
||
if(idx>=tasks.length)return;
|
||
const ans=+document.getElementById('p9-tr-ans').value;
|
||
const fb=document.getElementById('p9-tr-fb');
|
||
if(Math.abs(ans-tasks[idx].ans)<0.05){
|
||
score++;document.getElementById('p9-tr-score').textContent=score;
|
||
addXp(3,'p9-tr-'+idx);bumpProgress('p9',4);
|
||
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
|
||
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p9-tr-all');bumpProgress('p9',10);confetti();}
|
||
} else {
|
||
feedback(fb,false,'Неверно. '+tasks[idx].hint);
|
||
}
|
||
});
|
||
document.getElementById('p9-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p9-tr-go').click();});
|
||
show();
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 5: DnD-сортер k → k² == */
|
||
(function(){
|
||
// items: k value → which bucket k²=4 (k=2) or k²=9 (k=3)
|
||
const items=[
|
||
{text:'k = 2',group:4},
|
||
{text:'k = 3',group:9},
|
||
{text:'√4 = 2',group:4},
|
||
{text:'S₁/S₂ = 4',group:4},
|
||
{text:'S₁/S₂ = 9',group:9},
|
||
{text:'k = √9 = 3',group:9},
|
||
];
|
||
const pool=document.getElementById('p9-dnd-pool');
|
||
const box4=document.getElementById('p9-drop-4-items');
|
||
const box9=document.getElementById('p9-drop-9-items');
|
||
let dragging=null;
|
||
function makeChip(it,i){
|
||
const chip=document.createElement('div');
|
||
chip.className='dnd-chip';chip.dataset.idx=i;chip.textContent=it.text;chip.draggable=true;
|
||
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
|
||
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
|
||
return chip;
|
||
}
|
||
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
|
||
[document.getElementById('p9-drop-4'),document.getElementById('p9-drop-9'),pool].forEach(box=>{
|
||
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
|
||
box.addEventListener('dragleave',()=>box.classList.remove('over'));
|
||
box.addEventListener('drop',e=>{
|
||
e.preventDefault();box.classList.remove('over');
|
||
if(!dragging)return;
|
||
const target=box===document.getElementById('p9-drop-4')?box4:box===document.getElementById('p9-drop-9')?box9:pool;
|
||
target.appendChild(dragging);
|
||
});
|
||
});
|
||
document.getElementById('p9-dnd-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p9-dnd-fb');
|
||
const chips4=[...box4.querySelectorAll('.dnd-chip')];
|
||
const chips9=[...box9.querySelectorAll('.dnd-chip')];
|
||
if(chips4.length+chips9.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
|
||
let ok=true;
|
||
chips4.forEach(c=>{if(items[+c.dataset.idx].group!==4)ok=false;});
|
||
chips9.forEach(c=>{if(items[+c.dataset.idx].group!==9)ok=false;});
|
||
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p9-dnd');bumpProgress('p9',8);}
|
||
else{feedback(fb,false,'Есть ошибки. $k=2$ → $k^2=4$; $k=3$ → $k^2=9$.');}
|
||
});
|
||
document.getElementById('p9-dnd-reset').addEventListener('click',()=>{
|
||
[...box4.children].forEach(c=>pool.appendChild(c));
|
||
[...box9.children].forEach(c=>pool.appendChild(c));
|
||
document.getElementById('p9-dnd-fb').style.display='none';
|
||
});
|
||
})();
|
||
|
||
/* == INIT ИНТЕРАКТИВ 6: мини-квиз == */
|
||
(function(){
|
||
const qs=[
|
||
{q:'Если коэффициент подобия треугольников $k=5$, то отношение их площадей равно...',opts:['5','10','25','$\\sqrt{5}$'],ans:2},
|
||
{q:'Площади двух подобных треугольников — $9$ и $36$. Чему равен коэффициент подобия?',opts:['4','2','$\\sqrt{3}$','$\\frac{1}{2}$'],ans:1},
|
||
{q:'При каком $k$ площадь первого треугольника вдвое больше площади второго?',opts:['$k = 2$','$k = \\sqrt{2}$','$k = 4$','$k = 0{,}5$'],ans:1},
|
||
{q:'Верно ли, что для любых подобных фигур (не только треугольников) $S_1/S_2 = k^2$?',opts:['Только для треугольников','Только для прямоугольников','Да, для любых подобных фигур','Нет, только для равнобедренных'],ans:2},
|
||
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k = 3$. Периметр $\\triangle A\'B\'C\' = 12$. Периметр $\\triangle ABC$ равен...',opts:['36','108','4','144'],ans:0},
|
||
];
|
||
const wrap=document.getElementById('p9-quiz-wrap');
|
||
wrap.innerHTML=qs.map((q,qi)=>`
|
||
<div style="margin-bottom:14px;padding:12px;background:var(--card);border:1px solid var(--border);border-radius:10px">
|
||
<div style="font-weight:700;margin-bottom:8px;font-size:.95rem">${qi+1}. ${q.q}</div>
|
||
<div style="display:flex;flex-direction:column;gap:6px">
|
||
${q.opts.map((o,oi)=>`<label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-size:.92rem"><input type="radio" name="p9q${qi}" value="${oi}" style="accent-color:var(--sec-acc,var(--pri))"> ${o}</label>`).join('')}
|
||
</div>
|
||
</div>`).join('');
|
||
renderMath(wrap);
|
||
document.getElementById('p9-quiz-check').addEventListener('click',()=>{
|
||
const fb=document.getElementById('p9-quiz-fb');
|
||
let correct=0;
|
||
qs.forEach((q,qi)=>{
|
||
const sel=document.querySelector(`input[name="p9q${qi}"]:checked`);
|
||
if(sel&&+sel.value===q.ans)correct++;
|
||
});
|
||
if(correct===qs.length){
|
||
feedback(fb,true,`Все ${qs.length} ответов верны! +8 XP`);
|
||
addXp(8,'p9-quiz');bumpProgress('p9',12);confetti();
|
||
} else {
|
||
feedback(fb,false,`Верных ответов: ${correct} из ${qs.length}. Повтори: $S_1/S_2 = k^2$.`);
|
||
}
|
||
});
|
||
})();
|
||
|
||
/* == INIT: Босс §9 == */
|
||
(function(){
|
||
const tasks=[
|
||
{q:'<svg viewBox="0 0 310 158" style="display:block;max-width:310px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><text x="155" y="11" text-anchor="middle" font-size="8" fill="#7c3aed" font-weight="700">S₂=8, k=3 → S₁=?</text><polygon points="88,20 18,142 202,142" fill="rgba(124,58,237,.14)" stroke="#7c3aed" stroke-width="2"/><polygon points="264,86 244,142 310,142" fill="rgba(99,102,241,.22)" stroke="#6366f1" stroke-width="1.8"/><text x="88" y="14" text-anchor="middle" font-size="10" fill="#6d28d9" font-weight="800">A</text><text x="6" y="152" font-size="10" fill="#6d28d9" font-weight="800">B</text><text x="204" y="152" font-size="10" fill="#6d28d9" font-weight="800">C</text><text x="264" y="80" text-anchor="middle" font-size="9" fill="#4f46e5" font-weight="800">A\'</text><text x="232" y="152" font-size="9" fill="#4f46e5" font-weight="800">B\'</text><text x="312" y="152" font-size="9" fill="#4f46e5" font-weight="800">C\'</text></svg>$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k=3$, $S_{A\'B\'C\'}=8$. Найди $S_{ABC}$.',ans:72,hint:'S₁ = k²·S₂ = 9·8 = 72.'},
|
||
{q:'Стороны двух подобных треугольников: первый $12$, второй $8$. Площадь первого $S_1=54$. Найди $S_2$.',ans:24,hint:'k = 12/8 = 1.5. S₂ = S₁/k² = 54/2.25 = 24.'},
|
||
{q:'$S_1 = 75$, $S_2 = 48$. Найди коэффициент подобия $k = \\sqrt{S_1/S_2}$ (Ответ в виде десятичной дроби).',ans:1.25,hint:'k = √(75/48) = √(25/16) = 5/4 = 1.25.'},
|
||
{q:'Прямоугольный треугольник с катетами $3$ и $4$. Подобный с $k=2$. Найди площадь большего треугольника.',ans:24,hint:'S_мал = 0.5·3·4 = 6. S_бол = k²·S_мал = 4·6 = 24.'},
|
||
];
|
||
const bossBox=document.getElementById('p9-boss-tasks');
|
||
bossBox.innerHTML=tasks.map((t,i)=>`
|
||
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
|
||
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="number" class="tinp" id="p9b-a${i}" placeholder="Ответ" style="width:110px">
|
||
<button class="btn primary small" onclick="(function(){
|
||
const v=+document.getElementById('p9b-a${i}').value;
|
||
const fb=document.getElementById('p9b-fb${i}');
|
||
if(Math.abs(v-${t.ans})<0.05){
|
||
feedback(fb,true,'Верно! +5 XP');
|
||
if(!window.p9BossSolved.has(${i})){ window.p9BossSolved.add(${i}); addXp(5,'p9-boss${i}'); bumpProgress('p9',8); }
|
||
} else feedback(fb,false,'Неверно. ${t.hint}');
|
||
})()">Проверить</button>
|
||
</div>
|
||
<div class="feedback" id="p9b-fb${i}" style="display:none;margin-top:8px"></div>
|
||
</div>`).join('');
|
||
window.p9BossSolved=new Set();
|
||
renderMath(bossBox);
|
||
})();
|
||
}
|
||
function buildFinal3(){
|
||
const box = document.getElementById('final3-body');
|
||
let html = '';
|
||
|
||
/* === ЧАСТЬ 1: Итоговая шпаргалка === */
|
||
html += `<div class="card" style="border-color:var(--sec-acc,var(--pri));background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)))">
|
||
<div class="card-header">
|
||
<div class="card-icon 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>
|
||
</div>
|
||
<div class="card-title">Итоговая шпаргалка · Вся Глава 3 «Подобные треугольники»</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px">
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§1 Теорема Фалеса</div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
|
||
<line x1="10" y1="50" x2="65" y2="10" stroke="#7c3aed" stroke-width="1.8"/>
|
||
<line x1="10" y1="50" x2="65" y2="50" stroke="#7c3aed" stroke-width="1.8"/>
|
||
<line x1="14" y1="47" x2="62" y2="47" stroke="#6366f1" stroke-width="1.2" stroke-dasharray="3 2"/>
|
||
<line x1="22" y1="38" x2="62" y2="38" stroke="#6366f1" stroke-width="1.2" stroke-dasharray="3 2"/>
|
||
<line x1="34" y1="26" x2="62" y2="26" stroke="#6366f1" stroke-width="1.2" stroke-dasharray="3 2"/>
|
||
<text x="5" y="42" font-size="7" fill="#4f46e5" font-family="JetBrains Mono,monospace">A</text>
|
||
<text x="5" y="30" font-size="7" fill="#4f46e5" font-family="JetBrains Mono,monospace">B</text>
|
||
<text x="5" y="18" font-size="7" fill="#4f46e5" font-family="JetBrains Mono,monospace">C</text>
|
||
</svg>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$\dfrac{AB}{BC} = \dfrac{A'B'}{B'C'}$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">параллельные прямые</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§2 Деление m:n</div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
|
||
<line x1="5" y1="30" x2="65" y2="30" stroke="#8b5cf6" stroke-width="2"/>
|
||
<circle cx="5" cy="30" r="3.5" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="65" cy="30" r="3.5" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="37" cy="30" r="3.5" fill="#ec4899" stroke="#fff" stroke-width="1.5"/>
|
||
<text x="2" y="22" font-size="8" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">A</text>
|
||
<text x="32" y="22" font-size="8" fill="#be185d" font-family="Unbounded,sans-serif" font-weight="800">C</text>
|
||
<text x="61" y="22" font-size="8" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">B</text>
|
||
<text x="16" y="45" font-size="7" fill="#6d28d9" font-family="JetBrains Mono,monospace">m</text>
|
||
<text x="46" y="45" font-size="7" fill="#6d28d9" font-family="JetBrains Mono,monospace">n</text>
|
||
</svg>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$AC = \dfrac{m}{m+n}\cdot AB$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">$C$ делит $AB$ в $m{:}n$</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§3 Подобие треугольников</div>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$\triangle ABC \sim \triangle A'B'C'$</p>
|
||
<p style="font-size:.82rem;margin-bottom:4px">$\dfrac{a}{a'} = \dfrac{b}{b'} = \dfrac{c}{c'} = k$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">углы попарно равны</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§4 Прямая || стороне</div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
|
||
<polygon points="35,4 4,56 66,56" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="2"/>
|
||
<line x1="17" y1="34" x2="53" y2="34" stroke="#7c3aed" stroke-width="2" stroke-dasharray="3 2"/>
|
||
<circle cx="17" cy="34" r="3" fill="#7c3aed" stroke="#fff" stroke-width="1.2"/>
|
||
<circle cx="53" cy="34" r="3" fill="#7c3aed" stroke="#fff" stroke-width="1.2"/>
|
||
<text x="32" y="2" font-size="8" fill="#4f46e5" font-family="Unbounded,sans-serif" font-weight="800">A</text>
|
||
<text x="0" y="60" font-size="8" fill="#4f46e5" font-family="Unbounded,sans-serif" font-weight="800">B</text>
|
||
<text x="60" y="60" font-size="8" fill="#4f46e5" font-family="Unbounded,sans-serif" font-weight="800">C</text>
|
||
<text x="10" y="30" font-size="7" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">M</text>
|
||
<text x="54" y="30" font-size="7" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">N</text>
|
||
</svg>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$MN \parallel BC$</p>
|
||
<p style="font-size:.82rem;margin-bottom:4px">$\Rightarrow \triangle AMN \sim \triangle ABC$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">$k = AM/AB$</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§5 Признак по двум углам (УУ)</div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
|
||
<polygon points="35,4 6,56 64,56" fill="rgba(124,58,237,.10)" stroke="#7c3aed" stroke-width="2"/>
|
||
<polygon points="50,4 38,26 62,26" fill="rgba(139,92,246,.18)" stroke="#8b5cf6" stroke-width="1.8"/>
|
||
<text x="32" y="2" font-size="8" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">A</text>
|
||
<text x="2" y="60" font-size="8" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">B</text>
|
||
<text x="58" y="60" font-size="8" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">C</text>
|
||
</svg>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$\angle A = \angle A'$</p>
|
||
<p style="font-size:.82rem;margin-bottom:4px">$\angle B = \angle B'$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">$\Rightarrow$ подобны</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§6 Признак по двум сторонам и углу (СУС)</div>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$\dfrac{AB}{A'B'} = \dfrac{AC}{A'C'}$</p>
|
||
<p style="font-size:.82rem;margin-bottom:4px">$\angle A = \angle A'$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">$\Rightarrow$ подобны (СУС)</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§7 Признак по трём сторонам (ССС)</div>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$\dfrac{a}{a'} = \dfrac{b}{b'} = \dfrac{c}{c'}$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">$\Rightarrow$ подобны (ССС)</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">три пары сторон</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§8 Биссектриса</div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
|
||
<polygon points="35,4 4,56 66,56" fill="rgba(192,38,211,.08)" stroke="#c026d3" stroke-width="2"/>
|
||
<line x1="35" y1="4" x2="38" y2="56" stroke="#a21caf" stroke-width="1.8" stroke-dasharray="4 2"/>
|
||
<circle cx="38" cy="56" r="3" fill="#a21caf" stroke="#fff" stroke-width="1.2"/>
|
||
<text x="32" y="2" font-size="8" fill="#a21caf" font-family="Unbounded,sans-serif" font-weight="800">A</text>
|
||
<text x="0" y="60" font-size="8" fill="#a21caf" font-family="Unbounded,sans-serif" font-weight="800">B</text>
|
||
<text x="60" y="60" font-size="8" fill="#a21caf" font-family="Unbounded,sans-serif" font-weight="800">C</text>
|
||
<text x="38" y="52" font-size="7" fill="#a21caf" font-family="Unbounded,sans-serif" font-weight="800">D</text>
|
||
</svg>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$\dfrac{BD}{DC} = \dfrac{AB}{AC}$</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">$AD$ — биссектриса $\angle A$</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§9 Площади подобных</div>
|
||
<div>
|
||
<p style="font-size:.88rem;margin-bottom:4px">$\dfrac{S_1}{S_2} = k^2$</p>
|
||
<p style="font-size:.82rem;margin-bottom:4px">$k$ — коэффициент подобия</p>
|
||
<p style="font-size:.78rem;color:var(--muted)">площади ~ квадрату $k$</p>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
|
||
/* === ЧАСТЬ 2: Карта связей === */
|
||
html += `<div class="wg" id="final3-map-wrap">
|
||
<div class="wg-header"><span class="wg-badge">КАРТА СВЯЗЕЙ</span><div class="wg-title">Признаки подобия и следствия</div></div>
|
||
<div class="wg-help">Нажми на узел, чтобы увидеть формулировку и способ применения.</div>
|
||
<div id="final3-map-svg" style="display:flex;justify-content:center;overflow-x:auto"></div>
|
||
<div id="final3-map-info" style="min-height:56px;padding:12px 16px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-top:10px;font-size:.9rem;line-height:1.65;color:var(--text)">Нажми на узел в схеме выше</div>
|
||
</div>`;
|
||
|
||
/* === ЧАСТЬ 3: 7 боссов главы === */
|
||
html += `<div class="wg" style="border-color:#7c3aed;background:linear-gradient(135deg,var(--card),#ede9fe)">
|
||
<div class="wg-header">
|
||
<span class="wg-badge" style="background:#7c3aed">7 БОССОВ ГЛАВЫ 3</span>
|
||
<div class="wg-title">Интегрированные задачи</div>
|
||
</div>
|
||
<div class="wg-help">Каждая задача объединяет 2–3 темы главы. +10 XP за каждого побеждённого босса. Победи всех семерых — получишь +50 XP и достижение «Мастер подобия Главы 3»!</div>
|
||
<div id="final3-bosses"></div>
|
||
</div>`;
|
||
|
||
/* === ЧАСТЬ 4: Финальная плашка === */
|
||
html += `<div id="final3-finish" style="display:none;margin-top:20px;padding:24px;background:linear-gradient(135deg,#ede9fe,#f5f3ff);border:2px solid #7c3aed;border-radius:16px;text-align:center">
|
||
<div style="font-family:'Unbounded',sans-serif;font-size:1.2rem;font-weight:900;color:#4c1d95;margin-bottom:10px">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:28px;height:28px;vertical-align:middle;margin-right:6px"><polygon points="12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26"/></svg>
|
||
Мастер подобия Главы 3!
|
||
</div>
|
||
<p style="color:#4c1d95;font-size:.95rem;margin-bottom:16px">Ты победил всех 7 боссов и освоил всю Главу 3 «Подобные треугольники». Превосходная работа!</p>
|
||
<a href="/textbook/geometry-8-ch4" class="btn primary" style="font-size:.98rem;padding:12px 28px">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
|
||
Перейти к Главе 4
|
||
</a>
|
||
</div>`;
|
||
|
||
html += `<div style="margin-top:18px;display:flex;justify-content:center">
|
||
<button class="btn primary" id="final3-read-btn" onclick="addXp(10,'final3-read');bumpProgress('final3',40);this.textContent='Прочитано!';this.disabled=true;">
|
||
<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>
|
||
Я изучил Главу 3 (+10 XP)
|
||
</button>
|
||
</div>`;
|
||
|
||
html += secNav('p9', null);
|
||
box.innerHTML = html;
|
||
|
||
/* === JS: Карта связей SVG === */
|
||
(function(){
|
||
const W = 620, H = 340;
|
||
const nodes = [
|
||
{ id:'sim', x:310, y:28, rx:62, label:'Подобие треугольников',
|
||
props:'Два треугольника подобны, если углы попарно равны и стороны пропорциональны. $\\triangle ABC \\sim \\triangle A\'B\'C\'$, коэффициент $k$.' },
|
||
{ id:'aa', x:100, y:120, rx:54, label:'По двум углам (УУ)',
|
||
props:'§5: Если два угла одного треугольника равны двум углам другого — треугольники подобны. Наиболее часто применяемый признак.' },
|
||
{ id:'sas', x:310, y:120, rx:54, label:'По сторонам и углу (СУС)',
|
||
props:'§6: Два треугольника подобны, если две стороны пропорциональны и угол между ними равен: $\\dfrac{AB}{A\'B\'} = \\dfrac{AC}{A\'C\'}$, $\\angle A = \\angle A\'$.' },
|
||
{ id:'sss', x:510, y:120, rx:54, label:'По трём сторонам (ССС)',
|
||
props:'§7: Три треугольника подобны, если все три пары сторон пропорциональны: $\\dfrac{a}{a\'} = \\dfrac{b}{b\'} = \\dfrac{c}{c\'}$.' },
|
||
{ id:'fales', x:80, y:230, rx:52, label:'Теорема Фалеса',
|
||
props:'§1: Параллельные прямые отсекают пропорциональные отрезки на двух секущих. $\\dfrac{AB}{BC} = \\dfrac{A\'B\'}{B\'C\'}$.' },
|
||
{ id:'paral', x:230, y:230, rx:52, label:'Прямая || стороне',
|
||
props:'§4: $MN \\parallel BC \\Rightarrow \\triangle AMN \\sim \\triangle ABC$ с $k = AM/AB$. Следует из теоремы Фалеса + признак УУ.' },
|
||
{ id:'biss', x:390, y:230, rx:52, label:'Биссектриса',
|
||
props:'§8: Биссектриса $AD$ треугольника $ABC$ делит сторону $BC$ в отношении: $\\dfrac{BD}{DC} = \\dfrac{AB}{AC}$. Доказывается через подобие.' },
|
||
{ id:'areas', x:540, y:230, rx:52, label:'Площади $S_1/S_2$',
|
||
props:'§9: Отношение площадей подобных треугольников равно квадрату коэффициента подобия: $\\dfrac{S_1}{S_2} = k^2$.' },
|
||
{ id:'div', x:150, y:310, rx:50, label:'Деление m:n',
|
||
props:'§2: Точка $C$ делит $AB$ в отношении $m:n$: $AC = \\dfrac{m}{m+n}\\cdot AB$, $CB = \\dfrac{n}{m+n}\\cdot AB$.' },
|
||
];
|
||
const edges = [
|
||
['sim','aa'],['sim','sas'],['sim','sss'],
|
||
['aa','paral'],['fales','paral'],['aa','biss'],
|
||
['sim','areas'],['paral','div'],
|
||
];
|
||
let sel = null;
|
||
function draw(selId){
|
||
const colors = { sim:'#7c3aed', aa:'#4f46e5', sas:'#8b5cf6', sss:'#6366f1', fales:'#2563eb', paral:'#0891b2', biss:'#c026d3', areas:'#059669', div:'#d97706' };
|
||
let s = `<svg viewBox="0 0 ${W} ${H}" style="width:100%;max-width:640px;background:var(--card);border:1.5px solid var(--border);border-radius:14px;cursor:pointer">`;
|
||
s += `<defs><marker id="f3-arr" markerWidth="7" markerHeight="7" refX="6" refY="3.5" orient="auto"><polygon points="0 0,7 3.5,0 7" fill="#94a3b8"/></marker></defs>`;
|
||
edges.forEach(([a,b])=>{
|
||
const na=nodes.find(n=>n.id===a), nb=nodes.find(n=>n.id===b);
|
||
if(!na||!nb) return;
|
||
const dx=nb.x-na.x, dy=nb.y-na.y, len=Math.sqrt(dx*dx+dy*dy);
|
||
if(len<1) return;
|
||
const sy_r=na.rx*0.52;
|
||
const sx=na.x+dx/len*na.rx, sy2=na.y+dy/len*sy_r;
|
||
const ex=nb.x-dx/len*(nb.rx+7), ey=nb.y-dy/len*(nb.rx*0.52+7);
|
||
const isAct = selId===a||selId===b;
|
||
s += `<line x1="${sx.toFixed(1)}" y1="${sy2.toFixed(1)}" x2="${ex.toFixed(1)}" y2="${ey.toFixed(1)}" stroke="${isAct?'#7c3aed':'#94a3b8'}" stroke-width="${isAct?2.5:1.5}" marker-end="url(#f3-arr)"/>`;
|
||
});
|
||
nodes.forEach(n=>{
|
||
const isS = selId===n.id;
|
||
const col = colors[n.id] || '#7c3aed';
|
||
const ry = n.rx * 0.52;
|
||
s += `<ellipse cx="${n.x}" cy="${n.y}" rx="${n.rx}" ry="${ry}" fill="${isS?col:'var(--card)'}" stroke="${col}" stroke-width="${isS?3:2}" data-nid="${n.id}" style="cursor:pointer"/>`;
|
||
const words = n.label.split(' ');
|
||
const line1 = words.slice(0,2).join(' '), line2 = words.slice(2).join(' ');
|
||
const tc = isS ? '#fff' : col;
|
||
if(line2){
|
||
s += `<text x="${n.x}" y="${n.y-5}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line1}</text>`;
|
||
s += `<text x="${n.x}" y="${n.y+7}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line2}</text>`;
|
||
} else {
|
||
s += `<text x="${n.x}" y="${n.y+4}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line1}</text>`;
|
||
}
|
||
});
|
||
s += '</svg>';
|
||
document.getElementById('final3-map-svg').innerHTML = s;
|
||
document.getElementById('final3-map-svg').querySelector('svg').addEventListener('click', function(e){
|
||
const el = e.target.closest('[data-nid]');
|
||
if(!el) return;
|
||
const nid = el.dataset.nid;
|
||
sel = (sel===nid) ? null : nid;
|
||
const nd = nodes.find(n=>n.id===nid);
|
||
if(sel && nd){ document.getElementById('final3-map-info').innerHTML = '<b>' + nd.label + '</b>: ' + nd.props; renderMath(document.getElementById('final3-map-info')); }
|
||
else document.getElementById('final3-map-info').textContent = 'Нажми на узел в схеме выше';
|
||
draw(sel);
|
||
});
|
||
}
|
||
draw(null);
|
||
})();
|
||
|
||
/* === JS: 7 боссов === */
|
||
(function(){
|
||
const bosses = [
|
||
{
|
||
n: 1,
|
||
title: 'Параллель и пропорция',
|
||
color: '#4f46e5',
|
||
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
|
||
<!-- Triangle A(140,12) B(20,170) C(260,170). MN parallel BC at 2/3 height. AM/AB=8/12=2/3: M on AB, N on AC. M=(140+2/3*(20-140), 12+2/3*(170-12))=(140-80,12+105.3)=(60,117) N=(140+2/3*(260-140),12+2/3*(170-12))=(140+80,117)=(220,117) -->
|
||
<polygon points="140,12 20,170 260,170" fill="rgba(79,70,229,.08)" stroke="#4f46e5" stroke-width="2"/>
|
||
<line x1="60" y1="117" x2="220" y2="117" stroke="#7c3aed" stroke-width="2.5"/>
|
||
<!-- tick marks: MN || BC -->
|
||
<line x1="136" y1="113" x2="144" y2="121" stroke="#7c3aed" stroke-width="1.8"/>
|
||
<line x1="136" y1="167" x2="144" y2="175" stroke="#4f46e5" stroke-width="1.8"/>
|
||
<!-- vertex dots -->
|
||
<circle cx="140" cy="12" r="4" fill="#4f46e5" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="20" cy="170" r="4" fill="#4f46e5" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="260" cy="170" r="4" fill="#4f46e5" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="60" cy="117" r="4" fill="#7c3aed" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="220" cy="117" r="4" fill="#7c3aed" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- labels -->
|
||
<text x="127" y="8" font-size="11" font-weight="700" fill="#3730a3" font-family="Unbounded,sans-serif">A</text>
|
||
<text x="4" y="180" font-size="11" font-weight="700" fill="#3730a3" font-family="Unbounded,sans-serif">B</text>
|
||
<text x="264" y="180" font-size="11" font-weight="700" fill="#3730a3" font-family="Unbounded,sans-serif">C</text>
|
||
<text x="42" y="113" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">M</text>
|
||
<text x="224" y="113" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">N</text>
|
||
<!-- side labels -->
|
||
<text x="72" y="68" font-size="9" fill="#3730a3" font-family="JetBrains Mono,monospace">AB=12</text>
|
||
<text x="4" y="148" font-size="9" fill="#3730a3" font-family="JetBrains Mono,monospace">AM=8</text>
|
||
<text x="190" y="150" font-size="9" fill="#3730a3" font-family="JetBrains Mono,monospace">AC=18</text>
|
||
<text x="116" y="108" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">MN=?</text>
|
||
</svg>`,
|
||
cond: 'В $\\triangle ABC$: $AB = 12$, $AC = 18$, $MN \\parallel BC$, $AM = 8$. (§1, §4)',
|
||
parts: [
|
||
{ label: 'Найди коэффициент подобия $k = AM/AB$.', ans: 0.667, tol: 0.005, hint: '$k = AM/AB = 8/12 = 2/3 \\approx 0{,}667$' },
|
||
{ label: 'Найди $AN$ (используй $AN/AC = k$).', ans: 12, hint: '$AN = k \\cdot AC = \\dfrac{2}{3} \\cdot 18 = 12$' },
|
||
],
|
||
},
|
||
{
|
||
n: 2,
|
||
title: 'Биссектриса треугольника',
|
||
color: '#c026d3',
|
||
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
|
||
<!-- Triangle A(140,12) B(20,170) C(260,170). AB=15, AC=10, BC=14. Bisector AD from A to BC. BD/DC=AB/AC=15/10=3/2. BD=14*3/5=8.4, DC=5.6. D on BC: D=(20+8.4/14*(260-20), 170)=(20+144, 170)=(164, 170) -->
|
||
<polygon points="140,12 20,170 260,170" fill="rgba(192,38,211,.08)" stroke="#c026d3" stroke-width="2"/>
|
||
<line x1="140" y1="12" x2="164" y2="170" stroke="#a21caf" stroke-width="2" stroke-dasharray="5 3"/>
|
||
<!-- vertex dots -->
|
||
<circle cx="140" cy="12" r="4" fill="#c026d3" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="20" cy="170" r="4" fill="#c026d3" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="260" cy="170" r="4" fill="#c026d3" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="164" cy="170" r="4" fill="#a21caf" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- labels -->
|
||
<text x="130" y="8" font-size="11" font-weight="700" fill="#86198f" font-family="Unbounded,sans-serif">A</text>
|
||
<text x="4" y="180" font-size="11" font-weight="700" fill="#86198f" font-family="Unbounded,sans-serif">B</text>
|
||
<text x="264" y="180" font-size="11" font-weight="700" fill="#86198f" font-family="Unbounded,sans-serif">C</text>
|
||
<text x="162" y="163" font-size="11" font-weight="700" fill="#86198f" font-family="Unbounded,sans-serif">D</text>
|
||
<!-- angle bisector arc mark at A -->
|
||
<path d="M126,30 A18,18 0 0,1 155,30" stroke="#c026d3" stroke-width="1.8" fill="rgba(192,38,211,.12)"/>
|
||
<!-- side labels -->
|
||
<text x="58" y="90" font-size="9" fill="#86198f" font-family="JetBrains Mono,monospace">AB=15</text>
|
||
<text x="186" y="90" font-size="9" fill="#86198f" font-family="JetBrains Mono,monospace">AC=10</text>
|
||
<text x="80" y="185" font-size="9" fill="#86198f" font-family="JetBrains Mono,monospace">BC=14</text>
|
||
<text x="148" y="155" font-size="9" fill="#86198f" font-family="JetBrains Mono,monospace">D=?</text>
|
||
</svg>`,
|
||
cond: 'В $\\triangle ABC$: $AB = 15$, $AC = 10$, $BC = 14$. $AD$ — биссектриса угла $A$. (§8)',
|
||
parts: [
|
||
{ label: 'Найди $BD$ (используй $BD/DC = AB/AC = 15/10$, $BD + DC = 14$).', ans: 8.4, tol: 0.05, hint: '$BD/DC = 3/2$, $BD = 14 \\cdot 3/5 = 8{,}4$' },
|
||
{ label: 'Найди $DC$.', ans: 5.6, tol: 0.05, hint: '$DC = 14 - BD = 14 - 8{,}4 = 5{,}6$' },
|
||
],
|
||
},
|
||
{
|
||
n: 3,
|
||
title: 'Признак по двум углам и площади',
|
||
color: '#059669',
|
||
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
|
||
<!-- Large triangle A(140,12) B(20,170) C(260,170), k=9/6=1.5. Small triangle A'(180,90) B'(130,170) C'(230,170) -->
|
||
<polygon points="140,12 20,170 260,170" fill="rgba(5,150,105,.08)" stroke="#059669" stroke-width="2"/>
|
||
<polygon points="180,90 130,170 230,170" fill="rgba(16,185,129,.18)" stroke="#10b981" stroke-width="2"/>
|
||
<!-- vertex dots large -->
|
||
<circle cx="140" cy="12" r="4" fill="#059669" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="20" cy="170" r="4" fill="#059669" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="260" cy="170" r="4" fill="#059669" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- vertex dots small -->
|
||
<circle cx="180" cy="90" r="3.5" fill="#10b981" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="130" cy="170" r="3.5" fill="#10b981" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="230" cy="170" r="3.5" fill="#10b981" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- labels large -->
|
||
<text x="128" y="8" font-size="11" font-weight="700" fill="#065f46" font-family="Unbounded,sans-serif">A</text>
|
||
<text x="4" y="180" font-size="11" font-weight="700" fill="#065f46" font-family="Unbounded,sans-serif">B</text>
|
||
<text x="264" y="180" font-size="11" font-weight="700" fill="#065f46" font-family="Unbounded,sans-serif">C</text>
|
||
<!-- labels small -->
|
||
<text x="184" y="88" font-size="9" font-weight="700" fill="#047857" font-family="Unbounded,sans-serif">A'</text>
|
||
<text x="116" y="180" font-size="9" font-weight="700" fill="#047857" font-family="Unbounded,sans-serif">B'</text>
|
||
<text x="232" y="180" font-size="9" font-weight="700" fill="#047857" font-family="Unbounded,sans-serif">C'</text>
|
||
<!-- side labels -->
|
||
<text x="55" y="85" font-size="9" fill="#065f46" font-family="JetBrains Mono,monospace">AB=6</text>
|
||
<text x="194" y="128" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">A'B'=9</text>
|
||
<text x="60" y="175" font-size="9" fill="#065f46" font-family="JetBrains Mono,monospace">S=12</text>
|
||
</svg>`,
|
||
cond: '$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по двум углам. $AB = 6$, $A\'B\' = 9$, $S_{\\triangle ABC} = 12$ см². (§5, §9)',
|
||
parts: [
|
||
{ label: 'Найди коэффициент подобия $k = A\'B\'/AB$.', ans: 1.5, tol: 0.01, hint: '$k = 9/6 = 1{,}5$' },
|
||
{ label: 'Найди $S_{\\triangle A\'B\'C\'}$ (используй $S\'/S = k^2$).', ans: 27, hint: '$S\' = k^2 \\cdot S = 2{,}25 \\cdot 12 = 27$ см²' },
|
||
],
|
||
},
|
||
{
|
||
n: 4,
|
||
title: 'Деление отрезка в отношении',
|
||
color: '#d97706',
|
||
svg: `<svg viewBox="0 0 280 120" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
|
||
<!-- Segment A(20,60) B(260,60). Total=240. m:n=3:2. AC=240*3/5=144. C=(20+144, 60)=(164, 60). -->
|
||
<line x1="20" y1="60" x2="260" y2="60" stroke="#d97706" stroke-width="2.5"/>
|
||
<circle cx="20" cy="60" r="5" fill="#d97706" stroke="#fff" stroke-width="2"/>
|
||
<circle cx="260" cy="60" r="5" fill="#d97706" stroke="#fff" stroke-width="2"/>
|
||
<circle cx="164" cy="60" r="5" fill="#b45309" stroke="#fff" stroke-width="2"/>
|
||
<!-- tick marks -->
|
||
<line x1="92" y1="50" x2="92" y2="70" stroke="#d97706" stroke-width="1.5"/>
|
||
<line x1="92" y1="50" x2="92" y2="70" stroke="#d97706" stroke-width="1.5"/>
|
||
<line x1="212" y1="50" x2="212" y2="70" stroke="#d97706" stroke-width="1.5"/>
|
||
<!-- brace AC label -->
|
||
<text x="20" y="44" font-size="11" font-weight="700" fill="#92400e" font-family="Unbounded,sans-serif">A</text>
|
||
<text x="158" y="44" font-size="11" font-weight="700" fill="#92400e" font-family="Unbounded,sans-serif">C</text>
|
||
<text x="254" y="44" font-size="11" font-weight="700" fill="#92400e" font-family="Unbounded,sans-serif">B</text>
|
||
<!-- distance labels -->
|
||
<text x="76" y="82" font-size="9" fill="#92400e" font-family="JetBrains Mono,monospace">AC=?</text>
|
||
<text x="185" y="82" font-size="9" fill="#92400e" font-family="JetBrains Mono,monospace">CB=?</text>
|
||
<!-- ratio label -->
|
||
<text x="78" y="100" text-anchor="middle" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">3</text>
|
||
<text x="208" y="100" text-anchor="middle" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">2</text>
|
||
<text x="140" y="30" text-anchor="middle" font-size="9" fill="#92400e" font-family="JetBrains Mono,monospace">AB = 20 см, AC:CB = 3:2</text>
|
||
</svg>`,
|
||
cond: 'Отрезок $AB = 20$ см. Точка $C$ делит $AB$ в отношении $AC{:}CB = 3{:}2$. (§2)',
|
||
parts: [
|
||
{ label: 'Найди $AC$ (см).', ans: 12, hint: '$AC = \\dfrac{3}{3+2} \\cdot 20 = 12$ см' },
|
||
{ label: 'Найди $CB$ (см).', ans: 8, hint: '$CB = \\dfrac{2}{5} \\cdot 20 = 8$ см' },
|
||
],
|
||
},
|
||
{
|
||
n: 5,
|
||
title: 'По двум сторонам и углу: стороны и косинус',
|
||
color: '#8b5cf6',
|
||
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
|
||
<!-- Triangle ABC: AB=8, AC=12, angle A=60deg. Large. A'B'C' similar with k=1.5: A'B'=12, A'C'=18. Triangle A(40,160) B(200,160) C=A+AC*cos60deg, A+AC*sin60deg = (40+12*0.5*12, 160-12*sin60*12)... scale: AB=8 -> 120px, so 1cm=15px. A(30,155) B(30+120,155)=(150,155). C=A+(AC*cos60*15, -AC*sin60*15)=(30+90, 155-156)=(120, 0)... too tall. Use AB=8->100px scale (12.5px/cm). A(30,155) B(30+100,155)=(130,155). C=(30+12*0.5*12.5, 155-12*sin60*12.5)=(30+75, 155-129.9)=(105,25). -->
|
||
<polygon points="30,155 130,155 105,25" fill="rgba(139,92,246,.08)" stroke="#8b5cf6" stroke-width="2"/>
|
||
<!-- angle at A: arc -->
|
||
<path d="M52,155 A22,22 0 0,1 44,131" stroke="#8b5cf6" stroke-width="1.8" fill="rgba(139,92,246,.15)"/>
|
||
<text x="56" y="148" font-size="9" fill="#6d28d9" font-weight="700" font-family="JetBrains Mono,monospace">60°</text>
|
||
<!-- vertex dots -->
|
||
<circle cx="30" cy="155" r="4" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="130" cy="155" r="4" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="105" cy="25" r="4" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- labels -->
|
||
<text x="16" y="151" font-size="11" font-weight="700" fill="#5b21b6" font-family="Unbounded,sans-serif">A</text>
|
||
<text x="134" y="168" font-size="11" font-weight="700" fill="#5b21b6" font-family="Unbounded,sans-serif">B</text>
|
||
<text x="94" y="18" font-size="11" font-weight="700" fill="#5b21b6" font-family="Unbounded,sans-serif">C</text>
|
||
<!-- side labels -->
|
||
<text x="72" y="172" text-anchor="middle" font-size="9" fill="#5b21b6" font-family="JetBrains Mono,monospace">AB=8</text>
|
||
<text x="62" y="92" font-size="9" fill="#5b21b6" font-family="JetBrains Mono,monospace">AC=12</text>
|
||
<!-- similar triangle labels -->
|
||
<text x="155" y="60" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">k=1.5</text>
|
||
<text x="155" y="75" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">A'B'=?</text>
|
||
<text x="155" y="90" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">A'C'=?</text>
|
||
<text x="155" y="105" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">B'C'=?</text>
|
||
</svg>`,
|
||
cond: '$\\triangle ABC \\sim \\triangle A\'B\'C\'$ (по двум сторонам и углу, СУС). $AB = 8$, $AC = 12$, $\\angle A = 60°$, $k = 1{,}5$. (§6)',
|
||
parts: [
|
||
{ label: 'Найди $A\'B\'$ (см).', ans: 12, hint: '$A\'B\' = k \\cdot AB = 1{,}5 \\cdot 8 = 12$' },
|
||
{ label: 'Найди $A\'C\'$ (см).', ans: 18, hint: '$A\'C\' = k \\cdot AC = 1{,}5 \\cdot 12 = 18$' },
|
||
{ label: 'Найди $BC$ по теореме косинусов: $BC^2 = AB^2+AC^2-2\\cdot AB\\cdot AC\\cdot\\cos60°$. Введи $BC$ (целое).', ans: 4, tol: 0.5, hint: '$BC^2 = 64+144-2\\cdot8\\cdot12\\cdot0{,}5 = 208-96=112$. Нет, пересчитаем: $BC^2=64+144-96=112 \\Rightarrow BC\\approx 10{,}58$. Округли до $11$.', _override: true, _ans_exact: 11, _tol_exact: 0.5, _hint_fix: 'По теореме косинусов: $BC^2 = 8^2+12^2-2\\cdot8\\cdot12\\cdot\\cos60° = 64+144-96=112$, $BC=\\sqrt{112}\\approx 10{,}58 \\approx 11$' },
|
||
],
|
||
},
|
||
{
|
||
n: 6,
|
||
title: 'Высоты и площади подобных',
|
||
color: '#0891b2',
|
||
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
|
||
<!-- Two similar triangles: large ABC (k=2 wrt small A'B'C') -->
|
||
<!-- Small A'B'C': A'(190,155) B'(130,155) C'(170,90). h'=65px -->
|
||
<!-- Large ABC: A(250,155) B(40,155) C(140,25). h=130px, k=2 -->
|
||
<polygon points="140,25 40,155 250,155" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="2"/>
|
||
<polygon points="170,90 130,155 210,155" fill="rgba(6,182,212,.20)" stroke="#06b6d4" stroke-width="1.8"/>
|
||
<!-- height of large -->
|
||
<line x1="140" y1="25" x2="140" y2="155" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||
<path d="M140,155 L140,147 L148,147" fill="none" stroke="#0891b2" stroke-width="1.5"/>
|
||
<!-- height of small -->
|
||
<line x1="170" y1="90" x2="170" y2="155" stroke="#06b6d4" stroke-width="1.5" stroke-dasharray="3 2"/>
|
||
<path d="M170,155 L170,149 L176,149" fill="none" stroke="#06b6d4" stroke-width="1.5"/>
|
||
<!-- vertex dots large -->
|
||
<circle cx="140" cy="25" r="4" fill="#0891b2" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="40" cy="155" r="4" fill="#0891b2" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="250" cy="155" r="4" fill="#0891b2" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- vertex dots small -->
|
||
<circle cx="170" cy="90" r="3.5" fill="#06b6d4" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="130" cy="155" r="3.5" fill="#06b6d4" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="210" cy="155" r="3.5" fill="#06b6d4" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- labels large -->
|
||
<text x="126" y="20" font-size="11" font-weight="700" fill="#164e63" font-family="Unbounded,sans-serif">A</text>
|
||
<text x="24" y="167" font-size="11" font-weight="700" fill="#164e63" font-family="Unbounded,sans-serif">B</text>
|
||
<text x="254" y="167" font-size="11" font-weight="700" fill="#164e63" font-family="Unbounded,sans-serif">C</text>
|
||
<!-- labels small -->
|
||
<text x="174" y="88" font-size="9" font-weight="700" fill="#0e7490" font-family="Unbounded,sans-serif">A'</text>
|
||
<text x="116" y="166" font-size="9" font-weight="700" fill="#0e7490" font-family="Unbounded,sans-serif">B'</text>
|
||
<text x="212" y="166" font-size="9" font-weight="700" fill="#0e7490" font-family="Unbounded,sans-serif">C'</text>
|
||
<!-- height labels -->
|
||
<text x="144" y="88" font-size="9" fill="#164e63" font-family="JetBrains Mono,monospace">h=6</text>
|
||
<text x="174" y="128" font-size="9" fill="#0e7490" font-family="JetBrains Mono,monospace">h'=?</text>
|
||
<text x="4" y="130" font-size="9" fill="#0e7490" font-family="JetBrains Mono,monospace">S'=9</text>
|
||
<text x="4" y="144" font-size="9" fill="#164e63" font-family="JetBrains Mono,monospace">S=?</text>
|
||
<text x="4" y="158" font-size="9" fill="#164e63" font-family="JetBrains Mono,monospace">k=2</text>
|
||
</svg>`,
|
||
cond: '$\\triangle ABC \\sim \\triangle A\'B\'C\'$ с коэффициентом $k = 2$ (большой к малому). Высота $h_{ABC} = 6$ см, $S_{A\'B\'C\'} = 9$ см². (§9)',
|
||
parts: [
|
||
{ label: 'Найди $h\'$ (высоту малого треугольника).', ans: 3, hint: '$h\' = h/k = 6/2 = 3$ см (высоты подобных ~ $k$)' },
|
||
{ label: 'Найди $S_{ABC}$ (площадь большего треугольника).', ans: 36, hint: '$S/S\' = k^2 = 4 \\Rightarrow S = 4 \\cdot 9 = 36$ см²' },
|
||
],
|
||
},
|
||
{
|
||
n: 7,
|
||
title: 'Средняя линия и площади',
|
||
color: '#16a34a',
|
||
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
|
||
<!-- Triangle ABC: AB=14, BC=21. M midpoint AB. MN||BC, N on AC. k=AM/AB=1/2. MN=BC/2=10.5. A(140,12) B(20,170) C(260,170). M=midpoint(A,B)=(80,91). N=midpoint(A,C)=(200,91). -->
|
||
<polygon points="140,12 20,170 260,170" fill="rgba(22,163,74,.08)" stroke="#16a34a" stroke-width="2"/>
|
||
<line x1="80" y1="91" x2="200" y2="91" stroke="#15803d" stroke-width="2.5"/>
|
||
<!-- vertex dots -->
|
||
<circle cx="140" cy="12" r="4" fill="#16a34a" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="20" cy="170" r="4" fill="#16a34a" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="260" cy="170" r="4" fill="#16a34a" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="80" cy="91" r="4" fill="#15803d" stroke="#fff" stroke-width="1.5"/>
|
||
<circle cx="200" cy="91" r="4" fill="#15803d" stroke="#fff" stroke-width="1.5"/>
|
||
<!-- tick marks M midpoint -->
|
||
<line x1="108" y1="48" x2="116" y2="56" stroke="#16a34a" stroke-width="1.8"/>
|
||
<line x1="37" y1="126" x2="45" y2="134" stroke="#16a34a" stroke-width="1.8"/>
|
||
<!-- labels -->
|
||
<text x="128" y="8" font-size="11" font-weight="700" fill="#14532d" font-family="Unbounded,sans-serif">A</text>
|
||
<text x="4" y="180" font-size="11" font-weight="700" fill="#14532d" font-family="Unbounded,sans-serif">B</text>
|
||
<text x="264" y="180" font-size="11" font-weight="700" fill="#14532d" font-family="Unbounded,sans-serif">C</text>
|
||
<text x="60" y="88" font-size="11" font-weight="700" fill="#14532d" font-family="Unbounded,sans-serif">M</text>
|
||
<text x="204" y="88" font-size="11" font-weight="700" fill="#14532d" font-family="Unbounded,sans-serif">N</text>
|
||
<!-- side labels -->
|
||
<text x="48" y="126" font-size="9" fill="#14532d" font-family="JetBrains Mono,monospace">AB=14</text>
|
||
<text x="108" y="185" font-size="9" fill="#14532d" font-family="JetBrains Mono,monospace">BC=21</text>
|
||
<text x="110" y="82" font-size="9" fill="#14532d" font-family="JetBrains Mono,monospace">MN=?</text>
|
||
</svg>`,
|
||
cond: 'В $\\triangle ABC$: $AB = 14$, $BC = 21$. $M$ — середина $AB$, $N$ на $AC$ так, что $MN \\parallel BC$. (§4, §9)',
|
||
parts: [
|
||
{ label: 'Найди $MN$ (используй $k = AM/AB = 1/2$, $MN = k \\cdot BC$).', ans: 10.5, tol: 0.05, hint: '$k = 7/14 = 1/2$, $MN = 1/2 \\cdot 21 = 10{,}5$ см' },
|
||
{ label: 'Найди $AN/NC$ (какое оно?).', ans: 1, hint: '$M$ — середина $AB \\Rightarrow k = 1/2 \\Rightarrow AN/NC = AM/MB = 1/1$, т.е. $N$ — середина $AC$' },
|
||
{ label: 'Найди отношение $S_{\\triangle AMN}/S_{\\triangle ABC}$ (введи как десятичную дробь).', ans: 0.25, tol: 0.01, hint: '$S_{AMN}/S_{ABC} = k^2 = (1/2)^2 = 0{,}25$' },
|
||
],
|
||
},
|
||
];
|
||
|
||
window.final3BossSolved = new Set();
|
||
const bossBox = document.getElementById('final3-bosses');
|
||
bossBox.innerHTML = bosses.map(b => {
|
||
const partsHtml = b.parts.map((p,pi) => {
|
||
return `<div style="padding:10px 0;border-top:1px dashed var(--border)">
|
||
<div style="font-size:.9rem;margin-bottom:7px">${p.label}</div>
|
||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||
<input type="number" step="any" class="tinp final3-boss-inp" data-b="${b.n-1}" data-p="${pi}" placeholder="Ответ" style="width:120px">
|
||
<button class="btn primary final3-boss-check" data-b="${b.n-1}" data-p="${pi}" style="background:${b.color};border-color:${b.color}">Проверить</button>
|
||
<span class="final3-boss-ok" data-b="${b.n-1}" data-p="${pi}" style="display:none;color:var(--ok);font-weight:700">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" style="width:16px;height:16px;vertical-align:middle"><polyline points="20 6 9 17 4 12"/></svg>
|
||
</span>
|
||
</div>
|
||
<div class="feedback final3-boss-fb" data-b="${b.n-1}" data-p="${pi}" style="display:none;margin-top:6px"></div>
|
||
</div>`;
|
||
}).join('');
|
||
|
||
const svgHtml = b.svg ? `<div style="display:flex;justify-content:center;margin:10px 0">${b.svg}</div>` : '';
|
||
|
||
return `<div style="padding:16px;background:var(--card);border-radius:12px;border:2px solid ${b.color};margin-bottom:14px" id="final3-boss-card-${b.n-1}">
|
||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap">
|
||
<span style="background:${b.color};color:#fff;padding:4px 10px;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.7rem;font-weight:800">БОСС ${b.n}</span>
|
||
<span style="font-family:'Unbounded',sans-serif;font-size:.88rem;font-weight:800;color:${b.color}">${b.title}</span>
|
||
<span id="final3-boss-xp-${b.n-1}" style="margin-left:auto;display:none;background:var(--ok-bg);color:#065f46;padding:3px 10px;border-radius:99px;font-size:.78rem;font-weight:800">+10 XP</span>
|
||
</div>
|
||
<div style="padding:10px 14px;background:linear-gradient(135deg,#ede9fe,#fff);border-left:4px solid ${b.color};border-radius:9px;font-size:.92rem;line-height:1.6;margin-bottom:4px">${b.cond}</div>
|
||
${svgHtml}
|
||
${partsHtml}
|
||
</div>`;
|
||
}).join('');
|
||
|
||
function checkPart(bi, pi){
|
||
const boss = bosses[bi];
|
||
const part = boss.parts[pi];
|
||
const inp = bossBox.querySelector(`.final3-boss-inp[data-b="${bi}"][data-p="${pi}"]`);
|
||
const fb = bossBox.querySelector(`.final3-boss-fb[data-b="${bi}"][data-p="${pi}"]`);
|
||
const ok = bossBox.querySelector(`.final3-boss-ok[data-b="${bi}"][data-p="${pi}"]`);
|
||
if(!inp) return;
|
||
const val = parseFloat(inp.value);
|
||
const useExact = part._override && part._ans_exact !== undefined;
|
||
const ansCheck = useExact ? part._ans_exact : part.ans;
|
||
const tolCheck = useExact ? part._tol_exact : (part.tol !== undefined ? part.tol : 0);
|
||
const hintText = useExact ? part._hint_fix : part.hint;
|
||
if(Math.abs(val - ansCheck) <= tolCheck){
|
||
feedback(fb, true, 'Верно! ' + (hintText ? '<br><span style="font-size:.82rem;opacity:.85">' + hintText + '</span>' : ''));
|
||
inp.disabled = true;
|
||
const btn = bossBox.querySelector(`.final3-boss-check[data-b="${bi}"][data-p="${pi}"]`);
|
||
if(btn) btn.disabled = true;
|
||
if(ok) ok.style.display = 'inline';
|
||
const allDone = boss.parts.every((_,pj) => {
|
||
const el = bossBox.querySelector(`.final3-boss-inp[data-b="${bi}"][data-p="${pj}"]`);
|
||
return el && el.disabled;
|
||
});
|
||
if(allDone && !window.final3BossSolved.has(bi)){
|
||
window.final3BossSolved.add(bi);
|
||
addXp(10, 'final3-boss-' + (bi+1));
|
||
const xpBadge = document.getElementById('final3-boss-xp-' + bi);
|
||
if(xpBadge) xpBadge.style.display = 'inline';
|
||
bumpProgress('final3', 8);
|
||
if(window.final3BossSolved.size === bosses.length){
|
||
setTimeout(()=>{
|
||
confetti();
|
||
if(!STATE.achievements.has('final3-master')){
|
||
STATE.achievements.set('final3-master', 'Мастер подобия Главы 3');
|
||
saveProgress();
|
||
const pop = document.getElementById('ach-popup');
|
||
if(pop){ document.getElementById('ach-text').textContent = 'Мастер подобия Главы 3!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'), 4000); }
|
||
}
|
||
addXp(50, 'final3-all-bosses');
|
||
bumpProgress('final3', 20);
|
||
const fin = document.getElementById('final3-finish');
|
||
if(fin) fin.style.display = 'block';
|
||
}, 500);
|
||
}
|
||
}
|
||
} else {
|
||
feedback(fb, false, 'Неверно. Подсказка: ' + (hintText || part.hint));
|
||
}
|
||
}
|
||
|
||
bossBox.querySelectorAll('.final3-boss-check').forEach(btn=>{
|
||
btn.addEventListener('click', ()=>{ checkPart(+btn.dataset.b, +btn.dataset.p); });
|
||
});
|
||
bossBox.querySelectorAll('.final3-boss-inp').forEach(inp=>{
|
||
inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ const btn=bossBox.querySelector(`.final3-boss-check[data-b="${inp.dataset.b}"][data-p="${inp.dataset.p}"]`); if(btn)btn.click(); } });
|
||
});
|
||
})();
|
||
|
||
renderMath(box);
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|