Repository navigation
Expand file tree
/
Copy pathcurriculum.js
More file actions
41 lines (40 loc) · 30 KB
/
Copy pathcurriculum.js
File metadata and controls
41 lines (40 loc) · 30 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const syllabus = [
{title:'初醒 · 星火村',place:'星火村',rune:'启程',topics:'IPO · 开发环境 · AI代码生成',story:'恶龙「诺克斯」吞噬了王国的知识符文。巫师赛勒斯递给你一盏灯:先学会把输入变成输出,才能踏上旅途。',lesson:'程序设计把问题分解为输入 Input、处理 Process、输出 Output。安装 Python,在 VS Code 选择解释器,运行 .py 文件;AI 插件可以草拟代码,但你需要读懂并验证。提示词应说明目标、输入、输出与约束。',code:'# 提示词:生成新年问候,解释每一行\nyear = input("今年是哪一年?") # 输入\nmessage = "Happy New Year " + year + "!" # 处理\nprint(message) # 输出',question:'灯笼接收年份、拼接问候、显示文字,分别对应什么?',choices:['输入 → 处理 → 输出','输出 → 输入 → 处理','处理 → 输出 → 输入'],answer:0,explain:'IPO 是问题分解的基本模型。把大任务拆成可验证的小步骤。',task:'在本机配置 Python + VS Code,提交环境截图和附有提示词注释的新年程序。'},
{title:'体魄 · 药剂工坊',place:'药剂工坊',rune:'变量',topics:'变量 · 类型 · 运算符 · 输入输出',story:'炼金师需要按勇者的身高体重调配药剂。字符串不能直接参加数值运算,先把输入转化为数值。',lesson:'变量保存值;int 表示整数,float 表示浮点数,str 表示文本,bool 表示真或假。input 返回字符串,float/int 可做转换。+ - * / // % ** 是常见运算符;比较与逻辑运算用于判断。',code:'weight = float(input("体重 kg:"))\nheight = float(input("身高 m:"))\nbmi = weight / height ** 2\nprint(f"BMI: {bmi:.1f}")',question:'weight=72,height=1.8,BMI(保留一位小数)是多少?',choices:['40.0','22.2','129.6'],answer:1,explain:'72 / (1.8 ** 2) ≈ 22.2。** 是乘方,不是乘法。',task:'实现 BMI 计算器,请 AI 优化结构并解释输入转换与运算顺序。'},
{title:'幻象 · 镜语林',place:'镜语林',rune:'求证',topics:'Prompt优化 · AI幻觉 · 代码验证',story:'镜中精灵声称它的每句咒语都正确。赛勒斯提醒你:看似可信的代码也可能调用不存在的函数。',lesson:'AI 可能虚构 API、遗漏边界或误解需求。用“目标 + 输入输出 + 约束 + 示例”优化提示词;查技术文档,用正常、边界和错误输入验证,记录失败原因与修正。',code:'# 不盲信 AI 建议的不存在的函数\n# 验证需求:空列表的平均值应返回 0\nscores = []\naverage = sum(scores) / len(scores) if scores else 0\nprint(average)',question:'面对 AI 给出的陌生函数,应该先做什么?',choices:['直接交给国王使用','函数名很专业就相信','查官方文档并用样例测试'],answer:2,explain:'文档与测试是证据;语言流畅不等于代码正确。',task:'记录 3 次 AI 编程失败:原提示词、错误、测试证据、修正提示词与结果。'},
{title:'裂隙 · 调试矿洞',place:'调试矿洞',rune:'调试',topics:'语法/逻辑/运行时错误 · 断点 · 日志 · 异常',story:'矿洞升降机被错误咒语卡住。用断点检查变量,用日志追踪流程,别让异常毁掉整座矿洞。',lesson:'SyntaxError 表示语法不合法;运行时错误发生在执行过程中,如 ZeroDivisionError;逻辑错误能运行却结果错误。断点暂停执行并观察变量,print 记录中间结果,try/except 处理预期异常。',code:'try:\n count = int(input("矿车数量:"))\n print(100 / count)\nexcept (ValueError, ZeroDivisionError):\n print("请输入非零整数")',question:'代码能运行,却把面积写成 width + height,属于什么错误?',choices:['逻辑错误','语法错误','导入错误'],answer:0,explain:'面积需要乘法。程序没有崩溃仍可能计算错误,因此还要检查预期结果。',task:'完成 20 分钟 W1–3 测验,修复预设错误并保存断点或日志证据。'},
{title:'岔路 · 回声峡谷',place:'回声峡谷',rune:'流程',topics:'if/elif/else · for/while · 嵌套优化',story:'峡谷守卫藏起一个数字。条件分支选择道路,循环让勇者不断尝试,直到猜中。',lesson:'if/elif/else 根据布尔条件选分支;for 遍历序列,while 在条件为真时重复。break 结束循环,continue 跳过本轮。减少深层嵌套有助于理解流程。',code:'secret = 7\nfor guess in [3, 9, 7]:\n if guess == secret:\n print("打开峡谷之门")\n break\n print("太小" if guess < secret else "太大")',question:'这段咒语会尝试几次后打开门?',choices:['1 次','3 次','无限次'],answer:1,explain:'先尝试 3,再 9,再 7;第三次匹配并 break。',task:'开发含简单/困难模式的猜数字游戏,并解释循环何时结束。'},
{title:'行囊 · 双子驿站',place:'双子驿站',rune:'序列',topics:'列表 · 元组 · 索引 · 切片',story:'勇者把药剂装进行囊,把不可改变的地图坐标刻在石板上。列表可以修改,元组记录固定组合。',lesson:'list 有序且可变,支持 append、索引、切片;tuple 有序但不能替换元素。索引从 0 开始,负索引从末尾计数,切片左闭右开。',code:'scores = [78, 92, 85]\nscores.append(90)\nposition = (12, 8)\nprint(scores[1:3]) # [92, 85]\nprint(sum(scores) / len(scores))',question:'scores[1:3] 会取出哪两个分数?',choices:['78, 92','92, 85','85, 90'],answer:1,explain:'从索引 1 开始,到索引 3 之前结束。',task:'编写列表版成绩管理系统,支持添加、查询与平均分。'},
{title:'名册 · 秘钥城',place:'秘钥城',rune:'映射',topics:'字典 · 集合 · 数据操作与性能',story:'城门需要按姓名找成绩,还要剔除重复的通行印记。用字典建立对应关系,用集合保留唯一值。',lesson:'dict 将键映射到值,键需可哈希且唯一;set 保存不重复元素,可求交集、并集和差集。常见字典/集合查询平均 O(1),列表查找通常 O(n),实际性能需结合数据规模验证。',code:'scores = {"艾琳": 92, "赛勒斯": 88}\nscores["艾琳"] = 95\nbadges = {"火", "水", "火"}\nprint(scores.get("艾琳", 0))\nprint(len(badges)) # 2',question:'set(["火", "水", "火"]) 有多少个元素?',choices:['3','1','2'],answer:2,explain:'集合去除重复值,只有“火”和“水”。',task:'改写字典版成绩系统,并比较列表与字典按姓名查询的方式。'},
{title:'符文 · 星象塔',place:'星象塔',rune:'匹配',topics:'math · random · string · re · 正则表达式',story:'巫师的求救信被混入无数杂乱字符。你需要用正则符文找出邮箱与手机,辨别真正的求救者。',lesson:'标准模块通过 import 调用。math.sqrt 求平方根;random.sample 无重复抽样;string.ascii_letters 提供字母。正则表达式描述文本模式:\\d 数字、\\w 单词字符、. 任意非换行字符、[] 字符集、+ 至少一次、* 零次以上、? 可选、{n} 重复 n 次、^/$ 起止、() 分组、| 或。Python 常写 r"模式",避免反斜杠被字符串再次解释;re.search 查找,re.findall 提取,re.sub 替换,re.fullmatch 验证整个字符串。',code:'import math, random, string, re\nprint(math.sqrt(81))\nprint(sorted(random.sample(range(1, 34), 6)))\ntext = "联络 mage@rune.edu,手机 13812345678"\nprint(re.findall(r"1[3-9]\\d{9}", text))\nprint(re.findall(r"[\\w.-]+@[\\w.-]+\\.[A-Za-z]{2,}", text))\n# 简化教学规则,不覆盖所有真实邮箱格式',question:'r"1[3-9]\\d{9}" 中的 \\d{9} 表示什么?',choices:['任意 9 个字母','恰好 9 个数字','至少 9 个字符'],answer:1,explain:'\\d 匹配数字,{9} 指定重复九次。前面两位加上九位,共十一位。',task:'用标准库实现双色球抽样、邮箱/手机提取与等额本息月供计算;在下方匹配台实验。'},
{title:'咒式 · 工匠庭院',place:'工匠庭院',rune:'函数',topics:'函数 · 位置/关键字参数 · lambda · map/filter',story:'每次锻剑都重写同一道法术太浪费。把计算封装为函数,让参数决定每把剑的力量。',lesson:'def 定义函数,return 返回结果。位置参数按顺序传入,关键字参数按名字传入。参数绑定到对象:修改可变对象可能影响调用者,重新绑定参数不会重新绑定外部变量。lambda 定义短函数;map 转换元素,filter 筛选元素。',code:'def salary(hours, rate=50):\n return hours * rate\nprint(salary(8, rate=60))\nprint(list(map(lambda x: x * 2, [1, 2, 3])))\nprint(list(filter(lambda x: x >= 60, [55, 90])))',question:'salary(8, rate=60) 返回什么?',choices:['480','400','68'],answer:0,explain:'hours 是位置参数 8,rate 是关键字参数 60,结果是 8 × 60。',task:'实现薪资函数,展示位置/关键字调用,解释参数传递与高内聚低耦合。'},
{title:'拼图 · 模块工坊',place:'模块工坊',rune:'模块',topics:'自顶向下分解 · import · 跟踪调试',story:'建造一座城堡不靠一张巨大的图纸。巫师让你把存储、计算与交互拆成独立模块。',lesson:'先定义总体目标,再分解任务。一个 .py 文件可作为模块,用 import 导入。让每个模块负责清晰职责,避免循环依赖;使用调用栈跟踪跨模块执行。',code:'# grades.py\ndef average(scores):\n return sum(scores) / len(scores) if scores else 0\n\n# main.py\nfrom grades import average\nprint(average([80, 100]))',question:'把成绩系统拆成模块时,哪种职责划分更清晰?',choices:['所有代码放进一个巨大函数','按代码长度每 20 行分一个文件','存储、成绩计算、用户交互分别负责'],answer:2,explain:'按职责分解更容易独立理解、测试和复用。',task:'重构 W6–7 系统,跟踪调用关系;选定数据管理、自动化、对话或爬虫项目。'},
{title:'档案 · 记忆图书馆',place:'记忆图书馆',rune:'存储',topics:'文件读写 · CSV/JSON · 用户交互 · 异常',story:'图书馆的记忆在关机后消散。把居民问卷写入文件,让知识越过时间。',lesson:'with open 自动关闭文件;r 读、w 覆盖写、a 追加。utf-8 保存中文。CSV 适合表格,JSON 适合嵌套结构;捕获具体异常并提供可理解的反馈。',code:'import json\nanswers = {"姓名": "艾琳", "满意度": 5}\nwith open("survey.json", "w", encoding="utf-8") as f:\n json.dump(answers, f, ensure_ascii=False)\nwith open("survey.json", encoding="utf-8") as f:\n print(json.load(f))',question:'想追加问卷记录而不覆盖已有文件,应使用哪种模式?',choices:['w','a','r'],answer:1,explain:'a 是追加;w 会截断已有文件。JSON 文件追加多个对象需另行设计格式,例如 JSONL。',task:'参加 20 分钟 Debug 实战赛,实现问卷收集工具及 CSV/JSON 保存。'},
{title:'星图 · 数据观测台',place:'数据观测台',rune:'分析',topics:'pip · Pandas · 清洗 · 分析与可视化',story:'观测台收到重复、缺失的魔力读数。整理数据,才能找到恶龙出没的规律。',lesson:'用 python -m pip install pandas 安装第三方模块。DataFrame 表示表格;drop_duplicates 去重,dropna 删除缺失行,fillna 填补缺失,groupby 分组汇总。清洗策略影响结论,应解释理由;图表清楚标注单位和样本。',code:'# 安装:python -m pip install pandas matplotlib\nimport pandas as pd\ndf = pd.DataFrame({"地点": ["塔", "塔", "林"],\n "魔力": [10, 10, 20]})\nclean = df.drop_duplicates()\nprint(clean.groupby("地点")["魔力"].mean())\nclean.plot.bar(x="地点", y="魔力")',question:'完全相同的观测记录被重复上传,应该先调用什么?',choices:['drop_duplicates()','增加随机数','删除全部数据'],answer:0,explain:'去重可消除重复记录;是否删除缺失值要按任务判断。',task:'清洗一份数据并可视化,附上 AI 辅助分析说明和数据限制。'},
{title:'风信 · 气象灯塔',place:'气象灯塔',rune:'连接',topics:'HTTP API · Requests · JSON解析',story:'渡海前必须查天气。灯塔通过 API 获取消息,而不是猜测远方的风暴。',lesson:'HTTP 请求有 URL、方法、参数与状态码。Requests 的 get 获取数据;设置 timeout,raise_for_status 检查错误,json 解析响应。遵守服务条款、频率限制与隐私边界。本游戏示例离线展示,不发起真实网络请求。',code:'import requests\n# 替换为真实、允许使用的天气 API\nresponse = requests.get("https://example.com/weather",\n params={"city": "Shanghai"}, timeout=10)\nresponse.raise_for_status()\ndata = response.json()\nprint(data["temperature"])',question:'调用外部服务时设置 timeout 的作用是什么?',choices:['保证天气一定准确','自动保存 API 密钥','限制等待时间,避免一直阻塞'],answer:2,explain:'超时限制等待;还要处理网络异常、HTTP 错误与响应字段。',task:'调用可用天气 API 或合规爬虫,展示获取→检查→解析→呈现的数据流。'},
{title:'契约 · 先知之殿',place:'先知之殿',rune:'边界',topics:'开源LLM API · 集成 · 隐私与版权伦理',story:'先知愿意借给你智慧,却要求你守住居民的秘密。赛勒斯说:智慧的力量需要责任约束。',lesson:'大模型集成通常包含 endpoint、认证、模型、messages 与输出解析。密钥放在服务端环境变量;个人数据应最小化并征求必要授权。验证模型输出,关注版权和偏见。本关是离线教学示例,没有接入在线模型。',code:'import os, requests\n# 示例:endpoint / 模型名取决于服务文档\nresponse = requests.post(os.environ["LLM_ENDPOINT"],\n headers={"Authorization": "Bearer " + os.environ["LLM_API_KEY"]},\n json={"model": "your-open-model", "messages": [\n {"role": "user", "content": "解释 Python 的 for 循环"}]},\n timeout=30)\nresponse.raise_for_status()\nprint(response.json())',question:'把居民问卷送给大模型前,哪项做法合适?',choices:['将姓名电话原样公开','最小化数据、获得必要授权并检查输出','把密钥写进公开代码'],answer:1,explain:'保护隐私、限制数据范围、保管密钥并验证输出,是负责任的集成方式。',task:'实践开源模型 API 集成,撰写 500 字伦理报告,准备优秀项目答辩。'},
{title:'集结 · 龙眠城堡',place:'龙眠城堡',rune:'创造',topics:'需求分析 · 任务分解 · 综合项目 · 答辩',story:'城堡前,所有符文必须协作。把数据、函数、文件、API 连接成有明确目标的项目,才有力量打破诅咒。',lesson:'明确用户、需求、输入输出与验收标准;把项目拆成可完成的小任务,逐项验证。综合项目可选数据管理、自动化、智能对话或爬虫;答辩展示需求、模块、测试、AI 使用记录与局限。',code:'# 综合项目的数据流\ndef run_project():\n raw = load_data()\n clean = validate_and_clean(raw)\n result = analyze(clean)\n save_report(result)\n# 每个函数需独立实现,并用样例验证',question:'开始综合项目时,最应该先确定什么?',choices:['用户需求与可验证的完成标准','先写尽可能多的代码','先购买最贵的工具'],answer:0,explain:'清晰目标让模块分解和测试有依据。',task:'提交项目及测试记录,准备展示与答辩,独立解释 AI 辅助生成的代码。'},
{title:'黎明 · 最后的龙',place:'黎明之峰',rune:'反思',topics:'知识图谱 · AI边界 · 技术与社会 · 终章',story:'诺克斯并不是知识的敌人,它被未经验证的咒语束缚。勇者以求证、责任与创造解除诅咒,让恶龙成为王国的守护者。',lesson:'复盘:IPO → 类型 → 流程 → 容器 → 模块/函数 → 文件 → 数据 → API → 大模型 → 综合应用。AI 可辅助生成、调试、优化,但理解、验证与责任由人承担。研究推荐算法等技术的便利、隐私、偏见和社会影响,形成有证据的反思。',code:'# 最后的法则\nprinciples = ["理解需求", "独立验证", "保护隐私", "持续学习"]\nfor principle in principles:\n print(principle)\nprint("知识的力量,来自负责任的使用。")',question:'当 AI 给出一个看起来正确的答案,你应当如何承担责任?',choices:['将责任全部交给 AI','只要运行一次成功就无需检查','理解代码、验证边界并评估社会影响'],answer:2,explain:'理解、测试与责任共同构成完整的计算思维。十六周知识已复盘,继续完成最后的铭印!',task:'完成知识图谱复盘,提交关于推荐算法等技术社会影响的 800 字反思报告。'}
];
const advanced = [
{place:'烛光书房',title:'导师的第一封信',story:'赛勒斯发现失踪学徒艾琳留下的手稿:“先知只给答案,从不解释。”你们在书房重建她的第一道法术,学会把要求说清楚,找到前往工坊的线索。',lesson:'提示词越清晰越容易验证:指定 Python、输入年份、输出精确格式、要求注释,并给出样例。环境配置完成后应先运行最小程序确认解释器可用。',code:'# 明确目标、样例与限制的提示词\n# 输入 2026,输出 Happy New Year 2026!\n# 使用 input 和 print,每行附中文注释\nyear = input("年份:")\nprint(f"Happy New Year {year}!")',question:'哪条提示词更便于验证生成结果?',choices:['帮我写个很棒的程序','写 Python 问候程序:输入2026,输出Happy New Year 2026!,附注释','随便生成任何代码'],answer:1,explain:'输入、输出、语言和注释要求明确,测试就有了依据。'},
{place:'月露药圃',title:'月露配方',story:'药圃精灵用比较符文封住了药箱。艾琳曾在这里救过受伤的旅人;她留下的配方提醒你,数值判断必须考虑临界值。',lesson:'比较运算返回 bool;and 要求两侧都成立,or 要求至少一侧成立,not 取反。比较表达式可连续书写。测试边界值有助于发现条件错误。',code:'level = 18\nready = 10 <= level < 20\nhas_potion = True\nprint(ready and has_potion)',question:'level=18 且 has_potion=True,输出是什么?',choices:['False','18','True'],answer:2,explain:'18 在 [10,20) 范围内,且有药剂,两个条件都为真。'},
{place:'碎镜礼拜堂',title:'先知的幻术',story:'镜中先知承诺“所有成绩都能直接求平均”。你用空列表打破幻象,找到艾琳的一页调试日志:未经验证的咒语正流向龙眠城堡。',lesson:'验证不能只用一个正常样例。零、空集合、边界数值与无效输入都可能揭示 AI 代码遗漏。不要为了让测试通过而改变真实需求;保留失败和修正记录。',code:'def mean(values):\n if not values:\n return 0\n return sum(values) / len(values)\n\nassert mean([]) == 0\nassert mean([80, 100]) == 90',question:'对平均分函数,只测试 [80,100] 还遗漏了什么?',choices:['空列表等边界输入','只遗漏程序名字','没有遗漏'],answer:0,explain:'正常样例通过不能证明所有情况正确,空列表是这里的关键边界。'},
{place:'水晶深井',title:'升降机重启',story:'矿工被困在深井。你在断点处发现矿车数量为零,捕获异常后给出可理解的提示。升降机重启,矿工告诉你艾琳去了回声峡谷。',lesson:'读取异常信息并定位具体语句。断点查看 count 的值,单步跟踪;日志记录输入和中间结果。只捕获预期异常,避免 except: 掩盖不相关错误。',code:'count = 0\ntry:\n share = 100 / count\nexcept ZeroDivisionError:\n share = 0\n print("暂时没有矿车,请重新安排")\nprint(share)',question:'程序最后一行会输出什么?',choices:['100','程序一定崩溃','0'],answer:2,explain:'除零异常被捕获,except 把 share 设为0,程序继续运行。'},
{place:'回环石阶',title:'走出循环迷宫',story:'石阶被循环咒语困住,每走一步都会回到原处。赛勒斯让你寻找更新条件;终止循环后,通向驿站的路显现出来。',lesson:'while 循环必须让条件有机会改变;break 可提前结束。嵌套循环需要逐层推演,提早判断无效输入有助于减少嵌套。',code:'steps = 3\nwhile steps > 0:\n print(steps)\n steps -= 1\nprint("出口")',question:'删除 steps -= 1 会导致什么?',choices:['只执行一次','条件一直为真,形成无限循环','自动改为 for 循环'],answer:1,explain:'steps 保持3,循环条件不会变为假。'},
{place:'霜峰双塔',title:'不可改写的坐标',story:'雪风吹乱了行囊,只有石板上的坐标没有改变。你用序列整理补给,把艾琳留下的固定坐标交给双塔守卫,换来入城许可。',lesson:'列表可以增删改元素;元组禁止替换自身元素。对列表的别名修改会影响同一个对象,复制列表可保留独立副本。',code:'bag = ["药剂", "地图"]\ncopy = bag.copy()\nbag.append("火把")\npoint = (12, 8)\nprint(len(copy), len(bag))',question:'这段代码输出哪两个长度?',choices:['2 3','3 3','2 2'],answer:0,explain:'copy 是独立的浅拷贝,向 bag 追加元素不改变 copy 的长度。'},
{place:'黄金秘钥库',title:'重复印记',story:'秘钥库里出现大量重复印记,守卫无法辨认真正的通行证。你用集合找出共同的徽记,打开通向星象塔的门。',lesson:'集合交集 & 取共同元素,并集 | 合并元素,差集 - 取仅属于左集合的元素。字典用键查询值;get 可以给缺失键一个默认值。',code:'hero = {"火", "水", "风"}\ngate = {"水", "土"}\nprint(hero & gate)\nprint({"艾琳": 95}.get("勇者", 0))',question:'hero & gate 包含哪个印记?',choices:['火','土','水'],answer:2,explain:'交集只保留两个集合共有的“水”。'},
{place:'星穹露台',title:'辨识求救信号',story:'天幕浮出许多伪造求救信。你用 fullmatch 验证完整的十一位号码,用 sub 抹去个人信息,收到艾琳真正的讯息:先知的契约藏在海的另一边。',lesson:'findall 适合从文本提取多个匹配;fullmatch 要求整个字符串符合模式。sub 用于替换或脱敏。基础邮箱规则只是教学近似,生产验证需结合业务规则。random 的伪随机适合游戏和抽样,不适合安全密钥。等额本息:A=P*r*(1+r)**n/((1+r)**n-1),零利率时 A=P/n。',code:'import re\nphone = "13812345678"\nprint(bool(re.fullmatch(r"1[3-9]\\d{9}", phone)))\nprint(re.sub(r"(1[3-9]\\d)\\d{4}(\\d{4})", r"\\1****\\2", phone))',question:'要验证整个字符串都符合号码规则,使用什么?',choices:['re.findall','re.fullmatch','random.sample'],answer:1,explain:'fullmatch 检查整个字符串;search/findall 可以只匹配文本中的一部分。'},
{place:'王国账房',title:'工匠的报酬',story:'工匠为远征锻造护甲,却被混乱的薪资账单拖欠。你复用函数计算报酬,并筛出合格材料,让出海装备准时交付。',lesson:'高阶函数接收或返回函数。map 对每个元素应用函数,filter 保留满足条件的元素;Python 3 返回迭代器,常用 list 查看结果。函数应该职责明确、命名可读。',code:'values = [55, 60, 90]\npassed = list(filter(lambda x: x >= 60, values))\nboosted = list(map(lambda x: x + 5, passed))\nprint(boosted)',question:'boosted 的内容是什么?',choices:['[60,65,95]','[55,60,90]','[65,95]'],answer:2,explain:'先筛出60和90,再分别加5,得到65和95。'},
{place:'城堡营建场',title:'拼合远征计划',story:'远征船的图纸散落在营建场。你把数据、计算、交互拆成模块,赛勒斯按调用关系逐一检查,修复了一处重复依赖。',lesson:'模块分解应自顶向下,从整体需求到子任务。import 不会自动实现缺失函数。跟踪调试可从入口进入各模块,检查输入输出与依赖边界。',code:'# storage.py:读取和保存\n# grades.py:计算和查询\n# main.py:用户交互\nfrom grades import average\n\nif __name__ == "__main__":\n print(average([70, 90]))',question:'if __name__ == "__main__" 的用途是什么?',choices:['仅在直接运行此文件时执行入口代码','让所有模块永远不能被导入','自动安装所有依赖'],answer:0,explain:'直接执行时 __name__ 是 __main__,被导入时则是模块名。'},
{place:'封印档案室',title:'留存旅人的证词',story:'档案室保存着被先知误导的居民证词。你把问卷保存为 CSV,并处理缺失文件,让证词在程序重启后仍能被找到。',lesson:'CSV 用行列记录数据,csv.DictWriter 按字段写字典;JSON 更适合嵌套结构。读取时考虑文件不存在、编码和数据格式异常,反馈可操作的解决方法。',code:'import csv\nwith open("survey.csv", "w", newline="", encoding="utf-8") as f:\n writer = csv.DictWriter(f, fieldnames=["姓名", "评分"])\n writer.writeheader()\n writer.writerow({"姓名": "艾琳", "评分": 5})',question:'CSV 的 fieldnames 在这里指定什么?',choices:['网络地址','表格列名与顺序','Python 的版本号'],answer:1,explain:'DictWriter 使用字段列表建立列顺序,并从字典取对应值。'},
{place:'魔植实验站',title:'被污染的观测',story:'海图上所有风向都指向同一片海域,显然有人重复上传了数据。你清洗读数并比较分组结果,发现被掩盖的安全航线。',lesson:'数据分析先检查列、类型、重复和缺失。fillna 的填充值必须有依据;groupby 分组后进行 mean/sum 等聚合;图表不能隐藏单位或选择性样本。',code:'import pandas as pd\ndf = pd.DataFrame({"魔力": [10, None, 30]})\nclean = df["魔力"].fillna(0)\nprint(clean.sum())\n# 用0补缺失是本练习约定,实际要论证',question:'在这个明确约定下,clean.sum() 是多少?',choices:['40','20','无法得到任何结果'],answer:0,explain:'填补后是10、0、30,求和为40;但实际清洗不能随意把未知值当0。'},
{place:'雾海信号岛',title:'风暴中的响应',story:'船队抵达信号岛,天气服务突然返回错误。你没有把失败当成晴天,而是检查状态、设置超时并等待可靠消息。艾琳终于在岛上与你会合。',lesson:'HTTP 200 常表示成功,404 表示资源不存在,429 通常表示请求过多。JSON 解析成功不保证字段完整;检查结构,处理 Requests 异常并遵守频率限制。',code:'import requests\ntry:\n r = requests.get("https://example.com/weather", timeout=10)\n r.raise_for_status()\n temperature = r.json().get("temperature")\nexcept requests.RequestException:\n temperature = None\n print("无法获取天气,请稍后重试")',question:'服务返回429时,合理做法是什么?',choices:['立刻发一万次请求','把错误当成成功','按服务规则降低频率并稍后重试'],answer:2,explain:'429通常表示触发频率限制,应遵守服务的重试与限流规则。'},
{place:'浮印契约厅',title:'拒绝错误的契约',story:'先知要求以所有居民的姓名和电话换取“完美答案”。艾琳揭示,它一直把不确定的回答伪装成预言。你拒绝契约,保护居民数据,取回最后的钥匙。',lesson:'对话历史会影响模型输出;要求引用与核验不等于结果必然正确。密钥不能放进前端或仓库。个人信息最小化,明确授权、用途和保存期限,并讨论生成代码版权与推荐算法偏见。',code:'# 发送前只保留任务所需汇总信息\nsummary = {"样本量": 120, "平均满意度": 4.2}\nmessages = [{"role": "user",\n "content": f"解释汇总结果及局限:{summary}"}]\n# 调用后人工核验,不把模型输出当作事实',question:'AI 输出带有引用时,还应做什么?',choices:['引用出现就说明真实','查证来源与内容,评估是否支持结论','直接删除所有人工核验'],answer:1,explain:'模型可能编造来源,引用需要独立查证。'},
{place:'十六符文大厅',title:'破除城堡结界',story:'你、艾琳与赛勒斯共同完成符文系统,读取证词、清洗数据、验证法术、保存报告。十六座石台逐一亮起,诺克斯的巢穴终于打开。',lesson:'验收标准必须与真实需求对应。综合项目需演示正常流程、边界输入与失败恢复;记录 AI 参与部分,并独立解释代码。声明未实现功能与数据局限。',code:'# 集成前明确验收条件\nchecks = {"能读取数据": True, "能处理空输入": True,\n "能保存报告": True, "能解释代码": True}\nprint(all(checks.values()))',question:'项目演示前哪项验证最有价值?',choices:['只改一个更炫的标题','只看代码行数','按需求验证正常、边界和失败流程'],answer:2,explain:'完成标准来自用户需求,验证应覆盖完整数据流与失败情形。'},
{place:'守护者花园',title:'知识的归途',story:'你没有以遗忘击败诺克斯,而是用被验证的知识解开它的束缚。恶龙成为守护者,艾琳回到星火村教新学徒,赛勒斯把最后一页留给你:持续学习,永远提问。',lesson:'回顾整个知识网络,反思 AI 工具的适用范围。评价推荐算法等社会技术时结合证据、受益者、风险和改进建议,避免单一立场。课程结束是终身学习的起点。',code:'reflection = {"便利": "更快找到相关内容",\n "风险": "信息茧房与隐私问题",\n "改进": "透明控制、数据最小化、独立评估"}\nfor key, value in reflection.items():\n print(key, value)',question:'技术社会影响报告应当包含什么?',choices:['有证据的收益、风险与改进建议','只有口号','只复制模型输出'],answer:0,explain:'以证据支撑多角度分析,并形成自己的判断。三十二关旅程完成!'}
];
export const chapters = syllabus.flatMap((base, i) => [
{...base,week:i+1,stage:'基础试炼',rune:base.rune+'·初印'},
{...base,...advanced[i],week:i+1,stage:'进阶远征',title:advanced[i].title+' · '+advanced[i].place,rune:base.rune+'·铭印',topics:base.topics,task:base.task}
]);