训练一下条件独立的直觉(为什么本站支持上传 zip, exe, apk, mp4, msi, deb, rpm 却不支持上传 html)

为什么本站支持上传 zip, exe, apk, mp4, msi, deb, rpm 却不支持上传 html

Sorry, the file you are trying to upload is not authorized (authorized extensions: jpg, jpeg, png, gif, heic, heif, webp, avif, pdf, docx, xlsx, pptx, doc, xls, ppt, py, cs, cpp, c, rs, h, m, 7z, gz, xz, zstd, rar, zip, txt, zst, apk, mp4, mkv, webm, mp3, flac, wav, weba, psd, csv, xcf, db, exe, msi, appimage, deb, rpm).

复制以下内容,存储为 html 格式文件

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>d-分离 (d-Separation) 练习</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            background-color: #f4f7f9;
            color: #333;
            line-height: 1.6;
            display: flex;
            justify-content: center;
            padding: 20px;
        }
        .container {
            max-width: 800px;
            width: 100%;
            background-color: #fff;
            padding: 20px 30px;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
        }
        h1, h2 {
            text-align: center;
            color: #0056b3;
        }
        .introduction {
            background-color: #e7f3ff;
            border-left: 5px solid #0056b3;
            padding: 15px;
            margin: 20px 0;
            border-radius: 5px;
        }
        #quiz-area {
            margin-top: 20px;
        }
        #graph-container {
            text-align: center;
            margin-bottom: 20px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 8px;
            background-color: #fafafa;
            min-height: 250px;
        }
        #graph-svg {
            max-width: 100%;
            height: auto;
        }
        #question {
            font-size: 1.3em;
            font-weight: bold;
            text-align: center;
            margin-bottom: 25px;
        }
        .answer-buttons {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-bottom: 20px;
        }
        .btn {
            padding: 12px 25px;
            font-size: 1em;
            cursor: pointer;
            border: none;
            border-radius: 5px;
            color: white;
            transition: background-color 0.3s, transform 0.1s;
        }
        .btn:hover {
            opacity: 0.9;
            transform: translateY(-2px);
        }
        .btn:disabled {
            cursor: not-allowed;
            opacity: 0.6;
        }
        #yes-btn { background-color: #28a745; }
        #no-btn { background-color: #dc3545; }
        #next-btn {
            display: block;
            margin: 20px auto 0;
            background-color: #007bff;
            display: none;
        }
        #feedback {
            padding: 15px;
            border-radius: 5px;
            margin-top: 20px;
            display: none;
        }
        #feedback.correct {
            background-color: #d4edda;
            border: 1px solid #c3e6cb;
            color: #155724;
        }
        #feedback.incorrect {
            background-color: #f8d7da;
            border: 1px solid #f5c6cb;
            color: #721c24;
        }
        #progress {
            text-align: center;
            font-size: 0.9em;
            color: #666;
            margin-top: 10px;
        }
        .explanation {
            margin-top: 10px;
            font-size: 0.95em;
            text-align: left;
        }
        .explanation ul {
            padding-left: 20px;
        }
        .explanation strong {
            color: #0056b3;
        }
        #final-score {
            text-align: center;
            font-size: 1.5em;
            padding: 40px 20px;
        }
    </style>
</head>
<body>

<div class="container">
    <h1>d-分离 (d-Separation) 练习</h1>
    <div class="introduction">
        <p><strong>欢迎来到 d-分离练习!</strong></p>
        <p>d-分离是判断贝叶斯网络中变量是否条件独立的重要工具。请根据下图和问题,判断两个节点集是否在给定条件下 d-分离(条件独立)。</p>
        <ul>
            <li><strong>d-分离 (d-separated)</strong>: 两个节点之间所有的路径都被**阻断 (blocked)**。</li>
            <li><strong>d-连接 (d-connected)</strong>: 两个节点之间至少存在一条**未被阻断 (unblocked)** 的路径。</li>
        </ul>
    </div>

    <div id="quiz-area">
        <div id="progress"></div>
        <div id="graph-container">
            <svg id="graph-svg" width="600" height="250" viewBox="0 0 600 250"></svg>
        </div>
        <p id="question"></p>
        <div class="answer-buttons">
            <button class="btn" id="yes-btn">是 (d-分离)</button>
            <button class="btn" id="no-btn">否 (d-连接)</button>
        </div>
        <div id="feedback"></div>
        <button class="btn" id="next-btn">下一题</button>
    </div>
    <div id="final-score" style="display: none;"></div>
</div>

<script>
const questions = [
    // --- 基本规则 ---
    { // 1. 链式结构:被观察
        graph: { nodes: [{id:'A', x:100, y:125}, {id:'B', x:300, y:125}, {id:'C', x:500, y:125}], edges: [{from:'A', to:'B'}, {from:'B', to:'C'}] },
        query: { X: 'A', Y: 'C', Z: ['B'] },
        answer: 'yes',
        explanation: `路径 A → B → C 是一条链式结构。因为中间节点 B 在条件集 Z 中(被观察),所以该路径被阻断。这是图中唯一的路径,因此 A 和 C 在给定 B 的条件下是 d-分离的。`
    },
    { // 2. 链式结构:未被观察
        graph: { nodes: [{id:'A', x:100, y:125}, {id:'B', x:300, y:125}, {id:'C', x:500, y:125}], edges: [{from:'A', to:'B'}, {from:'B', to:'C'}] },
        query: { X: 'A', Y: 'C', Z: [] },
        answer: 'no',
        explanation: `路径 A → B → C 是一条链式结构。因为中间节点 B 不在条件集 Z 中(未被观察),所以该路径是连通的。因此 A 和 C 在给定空集的条件下是 d-连接的。`
    },
    { // 3. 分叉结构:被观察
        graph: { nodes: [{id:'A', x:100, y:125}, {id:'B', x:300, y:50}, {id:'C', x:500, y:125}], edges: [{from:'B', to:'A'}, {from:'B', to:'C'}] },
        query: { X: 'A', Y: 'C', Z: ['B'] },
        answer: 'yes',
        explanation: `路径 A ← B → C 是一条分叉结构。因为共同原因 B 在条件集 Z 中(被观察),所以该路径被阻断。这是唯一的路径,因此 A 和 C 在给定 B 的条件下是 d-分离的。`
    },
    { // 4. 分叉结构:未被观察
        graph: { nodes: [{id:'A', x:100, y:125}, {id:'B', x:300, y:50}, {id:'C', x:500, y:125}], edges: [{from:'B', to:'A'}, {from:'B', to:'C'}] },
        query: { X: 'A', Y: 'C', Z: [] },
        answer: 'no',
        explanation: `路径 A ← B → C 是一条分叉结构。因为共同原因 B 不在条件集 Z 中(未被观察),所以该路径是连通的。因此 A 和 C 在给定空集的条件下是 d-连接的。`
    },
    { // 5. 对撞结构:未被观察
        graph: { nodes: [{id:'A', x:100, y:50}, {id:'B', x:300, y:125}, {id:'C', x:500, y:50}], edges: [{from:'A', to:'B'}, {from:'C', to:'B'}] },
        query: { X: 'A', Y: 'C', Z: [] },
        answer: 'yes',
        explanation: `路径 A → B ← C 是一条对撞结构。因为对撞节点 B 及其后代都不在条件集 Z 中,所以该路径默认被阻断。这是唯一的路径,因此 A 和 C 在给定空集的条件下是 d-分离的。`
    },
    { // 6. 对撞结构:被观察
        graph: { nodes: [{id:'A', x:100, y:50}, {id:'B', x:300, y:125}, {id:'C', x:500, y:50}], edges: [{from:'A', to:'B'}, {from:'C', to:'B'}] },
        query: { X: 'A', Y: 'C', Z: ['B'] },
        answer: 'no',
        explanation: `路径 A → B ← C 是一条对撞结构。因为对撞节点 B 在条件集 Z 中(被观察),所以该路径被打开(连通)。这被称为“解释消除效应”。因此 A 和 C 在给定 B 的条件下是 d-连接的。`
    },
    { // 7. 对撞结构:后代被观察
        graph: { nodes: [{id:'A', x:100, y:50}, {id:'B', x:300, y:50}, {id:'C', x:500, y:50}, {id:'D', x:300, y:200}], edges: [{from:'A', to:'B'}, {from:'C', to:'B'}, {from:'B', to:'D'}] },
        query: { X: 'A', Y: 'C', Z: ['D'] },
        answer: 'no',
        explanation: `路径 A → B ← C 是一条对撞结构。虽然对撞节点 B 不在条件集 Z 中,但它的后代 D 在 Z 中。观察对撞节点的后代同样会打开这条路径。因此 A 和 C 在给定 D 的条件下是 d-连接的。`
    },
    // --- 组合情况 ---
    { // 8. 链 + 对撞
        graph: { nodes: [{id:'A', x:50, y:125}, {id:'B', x:200, y:125}, {id:'C', x:350, y:50}, {id:'D', x:500, y:125}], edges: [{from:'A', to:'B'}, {from:'C', to:'B'}, {from:'C', to:'D'}] },
        query: { X: 'A', Y: 'D', Z: ['C'] },
        answer: 'yes',
        explanation: `存在唯一路径 A → B ← C → D。我们逐段分析:
        <ul>
            <li>在 B 节点:A → B ← C 是一个对撞结构。由于对撞节点 B 未被观察,这条路径在 B 处被阻断。</li>
            <li>在 C 节点:B ← C → D 是一个分叉结构。由于分叉点 C 被观察,这条路径在 C 处也被阻断。</li>
        </ul>
        因为这条路径上至少有一个点(实际上是两个点)阻断了信息流,所以 A 和 D 在给定 C 的条件下是 d-分离的。`
    },
    { // 9. 同上,但观察 B
        graph: { nodes: [{id:'A', x:50, y:125}, {id:'B', x:200, y:125}, {id:'C', x:350, y:50}, {id:'D', x:500, y:125}], edges: [{from:'A', to:'B'}, {from:'C', to:'B'}, {from:'C', to:'D'}] },
        query: { X: 'A', Y: 'D', Z: ['B'] },
        answer: 'no',
        explanation: `存在唯一路径 A → B ← C → D。我们分析这条路径:
        <ul>
            <li>在 B 节点:A → B ← C 是一个对撞结构。由于对撞节点 B 被观察,这条路径在 B 处被打开(连通)。</li>
            <li>在 C 节点:B ← C → D 是一个分叉结构。分叉点 C 未被观察,所以路径在 C 处也是连通的。</li>
        </ul>
        因为整条路径上没有被阻断的点,所以 A 和 D 在给定 B 的条件下是 d-连接的。`
    },
    { // 10. M 型图
        graph: { nodes: [{id:'A', x:150, y:50}, {id:'B', x:450, y:50}, {id:'C', x:150, y:200}, {id:'D', x:450, y:200}], edges: [{from:'A', to:'C'}, {from:'A', to:'D'}, {from:'B', to:'C'}, {from:'B', to:'D'}] },
        query: { X: 'A', Y: 'B', Z: ['C'] },
        answer: 'no',
        explanation: `这里有两条路径连接 A 和 B:
        <ul>
            <li>路径 1: A → D ← B。这是一个对撞结构。对撞节点 D 未被观察,所以此路径被<strong>阻断</strong>。</li>
            <li>路径 2: A → C ← B。这是一个对撞结构。对撞节点 C 在条件集 Z 中被观察,所以此路径被<strong>打开(连通)</strong>。</li>
        </ul>
        因为存在至少一条连通的路径(路径 2),所以 A 和 B 在给定 C 的条件下是 d-连接的。`
    },
    { // 11. M 型图,观察两个
        graph: { nodes: [{id:'A', x:150, y:50}, {id:'B', x:450, y:50}, {id:'C', x:150, y:200}, {id:'D', x:450, y:200}], edges: [{from:'A', to:'C'}, {from:'A', to:'D'}, {from:'B', to:'C'}, {from:'B', to:'D'}] },
        query: { X: 'A', Y: 'B', Z: ['C', 'D'] },
        answer: 'no',
        explanation: `这里有两条路径连接 A 和 B:
        <ul>
            <li>路径 1: A → D ← B。对撞结构。对撞节点 D 被观察,路径<strong>打开(连通)</strong>。</li>
            <li>路径 2: A → C ← B。对撞结构。对撞节点 C 被观察,路径<strong>打开(连通)</strong>。</li>
        </ul>
        因为两条路径都由于观察了对撞节点而打开,所以 A 和 B 在给定 C 和 D 的条件下是 d-连接的。`
    },
    { // 12. 复杂图 1
        graph: { nodes: [{id:'A',x:50,y:125},{id:'B',x:200,y:50},{id:'C',x:200,y:200},{id:'D',x:350,y:125},{id:'E',x:500,y:125}], edges: [{from:'A',to:'B'},{from:'A',to:'C'},{from:'B',to:'D'},{from:'C',to:'D'},{from:'D',to:'E'}] },
        query: { X: 'A', Y: 'E', Z: ['D'] },
        answer: 'yes',
        explanation: `要判断 A 和 E 是否 d-分离,我们需要检查所有从 A 到 E 的路径。所有路径都必须经过 D。
        <ul>
            <li>路径 1: A → B → D → E。这是一条链式结构。中间节点 D 被观察,所以路径在 D 处被<strong>阻断</strong>。</li>
            <li>路径 2: A → C → D → E。这也是一条链式结构。中间节点 D 被观察,所以路径在 D 处被<strong>阻断</strong>。</li>
        </ul>
        因为所有从 A 到 E 的路径都被 D 阻断,所以 A 和 E 在给定 D 的条件下是 d-分离的。`
    },
    { // 13. 复杂图 1, 观察 A
        graph: { nodes: [{id:'A',x:50,y:125},{id:'B',x:200,y:50},{id:'C',x:200,y:200},{id:'D',x:350,y:125},{id:'E',x:500,y:125}], edges: [{from:'A',to:'B'},{from:'A',to:'C'},{from:'B',to:'D'},{from:'C',to:'D'},{from:'D',to:'E'}] },
        query: { X: 'B', Y: 'C', Z: ['A'] },
        answer: 'yes',
        explanation: `这里有两条路径连接 B 和 C:
        <ul>
            <li>路径 1: B ← A → C。这是一个分叉结构。分叉点 A 在条件集 Z 中被观察,所以此路径被<strong>阻断</strong>。</li>
            <li>路径 2: B → D ← C。这是一个对撞结构。对撞节点 D 及其后代 E 都未被观察,所以此路径被<strong>阻断</strong>。</li>
        </ul>
        因为所有路径都被阻断,所以 B 和 C 在给定 A 的条件下是 d-分离的。`
    },
    { // 14. 复杂图 1, 观察 D
        graph: { nodes: [{id:'A',x:50,y:125},{id:'B',x:200,y:50},{id:'C',x:200,y:200},{id:'D',x:350,y:125},{id:'E',x:500,y:125}], edges: [{from:'A',to:'B'},{from:'A',to:'C'},{from:'B',to:'D'},{from:'C',to:'D'},{from:'D',to:'E'}] },
        query: { X: 'B', Y: 'C', Z: ['D'] },
        answer: 'no',
        explanation: `这里有两条路径连接 B 和 C:
        <ul>
            <li>路径 1: B ← A → C。这是一个分叉结构。分叉点 A 未被观察,所以此路径是<strong>连通的</strong>。</li>
            <li>路径 2: B → D ← C。这是一个对撞结构。对撞节点 D 被观察,所以此路径也被<strong>打开(连通)</strong>。</li>
        </ul>
        因为存在连通路径(实际上两条都连通),所以 B 和 C 在给定 D 的条件下是 d-连接的。`
    },
    { // 15. 经典诱导依赖图
        graph: { nodes: [{id:'Rain',x:150,y:50},{id:'Sprinkler',x:450,y:50},{id:'Grass Wet',x:300,y:150}], edges: [{from:'Rain',to:'Grass Wet'},{from:'Sprinkler',to:'Grass Wet'}] },
        query: { X: 'Rain', Y: 'Sprinkler', Z: [] },
        answer: 'yes',
        explanation: `路径 Rain → Grass Wet ← Sprinkler 是一个对撞结构。因为对撞节点 Grass Wet 及其后代(无)都未被观察,所以路径被阻断。因此,在不知道草地是否湿润的情况下,下雨和洒水器是独立的(d-分离)。`
    },
    { // 16. 经典诱导依赖图,观察结果
        graph: { nodes: [{id:'Rain',x:150,y:50},{id:'Sprinkler',x:450,y:50},{id:'Grass Wet',x:300,y:150}], edges: [{from:'Rain',to:'Grass Wet'},{from:'Sprinkler',to:'Grass Wet'}] },
        query: { X: 'Rain', Y: 'Sprinkler', Z: ['Grass Wet'] },
        answer: 'no',
        explanation: `路径 Rain → Grass Wet ← Sprinkler 是一个对撞结构。因为对撞节点 Grass Wet 被观察了,所以路径被打开(连通)。这意味着,如果我们观察到草地是湿的,那么下雨和洒水器就变得相关了(例如,如果没下雨,那很可能是洒水器开了)。因此它们是 d-连接的。`
    },
    { // 17. 更长的链
        graph: { nodes: [{id:'A',x:50,y:125},{id:'B',x:180,y:125},{id:'C',x:310,y:125},{id:'D',x:440,y:125},{id:'E',x:570,y:125}], edges: [{from:'A',to:'B'},{from:'B',to:'C'},{from:'C',to:'D'},{from:'D',to:'E'}] },
        query: { X: 'A', Y: 'E', Z: ['C'] },
        answer: 'yes',
        explanation: `唯一的路径是 A → B → C → D → E。这是一个链式结构。因为中间节点 C 在条件集 Z 中被观察,所以信息流在 C 点被阻断。因此,A 和 E 在给定 C 的条件下是 d-分离的。`
    },
    { // 18. 对撞与分叉混合
        graph: { nodes: [{id:'A',x:50, y:125}, {id:'B',x:200, y:125}, {id:'C',x:350, y:50}, {id:'D',x:350, y:200}, {id:'E', x:500, y:125}], edges: [{from:'A', to:'B'}, {from:'B',to:'C'}, {from:'B',to:'D'}, {from:'C',to:'E'}, {from:'D',to:'E'}] },
        query: { X: 'A', Y: 'E', Z: [] },
        answer: 'no',
        explanation: `我们检查从 A 到 E 的所有路径,给定 Z=∅。
        <ul>
            <li>路径 1: A → B → C → E。路径上的 B 和 C 都是链式节点,且都未被观察。路径<strong>连通</strong>。</li>
            <li>路径 2: A → B → D → E。路径上的 B 和 D 都是链式节点,且都未被观察。路径<strong>连通</strong>。</li>
        </ul>
        因为存在连通路径,所以 A 和 E 在给定空集的条件下是 d-连接的。注意,C→E←D 中的 E 是对撞节点,但它不是 A 到 E 路径上的中间节点,不影响判断。`
    },
    { // 19. 钻石图
        graph: { nodes: [{id:'A',x:100,y:125},{id:'B',x:250,y:50},{id:'C',x:400,y:125},{id:'D',x:250,y:200}], edges: [{from:'A',to:'B'},{from:'B',to:'C'},{from:'A',to:'D'},{from:'D',to:'C'}] },
        query: { X: 'B', Y: 'D', Z: ['A', 'C'] },
        answer: 'no',
        explanation: `这里有两条路径连接 B 和 D:
        <ul>
            <li>路径 1: B ← A → D。这是一个分叉结构。分叉点 A 在 Z 中被观察,所以此路径被<strong>阻断</strong>。</li>
            <li>路径 2: B → C ← D。这是一个对撞结构。对撞点 C 在 Z 中被观察,所以此路径被<strong>打开(连通)</strong>。</li>
        </ul>
        因为存在一条连通的路径(路径 2),所以 B 和 D 在给定 A 和 C 的条件下是 d-连接的。`
    },
    { // 20. 钻石图 (最终版)
        graph: { nodes: [{id:'A',x:100,y:125},{id:'B',x:250,y:50},{id:'C',x:400,y:125},{id:'D',x:250,y:200}], edges: [{from:'A',to:'B'},{from:'B',to:'C'},{from:'A',to:'D'},{from:'D',to:'C'}] },
        query: { X: 'B', Y: 'D', Z: ['A'] },
        answer: 'yes',
        explanation: `这里有两条路径连接 B 和 D:
        <ul>
            <li>路径 1: B ← A → D。这是一个分叉结构。因为分叉点 A 在条件集 Z 中(被观察),所以此路径被 <strong>阻断</strong>。</li>
            <li>路径 2: B → C ← D。这是一个对撞结构。因为对撞点 C 及其后代(无)都不在条件集 Z 中,所以此路径被 <strong>阻断</strong>。</li>
        </ul>
        因为所有从 B 到 D 的路径都被阻断了,所以 B 和 D 在给定 A 的条件下是 d-分离的。`
    }
];

const quizArea = document.getElementById('quiz-area');
const finalScoreDiv = document.getElementById('final-score');
const progressEl = document.getElementById('progress');
const questionEl = document.getElementById('question');
const svgEl = document.getElementById('graph-svg');
const feedbackEl = document.getElementById('feedback');
const yesBtn = document.getElementById('yes-btn');
const noBtn = document.getElementById('no-btn');
const nextBtn = document.getElementById('next-btn');

let currentQuestionIndex = 0;
let score = 0;
const NODE_RADIUS = 25; // Define node radius as a constant

function loadQuestion() {
    if (currentQuestionIndex >= questions.length) {
        showFinalScore();
        return;
    }

    const currentQuestion = questions[currentQuestionIndex];
    const { graph, query } = currentQuestion;

    feedbackEl.style.display = 'none';
    feedbackEl.className = '';
    nextBtn.style.display = 'none';
    yesBtn.disabled = false;
    noBtn.disabled = false;

    progressEl.textContent = `问题 ${currentQuestionIndex + 1} / ${questions.length}`;

    let z_str = query.Z.length > 0 ? `{${query.Z.join(', ')}}` : '∅ (空集)';
    questionEl.innerHTML = `在下图中,给定条件集 Z = ${z_str},请问节点 <strong>${query.X}</strong> 和 <strong>${query.Y}</strong> 是否 d-分离?`;

    drawGraph(graph, query);
}

function drawGraph(graph, query) {
    svgEl.innerHTML = '';

    const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
    const marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
    marker.setAttribute('id', 'arrow');
    marker.setAttribute('viewBox', '0 -5 10 10');
    marker.setAttribute('refX', '10'); // Point of the arrow
    marker.setAttribute('refY', '0');
    marker.setAttribute('markerWidth', '6');
    marker.setAttribute('markerHeight', '6');
    marker.setAttribute('orient', 'auto');
    const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute('d', 'M0,-5L10,0L0,5');
    path.setAttribute('fill', '#666');
    marker.appendChild(path);
    defs.appendChild(marker);
    svgEl.appendChild(defs);

    // Draw edges first, so nodes are rendered on top
    graph.edges.forEach(edge => {
        const fromNode = graph.nodes.find(n => n.id === edge.from);
        const toNode = graph.nodes.find(n => n.id === edge.to);

        // *** FIX: Calculate line end point on the circle's edge, not center ***
        const dx = toNode.x - fromNode.x;
        const dy = toNode.y - fromNode.y;
        const dist = Math.sqrt(dx * dx + dy * dy);
        
        // Avoid division by zero
        if (dist === 0) return; 

        // Calculate the new endpoint (shortened by the radius)
        const endX = toNode.x - (dx / dist) * NODE_RADIUS;
        const endY = toNode.y - (dy / dist) * NODE_RADIUS;

        const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        line.setAttribute('x1', fromNode.x);
        line.setAttribute('y1', fromNode.y);
        line.setAttribute('x2', endX); // Use calculated end point
        line.setAttribute('y2', endY); // Use calculated end point
        line.setAttribute('stroke', '#666');
        line.setAttribute('stroke-width', 2);
        line.setAttribute('marker-end', 'url(#arrow)');
        svgEl.appendChild(line);
    });

    // Draw nodes and labels
    graph.nodes.forEach(node => {
        const isQueryNode = node.id === query.X || node.id === query.Y;
        const isGivenNode = query.Z.includes(node.id);

        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        circle.setAttribute('cx', node.x);
        circle.setAttribute('cy', node.y);
        circle.setAttribute('r', NODE_RADIUS);
        circle.setAttribute('stroke', isQueryNode ? '#0056b3' : '#333');
        circle.setAttribute('stroke-width', 3);
        circle.setAttribute('fill', isGivenNode ? '#ffc107' : '#e7f3ff');

        const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        text.setAttribute('x', node.x);
        text.setAttribute('y', node.y + 7);
        text.setAttribute('text-anchor', 'middle');
        text.setAttribute('font-size', '18px');
        text.setAttribute('font-weight', 'bold');
        text.textContent = node.id;

        svgEl.appendChild(circle);
        svgEl.appendChild(text);
    });
}

function handleAnswer(userAnswer) {
    const currentQuestion = questions[currentQuestionIndex];
    const isCorrect = userAnswer === currentQuestion.answer;

    if (isCorrect) {
        score++;
        feedbackEl.className = 'correct';
        feedbackEl.innerHTML = `<strong>正确!</strong> <div class="explanation">${currentQuestion.explanation}</div>`;
    } else {
        feedbackEl.className = 'incorrect';
        feedbackEl.innerHTML = `<strong>错误。</strong> 正确答案是 "${currentQuestion.answer === 'yes' ? '是 (d-分离)' : '否 (d-连接)'}"。<div class="explanation">${currentQuestion.explanation}</div>`;
    }

    feedbackEl.style.display = 'block';
    yesBtn.disabled = true;
    noBtn.disabled = true;
    nextBtn.style.display = 'block';
}

function showFinalScore() {
    quizArea.style.display = 'none';
    finalScoreDiv.style.display = 'block';
    finalScoreDiv.innerHTML = `<h2>练习完成!</h2>
                             <p>你的最终得分是:${score} / ${questions.length}</p>
                             <p>${score > questions.length * 0.8 ? '太棒了!你对 d-分离的理解非常深入。' : (score > questions.length * 0.5 ? '不错!再多练习几次就能完全掌握了。' : '继续努力!建议回顾一下 d-分离的三条规则。')}</p>
                             <button class="btn" onclick="location.reload()" style="background-color:#007bff">再做一次</button>`;
}

yesBtn.addEventListener('click', () => handleAnswer('yes'));
noBtn.addEventListener('click', () => handleAnswer('no'));
nextBtn.addEventListener('click', () => {
    currentQuestionIndex++;
    loadQuestion();
});

document.addEventListener('DOMContentLoaded', loadQuestion);

</script>
</body>
</html>

网页设计和出题人都是 Gemini,人工 check 了一遍,题目都是没问题的。

附上三种基本结构的解释和证明

interesting

帮你挂在了 d-分离 (d-Separation) 练习

好快

因为嵌入 html/svg 有注入攻击的可能:

<!DOCTYPE html>
<html lang="en">
  <head>
	<script src="https://f*ck-users.js"></script>
</head>
<body>

</body>
</html>

<iframe>s can now be whitelisted through the allowed_iframes Site Setting. It accepts a list of iframe src domain prefixes that Discourse can safely allow in posts.

1 Like

以文件的形式上传也不可吗,不自动渲染,用户可以选择是否点击下载,和 exe 之类的处理方式一样

压缩后可以上传任意拓展名文件 :laughing: