考试复习时间表规划器
来自 Wikiprompt,自由的提示词百科全书
考试复习时间表规划器 一个完整的技能/提示,用于制定逐日考试复习时间表,包含基于证据的学习技巧、Python规划脚本和模板。它收集考试详情,运行规划器,解决权衡问题,并交付一份人性化的计划。
提示词内容收藏
🌐
---
name: exam-revision-timetable-planner
description: 根据考试日期、科目权重和信心水平,制定逐日的考试复习时间表。将学习时间划分为专注时段,为薄弱和重要科目分配更多时间,交错安排科目,在每门考试前一周转为练习题目,并在考试前一天安排限时真题演练,同时尊重休息日和休息时间。当每个主题的时段过少或考试时间连续时,会发出提醒。包含一个带有 --self-test 的 stdlib Python 规划器。
---
# 考试复习时间表规划器
你帮助学生将紧张的考试季转化为一个切实可行的计划:每天每个时段学习哪个科目,直到最后一门考试。你使用基于证据的技巧(间隔学习、提取练习、交错学习、真题演练),通过休息和睡眠保持计划的合理性,并在时间不足时明确展示取舍。
## 此技能中的文件
- `scripts/revision_plan.py` - 读取科目 CSV 并打印科目表、逐日时间表和发现(仅使用 Python 3 标准库)
- `references/study-techniques.md` - 时段内该做什么:提取练习、间隔学习、交错学习、真题演练,以及应避免的事项
- `references/scheduling-rules.md` - 脚本如何分配优先级、目标、时段类型和发现,以及如何调整
- `templates/revision-plan.md` - 要交回的计划:概览、每周时间表、时段常规、检查点
- `examples/winter-exams.csv` - 12月2日至11日之间的五场大学考试,包含主题数量
## 工作流程
### 1. 收集事实
询问每门考试:科目、日期、权重(学分、期末成绩百分比或重要性1-5)、信心水平(1表示迷茫到5表示扎实),以及主题或章节数量。然后询问第一个复习日、工作日和周末的实际可用小时数(课后、工作、通勤后)、偏好的时段长度(默认50/10,低专注度时用25/5番茄钟)、每周休息日以及任何已被占用的日期。
### 2. 运行规划器
```
python3 scripts/revision_plan.py examples/winter-exams.csv --start 2026-11-16 --weekday-hours 3 --weekend-hours 5 --rest-day Sun --off 2026-11-21 --day-start 16:00
python3 scripts/revision_plan.py my-exams.csv --start 2026-05-04 --session-min 25 --break-min 5 --json
python3 scripts/revision_plan.py --self-test
```
退出码 1 表示 HIGH 发现(时段少于主题数),2 表示输入错误。
### 3. 解决取舍
对于 UNDER_COVERED 或 TIGHT:增加小时数、提前开始、降低强项科目的目标,或同意略过哪些低收益主题(使用教学大纲权重或真题出现频率)。对于 BACK_TO_BACK:将第二门科目的练习提前到第一门考试之前。与学生一起检查计划:在状态不佳的日子可行吗?留出余量,而不是每晚都塞满。
### 4. 交付
填写 `templates/revision-plan.md`:概览表、按周划分的时间表、来自 `references/study-techniques.md` 的时段常规,以及两个检查日期,用于重新评估信心并重新运行脚本。
## 示例结果
对于 `examples/winter-exams.csv`,从11月16日开始,工作日3小时,周六5小时,周日和11月21日休息:25天,57个50分钟的时段(47.5小时)。有机化学(权重5,信心2)和微观经济学(4,2)分别获得15和16个时段,欧洲历史(3,4)获得6个。每门科目以练习题结束,并在考试前一天安排限时真题。发现:统计学(8个主题10个时段)和欧洲历史(6个主题6个时段)为 TIGHT,欧洲历史和微观经济学在12月7日和8日连续考试。
## 规则
- 根据学生实际拥有的时间制定计划,而不是他们希望拥有的时间;保护睡眠(考试前不要安排深夜时段)。
- 每个时段以提取练习结束(问题、空白页回忆、闪卡),而不仅仅是重读或划重点。
- 每周至少保留一个休息日或两个半天;倦怠的代价超过失去一天。
- 每次检查或考试后重新规划,而不是遵循一个已失效的计划。
- 不代替学生完成计分作业;帮助制定计划和学习方法。如果学生表现出严重压力或恐慌的迹象,鼓励他们联系学生支持或医生。
FILE:references/study-techniques.md
# 学习技巧
每个时段内该做什么。按证据强度排序(Dunlosky 等人,2013年,“用有效的学习技巧改善学生的学习”,将练习测试和分散练习评为高实用性)。
## 提取练习(高)
从记忆中提取信息,而不是重新阅读:回答问题,在空白页上写下你记得的所有内容,然后对照笔记检查,并用另一种颜色填补空白。闪卡在翻转前回答才有效。先答错再纠正也有助于学习。
## 间隔学习(高)
将同一科目的学习分散到多天,而不是一个长块。每个主题的简单复习节奏:第二天、3天后、一周后,然后考试前。时间表跨天交错安排科目;每个时段以对该科目上一时段的5分钟回忆开始,以建立间隔学习。
## 交错学习(中等)
在科目内混合问题类型(数学和科学:一套题中包含不同类型的问题,而不是20道相同类型),以便练习选择方法,这是考试要求的。
## 真题演练(考试高价值)
每门考试前至少完成一份限时完整试卷,然后用官方评分标准批改,并按主题列出失分点。脚本在每门考试前一天安排一份;如果有更多试卷,可提前增加。
## 精细加工和自我解释(中等)
问“为什么这样有效?”和“这与X有何联系?”,像教学一样大声解释一个概念,凭记忆绘制概念图。
## 单独使用价值低
重读、划重点和抄笔记感觉高效,但长期收益甚微。仅在提取练习前作为第一遍使用。
## 时段常规(默认50/10)
1. 5分钟:凭记忆回忆你上次为该科目做了什么。
2. 30分钟:学习或练习一个主题(学习+回忆)或做问题(练习题)。
3. 10分钟:合上书自我测试;标记遗漏之处。
4. 5分钟:写下三个你无法回答的问题,留待下次。
5. 10分钟离开屏幕休息:活动、喝水。
注意力持续时间短时使用25/5时段(`--session-min 25 --break-min 5`),每四个时段后安排更长休息。
## 睡眠、饮食和前一天
睡眠巩固记忆;熬夜会降低考试表现。考试前一晚保持轻松复习和睡眠。规律饮食,每天活动,时段内将手机放在另一个房间。
FILE:references/scheduling-rules.md
# 调度规则
`scripts/revision_plan.py` 如何构建时间表。
## 每天时段数
适合每日小时数的时段数:`floor((hours * 60 + break) / (session + break))`。使用50/10时段:3小时 -> 3个时段,5小时 -> 5个时段。休息日(`--rest-day`)和 `--off` 日期无时段。考试日仅安排一半时段(考试占用其余时间),且仅针对后续考试。
## 优先级和目标
- 优先级 = 权重 x (6 - 信心)。权重5,信心2 -> 20;权重3,信心4 -> 6。
- 目标时段 = 该考试前所有可用时段 x 优先级 / 所有优先级之和(至少1)。
权重可以是学分或1-5重要性分数;只有比例重要,因此对每门科目使用相同量表。
## 选择每个时段
对于每个时段,脚本在考试尚未到来且当天少于 `--max-same`(默认2)个时段的科目中选择:
1. 首先选择仍低于目标的科目;
2. 然后选择与上一时段不同的科目(交错学习);
3. 然后选择每天剩余需求最高的科目,按考试剩余天数计算;
4. 平局时选择优先级更高、考试更早的科目。
考试前一天以该科目的限时真题开始。
## 时段类型
- 学习+回忆:直到科目目标的60%完成且距考试超过7天。
- 混合复习:目标60%之后,距考试超过7天。
- 练习题:考试前7天内。
- 真题(限时):考试前一天。
## 发现
| 代码 | 严重性 | 规则 | 典型解决方案 |
|---|---|---|---|
| UNDER_COVERED | HIGH | 时段 < 主题数 | 增加小时数、提前开始、略过低收益主题 |
| TIGHT | MEDIUM | 时段 < 1.5 x 主题数 | 接受单次通过,或从强项科目中抽取时间 |
| BELOW_TARGET | MEDIUM | 计划 < 目标的60% | 考试较早;先开始该科目 |
| BACK_TO_BACK | MEDIUM | 考试连续日期 | 提前加载第二门科目的练习 |
| SAME_DAY | MEDIUM | 一天两场考试 | 最后一周将两者视为一个块 |
| NO_REST_DAY | LOW | 计划超过10天无休息日或off日期 | 添加 `--rest-day` |
| LONG_DAYS | LOW | 每天超过8小时 | 限制在5-6个专注小时 |
## 调整
- 为某科目增加时间:提高其权重或降低其信心并重新运行。
- 减少科目切换:`--max-same 3`。
- 时钟时间:`--day-start 09:00` 添加开始和结束时间,时段之间有休息。
- 重新规划:每次检查后,更新信心和 `--start`,并重新运行;已完成的考试从 CSV 中移除。
FILE:templates/revision-plan.md
# 复习计划:<姓名>,<考试季>
**期间:** <11月16日至12月11日2026> **小时数:** <工作日3小时,周六5小时> **休息:** <周日 + 11月21日>
**时段:** <57 x 50分钟(47.5小时)> **时段节奏:** <50分钟学习 / 10分钟休息>
## 考试和优先级
| 科目 | 考试 | 权重 | 信心 | 主题 | 计划时段 | 备注 |
|---|---|---|---|---|---|---|
| <有机化学> | <12月2日周三> | <5> | <2> | <9> | <15> | <12月1日真题> |
## 第1周:<11月16-22日>
| 天 | 时段1 | 时段2 | 时段3 | 时段4 | 时段5 |
|---|---|---|---|---|---|
| <11月16日周一> | <16:00 有机化学:学习> | <17:00 微观经济学:学习> | <...> | | |
## 第2周:<...>
<...>
## 时段常规
1. 5分钟回忆上一时段(空白页)
2. 30分钟学习或练习一个主题
3. 10分钟自我测试,标记错误
4. 5分钟:三个未解决问题留待下次
5. 10分钟离开屏幕休息
## 已同意的取舍
- <统计学为 TIGHT:一次完整通过,第二次仅针对主题5-8(真题中分值最高)>
- <欧洲历史 / 微观经济学连续:微观经济学练习在12月5日前完成>
## 检查点
- <11月22日周日>:重新评估每门科目信心1-5,重新运行规划器
- <11月29日周日>:相同,调整最后10天
## 健康
- 睡眠:<23:30前上床,考试前一晚22:00后不学习>
- 每日活动:<30分钟步行>
- 如果压力过大:<与...交谈 / 学生支持联系方式>
FILE:examples/winter-exams.csv
subject,exam_date,weight,confidence,topics
有机化学,2026-12-02,5,2,9
统计学,2026-12-04,4,3,8
欧洲历史,2026-12-07,3,4,6
微观经济学,2026-12-08,4,2,7
学术英语,2026-12-11,2,4,4
FILE:scripts/revision_plan.py
#!/usr/bin/env python3
"""考试复习时间表规划器(仅使用 Python 3 标准库)。
读取包含考试日期、权重和信心的科目 CSV,将可用学习时间划分为专注时段,并构建逐日时间表,为薄弱、重要科目分配更多时间,交错安排科目,在考试后停止该科目的新学习,在每门考试前一周从学习转为练习题,并在前一天安排限时真题。
CSV 列(需要表头;分号或逗号分隔):
subject, exam_date (YYYY-MM-DD), weight (1-5 或学分), confidence (1-5), topics (可选)
用法:
python3 revision_plan.py exams.csv --start 2026-11-16 --weekday-hours 3 --weekend-hours 5
python3 revision_plan.py exams.csv --start 2026-11-16 --rest-day Sun --off 2026-11-28,2026-11-29 --day-start 16:00
python3 revision_plan.py --self-test
退出码:0 = 计划可行,1 = HIGH 发现(时段不足),2 = 输入错误。
"""
import argparse, csv, datetime as dt, io, json, sys
DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
SEV = {"HIGH": 0, "MEDIUM": 1, "LOW": 2}
class InputError(Exception):
pass
def parse_date(s, what):
try:
return dt.date.fromisoformat(s.strip())
except ValueError:
raise InputError(f"{what} '{s}' 必须为 YYYY-MM-DD")
def read_subjects(text):
sample = text[:2000]
delim = ";" if sample.count(";") > sample.count(",") else ","
rd = csv.DictReader(io.StringIO(text), delimiter=delim)
if not rd.fieldnames:
raise InputError("CSV 为空")
fields = [f.strip().lower() for f in rd.fieldnames]
missing = [c for c in ("subject", "exam_date", "weight", "confidence") if c not in fields]
if missing:
raise InputError("缺少列:" + ", ".join(missing))
subs = []
for i, raw in enumerate(rd, start=2):
r = {k.strip().lower(): (v or "").strip() for k, v in raw.items() if k}
if not any(r.values()):
continue
try:
w = float(r["weight"].replace(",", "."))
c = int(r["confidence"])
t = int(r["topics"]) if r.get("topics") else None
except ValueError:
raise InputError(f"第 {i} 行:weight、confidence 和 topics 必须为数字")
if w <= 0:
raise InputError(f"第 {i} 行:weight 必须为正数")
if not 1 <= c <= 5:
raise InputError(f"第 {i} 行:confidence 必须为 1(弱)到 5(强)")
if not r["subject"]:
raise InputError(f"第 {i} 行:subject 为空")
subs.append({"subject": r["subject"], "exam": parse_date(r["exam_date"], f"第 {i} 行:exam_date"),
"weight": w, "confidence": c, "topics": t})
if not subs:
raise InputError("CSV 中没有科目")
return subs
def slots_for(hours, session, brk):
"""适合 `hours` 的时段数,时段之间有休息。"""
mins = hours * 60
if mins < session:
return 0
return int((mins + brk) // (session + brk))
def plan(subs, start, weekday_hours=3.0, weekend_hours=5.0, session=50, brk=10, rest_day=None,
off=(), max_same=2, day_start=None):
if session < 15 or brk < 0:
raise InputError("session 必须至少为 15 分钟,break 不能为负数")
for s in subs:
if s["exam"] <= start:
raise InputError(f"{s['subject']}:考试 {s['exam']} 不在开始日期 {start} 之后")
last = max(s["exam"] for s in subs)
exam_days = {}
for s in subs:
exam_days.setdefault(s["exam"], []).append(s["subject"])
for s in subs:
s["priority"] = s["weight"] * (6 - s["confidence"])
days = []
d = start
while d < last:
if d in off or (rest_day is not None and d.weekday() == rest_day):
n = 0
else:
n = slots_for(weekend_hours if d.weekday() >= 5 else weekday_hours, session, brk)
if d in exam_days:
n //= 2 # 考试占用半天
days.append((d, n))
d += dt.timedelta(days=1)
# 目标时段:按优先级分配每门考试前可用时段的比例
total_p = sum(s["priority"] for s in subs)
for s in subs:
before = sum(n for day, n in days if day < s["exam"])
s["target"] = max(1, round(before * s["priority"] / total_p))
s["planned"] = 0
timetable = []
for day, n in days:
today, used = [], {}
live = [s for s in subs if s["exam"] > day]
# 考试前一天:先安排限时真题
for s in live:
if (s["exam"] - day).days == 1 and len(today) < n:
today.append((s["subject"], "真题(限时)")); used[s["subject"]] = 1; s["planned"] += 1
while len(today) < n:
cands = [s for s in live if used.get(s["subject"], 0) < max_same]
if not cands:
break
prev = today[-1][0] if today else None
def score(s):
days_left = max(1, (s["exam"] - day).days)
need = (s["target"] - s["planned"]) / days_left
# 首先选择仍低于目标的科目,然后交错(避免重复上一科目)
return (s["planned"] < s["target"], s["subject"] != prev, need, s["priority"], -s["exam"].toordinal())
s = max(cands, key=score)
left = (s["exam"] - day).days
kind = "练习题" if left <= 7 else ("学习+回忆" if s["planned"] < s["target"] * 0.6 else "混合复习")
today.append((s["subject"], kind)); used[s["subject"]] = used.get(s["subject"], 0) + 1; s["planned"] += 1
timed = []
t = day_start
for subj, kind in today:
if t is not None:
end = t + session
timed.append({"subject": subj, "kind": kind, "time": f"{t // 60:02d}:{t % 60:02d}-{end // 60:02d}:{end % 60:02d}"})
t = end + brk
else:
timed.append({"subject": subj, "kind": kind})
timetable.append({"date": day.isoformat(), "dow": DAYS[day.weekday()], "exams": exam_days.get(day, []), "sessions": timed})
findings = []
for s in subs:
if s["topics"]:
if s["planned"] < s["topics"]:
findings.append(("HIGH", "UNDER_COVERED", f"{s['subject']}:{s['planned']} 个时段对应 {s['topics']} 个主题;增加小时数、略过低收益主题或提前开始"))
elif s["planned"] < 1.5 * s["topics"]:
findings.append(("MEDIUM", "TIGHT", f"{s['subject']}:{s['planned']} 个时段对应 {s['topics']} 个主题,第二次通过时间不足"))
if s["planned"] < 0.6 * s["target"]:
findings.append(("MEDIUM", "BELOW_TARGET", f"{s['subject']}:考试前仅安排 {s['planned']} 个目标时段中的 {s['target']} 个"))
dates = sorted(exam_days)
for a, b in zip(dates, dates[1:]):
if (b - a).days <= 1:
findings.append(("MEDIUM", "BACK_TO_BACK", f"考试在 {a}({', '.join(exam_days[a])})和 {b}({', '.join(exam_days[b])})连续;在第一门考试前完成第二门科目的练习"))
for day, subjects in exam_days.items():
if len(subjects) > 1:
findings.append(("MEDIUM", "SAME_DAY", f"{len(subjects)} 场考试在 {day}:{', '.join(subjects)}"))
if rest_day is None and len(days) > 10 and not off:
findings.append(("LOW", "NO_REST_DAY", "超过 10 天的计划中没有休息日;每周至少休息半天"))
if max(weekday_hours, weekend_hours) > 8:
findings.append(("LOW", "LONG_DAYS", "每天超过 8 小时的复习很少能保持高效;保持 5-6 个专注小时"))
findings.sort(key=lambda f: SEV[f[0]])
total_sessions = sum(len(t["sessions"]) for t in timetable)
return {
"subjects": [{"subject": s["subject"], "exam": s["exam"].isoformat(), "weight": s["weight"], "confidence": s["confidence"],
"priority": s["priority"], "topics": s["topics"], "target": s["target"], "planned": s["planned"],
"hours": round(s["planned"] * session / 60, 1)} for s in sorted(subs, key=lambda x: x["exam"])],
"summary": {"start": start.isoformat(), "last_exam": last.isoformat(), "days": len(days), "sessions": total_sessions,
"study_hours": round(total_sessions * session / 60, 1), "session_min": session, "break_min": brk},
"timetable": timetable,
"findings": [{"severity": a, "code": b, "message": c} for a, b, c in findings],
}
def to_markdown(p):
s = p["summary"]
out = ["# 复习时间表", "",
f"{s['start']} 至 {s['last_exam']}:{s['days']} 天,{s['sessions']} 个时段,每个 {s['session_min']} 分钟({s['study_hours']} 小时专注学习),{s['break_min']} 分钟休息",
"", "| 科目 | 考试 | 权重 | 信心 | 优先级 | 主题 | 目标 | 计划 | 小时 |", "|---|---|---|---|---|---|---|---|---|"]
for x in p["subjects"]:
out.append(f"| {x['subject']} | {x['exam']} | {x['weight']:g} | {x['confidence']} | {x['priority']:g} | {x['topics'] or '-'} | {x['target']} | {x['planned']} | {x['hours']} |")
out += ["", "## 逐日", ""]
for t in p["timetable"]:
head = f"- **{t['dow']} {t['date']}**" + (f"(考试:{', '.join(t['exams'])})" if t["exams"] else "")
if not t["sessions"]:
out.append(head + ":休息")
continue
parts = [(f"{x['time']} " if "time" in x else "") + f"{x['subject']}({x['kind']})" for x in t["sessions"]]
out.append(head + ":" + "; ".join(parts))
out += ["", "## 发现"]
out += [f"- {f['severity']} {f['code']}:{f['message']}" for f in p["findings"]] or ["- 无"]
out += ["", "每个时段以对该科目上一时段的 5 分钟回忆开始,并以 3 个你无法回答的问题结束。"]
return "\n".join(out)
def self_test():
res = []
def check(name, cond):
res.append(cond)
print(("PASS " if cond else "FAIL ") + name)
D = dt.date
S = lambda name, exam, w=1, c=3, t=None: {"subject": name, "exam": exam, "weight": w, "confidence": c, "topics": t}
check("slots: 3 小时 50+10 = 3", slots_for(3, 50, 10) == 3)
check("slots: 50 分钟恰好 1", slots_for(50 / 60, 50, 10) == 1)
check("slots: 不足一个时段 = 0", slots_for(0.5, 50, 10) == 0)
check("slots: 25+5 在 2 小时 = 4", slots_for(2, 25, 5) == 4)
p = plan([S("A", D(2026, 1, 8))], D(2026, 1, 5), weekday_hours=2, weekend_hours=2, session=50, brk=10)
check("考试日或之后无时段", all(t["date"] < "2026-01-08" for t in p["timetable"]))
check("考试前一天以真题开始", p["timetable"][-1]["sessions"][0]["kind"] == "真题(限时)")
check("最后 7 天为练习题", all(x["kind"] != "学习+回忆" for t in p["timetable"] for x in t["sessions"]))
subs = [S("弱", D(2026, 3, 1), w=3, c=1), S("强", D(2026, 3, 1), w=3, c=5)]
p = plan(subs, D(2026, 2, 1), weekday_hours=3, weekend_hours=3, max_same=3)
pl = {x["subject"]: x["planned"] for x in p["subjects"]}
check("弱科目获得更多时段", pl["弱"] > 3 * pl["强"])
check("优先级 = 权重 x (6 - 信心)", p["subjects"][0]["priority"] in (15, 3))
p = plan([S("A", D(2026, 3, 1)), S("B", D(2026, 3, 1))], D(2026, 2, 1), weekday_hours=3, weekend_hours=3)
check("每天每科目最多 2 个时段", all(
sum(1 for x in t["sessions"] if x["subject"] == subj) <= 2 for t in p["timetable"] for subj in "AB"))
check("两科目需要时间时交错", all(t["sessions"][i]["subject"] != t["sessions"][i + 1]["subject"]
for t in p["timetable"][:10] for i in range(len(t["sessions"]) - 1)))
p = plan([S("A", D(2026, 2, 16))], D(2026, 2, 2), rest_day=6)
check("休息日为空", all(not t["sessions"] for t in p["timetable"] if t["dow"] == "Sun"))
p = plan([S("A", D(2026, 2, 6))], D(2026, 2, 2), off={D(2026, 2, 3)})
check("off 日为空", not [t for t in p["timetable"] if t["date"] == "2026-02-03"][0]["sessions"])
p = plan([S("A", D(2026, 2, 5)), S("B", D(2026, 2, 9))], D(2026, 2, 2), weekday_hours=4)
day5 = [t for t in p["timetable"] if t["date"] == "2026-02-05"][0]
check("考试日:一半时段,仅其他科目", len(day5["sessions"]) == 2 and all(x["subject"] == "B" for x in day5["sessions"]))
p = plan([S("A", D(2026, 2, 5), t=20)], D(2026, 2, 2))
check("UNDER_COVERED HIGH", p["findings"][0]["code"] == "UNDER_COVERED")
p = plan([S("A", D(2026, 2, 20), t=11)], D(2026, 2, 2), weekday_hours=1, weekend_hours=1, rest_day=6)
check("TIGHT", any(f["code"] == "TIGHT" for f in p["findings"]))
p = plan([S("A", D(2026, 2, 9)), S("B", D(2026, 2, 10)), S("C", D(2026, 2, 10))], D(2026, 2, 2))
codes = [f["code"] for f in p["findings"]]
check("BACK_TO_BACK 和 SAME_DAY", "BACK_TO_BACK" in codes and "SAME_DAY" in codes)
check("NO_REST_DAY", "NO_REST_DAY" in [f["code"] for f in plan([S("A", D(2026, 3, 1))], D(2026, 2, 1))["findings"]])
check("LONG_DAYS", "LONG_DAYS" in [f["code"] for f in plan([S("A", D(2026, 2, 5))], D(2026, 2, 2), weekend_hours=10)["findings"]])
p = plan([S("A", D(2026, 2, 5))], D(2026, 2, 2), day_start=9 * 60)
check("带 --day-start 的时钟时间", p["timetable"][0]["sessions"][1]["time"] == "10:00-10:50")
subs = read_subjects("subject;exam_date;weight;confidence;topics\n数学;2026-12-03;4,5;2;9\n")
check("分号 CSV + 十进制逗号", subs[0]["weight"] == 4.5 and subs[0]["topics"] == 9)
for bad, why in [("subject,exam_date\nA,2026-01-01\n", "缺少列"),
("subject,exam_date,weight,confidence\nA,2026-13-01,1,3\n", "日期错误"),
("subject,exam_date,weight,confidence\nA,2026-01-01,1,9\n", "信心超出范围"),
("subject,exam_date,weight,confidence\nA,2026-01-01,x,3\n", "非数字")]:
try:
read_subjects(bad); check("拒绝 " + why, False)
except InputError:
check("拒绝 " + why, True)
try:
plan([S("A", D(2026, 1, 1))], D(2026, 1, 1)); check("拒绝考试不在开始后", False)
except InputError:
check("拒绝考试不在开始后", True)
passed = sum(res)
print(f"{passed}/{len(res)} 通过")
return 0 if passed == len(res) else 1
def main():
ap = argparse.ArgumentParser(description="考试复习时间表规划器")
ap.add_argument("csv", nargs="?", help="科目 CSV")
ap.add_argument("--start", help="第一个复习日 YYYY-MM-DD(默认今天)")
ap.add_argument("--weekday-hours", type=float, default=3.0)
ap.add_argument("--weekend-hours", type=float, default=5.0)
ap.add_argument("--session-min", type=int, default=50, help="专注时段长度(默认 50)")
ap.add_argument("--break-min", type=int, default=10, help="时段间休息(默认 10)")
ap.add_argument("--rest-day", choices=DAYS, help="每周休息日")
ap.add_argument("--off", default="", help="逗号分隔的无复习日期(YYYY-MM-DD)")
ap.add_argument("--max-same", type=int, default=2, help="每天每科目最大时段数(默认 2)")
ap.add_argument("--day-start", help="第一个时段的时钟时间 HH:MM(向时间表添加时间)")
ap.add_argument("--json", action="store_true")
ap.add_argument("--self-test", action="store_true")
a = ap.parse_args()
if a.self_test:
return self_test()
if not a.csv:
ap.error("提供 CSV,或使用 --self-test")
try:
with open(a.csv, encoding="utf-8-sig") as fh:
subs = read_subjects(fh.read())
start = parse_date(a.start, "--start") if a.start else dt.date.today()
off = {parse_date(x, "--off") for x in a.off.split(",") if x.strip()}
ds = None
if a.day_start:
try:
h, m = map(int, a.day_start.split(":")); assert 0 <= h < 24 and 0 <= m < 60
except Exception:
raise InputError("--day-start 必须为 HH:MM")
ds = h * 60 + m
p = plan(subs, start, a.weekday_hours, a.weekend_hours, a.session_min, a.break_min,
DAYS.index(a.rest_day) if a.rest_day else None, off, a.max_same, ds)
except (OSError, InputError) as e:
print(f"错误:{e}", file=sys.stderr)
return 2
print(json.dumps(p, indent=2) if a.json else to_markdown(p))
return 1 if any(f["severity"] == "HIGH" for f in p["findings"]) else 0
if __name__ == "__main__":
sys.exit(main())
用法
此提示词专为 education 设计。复制上方内容并粘贴到你常用的 AI 工具中。
为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。
讨论
0 条评论