試験改訂タイムテーブルプランナー
フリーのプロンプト百科事典 Wikiprompt より
試験改訂タイムテーブルプランナー 試験日ごとの復習タイムテーブルを作成するための完全なスキル/プロンプト。エビデンスに基づく学習テクニック、Pythonプランナースクリプト、テンプレートを含む。試験の詳細を収集し、プランナーを実行し、トレードオフを修正し、人間らしい計画を提供する。
プロンプト内容保存
🌐
---
name: exam-revision-timetable-planner
description: 試験日、科目の重み付け、自信度から、日ごとの試験復習タイムテーブルを作成します。学習時間を集中セッションに分割し、苦手科目や重要科目に多くの時間を割り当て、科目を交互に配置し、各試験の前の最後の1週間は練習問題に切り替え、試験前日には時間制限付きの過去問を配置し、休息日やオフ日も尊重します。トピックごとのセッション数が少なすぎる場合や、試験が連続する場合にはフラグを立てます。--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日までの5つの大学試験とトピック数
## ワークフロー
### 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 の場合:2番目の科目の練習を最初の試験の前に移動する。計画を学生と確認する:悪い日でも実行可能か?毎晩詰め込むのではなく、余裕を残す。
### 4. 納品する
`templates/revision-plan.md` を記入する:概要テーブル、週ごとのタイムテーブル、`references/study-techniques.md` のセッションルーティン、そして自信度を再評価してスクリプトを再実行するための2つのチェックイン日。
## 結果の例
`examples/winter-exams.csv` を11月16日から、平日3時間、土曜日5時間、日曜日と11月21日をオフにした場合:25日間、50分のセッション57回(47.5時間)。有機化学(重み5、自信度2)とミクロ経済学(4、2)は15回と16回のセッション、ヨーロッパ史(3、4)は6回。各科目は練習問題で終了し、試験前日に時間制限付きの過去問があります。所見:統計学(8トピックに対して10セッション)とヨーロッパ史(6トピックに対して6セッション)はTIGHT、ヨーロッパ史とミクロ経済学は12月7日と8日にBACK_TO_BACK。
## ルール
- 学生が実際に持っている時間で計画を立てる。願望ではなく。睡眠を守る(試験前の深夜のセッションはしない)。
- すべてのセッションは想起で終了する(質問、白紙への想起、フラッシュカード)。単なる再読やハイライトではない。
- 毎週少なくとも1日の休息日または2つの半日を確保する。燃え尽き症候群は失われた1日以上のコストがかかる。
- チェックインまたは試験のたびに、壊れた計画に従うのではなく、再計画する。
- 学生の成績評価対象の課題は行わない。計画と学習方法の支援のみ。深刻なストレスやパニックの兆候が見られる場合は、学生支援または医師に相談するよう勧める。
FILE:references/study-techniques.md
# 学習テクニック
各セッション内で行うこと。エビデンスの強さ順(Dunlosky et al. 2013, "Improving Students' Learning With Effective Learning Techniques" は、練習テストと分散練習を高有用性と評価)。
## 想起練習(高)
情報を再読するのではなく、記憶から引き出す:質問に答える、白紙のページに覚えていることをすべて書く、その後ノートと照合してギャップを別の色で埋める。フラッシュカードは、めくる前に答える場合に有効。最初に間違えて、その後修正することも学習に役立つ。
## 分散学習(高)
1つの科目のセッションを1つの長いブロックではなく、多くの日に分散させる。各トピックの簡単な復習リズム:翌日、3日後、1週間後、そして試験前。タイムテーブルは科目を日をまたいで交互に配置する。各セッションは、その科目の前回のセッションの5分間の想起から始めて、分散学習を組み込む。
## 交互練習(中)
科目内で問題タイプを混ぜる(数学や科学の場合:同じものを20問ではなく、1つのセットに異なる種類の問題を含める)。これにより、試験で求められる方法の選択を練習できる。
## 過去問(試験には高)
各試験の前に、時間制限付きで少なくとも1回の完全な過去問を解く。その後、公式の採点基準で採点し、トピックごとに失点をリストアップする。スクリプトは各試験の前日に1回配置する。過去問が利用可能な場合は、さらに早い段階で追加する。
## 精緻化と自己説明(中)
「なぜこれが機能するのか?」「これはXとどう関連するのか?」と自問し、教えるように概念を声に出して説明し、記憶から概念マップを描く。
## 単独では価値が低い
再読、ハイライト、ノートの書き写しは生産的に感じられるが、長期的な効果はほとんどない。想起の前の最初のパスとしてのみ使用する。
## セッションルーティン(デフォルト50/10)
1. 5分:この科目で前回やったことを記憶から思い出す。
2. 30分:1つのトピックを学ぶか練習する(学習+想起)または問題を解く(練習問題)。
3. 10分:本を閉じて自分をテストし、間違えた箇所をマークする。
4. 5分:次回のために答えられなかった質問を3つ書き留める。
5. 10分の休憩(画面から離れて):体を動かす、水を飲む。
注意力が短い場合は、25/5セッション(`--session-min 25 --break-min 5`)を使用し、4回ごとに長い休憩を取る。
## 睡眠、食事、前日
睡眠は記憶を定着させる。徹夜は試験のパフォーマンスを低下させる。試験の前夜は軽い復習と睡眠のために確保する。規則正しい食事、毎日の運動、セッション中はスマホを別の部屋に置く。
FILE:references/scheduling-rules.md
# スケジューリングルール
`scripts/revision_plan.py` がタイムテーブルを構築する方法。
## 1日あたりのセッション数
1日の時間に収まるセッション数:`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 トピック数 | 1回のパスを受け入れる、または得意科目から時間を取る |
| BELOW_TARGET | MEDIUM | 計画 < 目標の60% | 試験が早い。その科目を最初に開始する |
| BACK_TO_BACK | MEDIUM | 試験が連続した日 | 2番目の試験の練習を前倒しする |
| SAME_DAY | MEDIUM | 1日に2つの試験 | 最後の1週間は両方を1つのブロックとして扱う |
| NO_REST_DAY | LOW | 休息日やオフ日なしで10日以上の計画 | `--rest-day` を追加 |
| LONG_DAYS | LOW | 1日8時間以上 | 5〜6時間の集中時間に制限 |
## 調整
- 特定の科目に時間を増やす:重みを上げるか、自信度を下げて再実行する。
- 科目の切り替えを減らす:`--max-same 3`。
- 時計時間:`--day-start 09:00` は、セッション間の休憩を含む開始時間と終了時間を追加する。
- 再計画:各チェックイン後、自信度と `--start` を更新して再実行する。終了した試験はCSVから削除する。
FILE:templates/revision-plan.md
# 復習計画:<名前>、<試験シーズン>
**期間:** <2026年11月16日から12月11日> **時間:** <平日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. 1つのトピックを30分学習または練習
3. 10分の自己テスト、間違いをマーク
4. 5分:次回のための未解決の質問を3つ
5. 画面から離れて10分の休憩
## 合意したトレードオフ
- <統計学はTIGHT:1回の完全なパス、2回目はトピック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
Organic Chemistry,2026-12-02,5,2,9
Statistics,2026-12-04,4,3,8
European History,2026-12-07,3,4,6
Microeconomics,2026-12-08,4,2,7
Academic English,2026-12-11,2,4,4
FILE:scripts/revision_plan.py
#!/usr/bin/env python3
"""試験復習タイムテーブルプランナー(Python 3 標準ライブラリのみ)。
試験日、重み、自信度を持つ科目のCSVを読み取り、利用可能な学習時間を集中セッションに分割し、弱い科目や重い科目に多くの時間を与え、科目を交互に配置し、試験後にその科目の新しい作業を停止し、各試験の前の最後の1週間で学習から練習問題に移行し、前日に時間制限付きの過去問を配置する日ごとのタイムテーブルを構築します。
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("セッションは15分以上、休憩は負の値にしないでください")
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 # 試験が1日の半分を占める
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"], "Past paper (timed)")); 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 = "Practice questions" if left <= 7 else ("Learn + recall" if s["planned"] < s["target"] * 0.6 else "Mixed review")
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['topics']} トピックに対して {s['planned']} セッション。時間を増やすか、優先度の低いトピックを削除するか、開始を早めてください"))
elif s["planned"] < 1.5 * s["topics"]:
findings.append(("MEDIUM", "TIGHT", f"{s['subject']}: {s['topics']} トピックに対して {s['planned']} セッションでは、2回目のパスの時間がほとんどありません"))
if s["planned"] < 0.6 * s["target"]:
findings.append(("MEDIUM", "BELOW_TARGET", f"{s['subject']}: 目標 {s['target']} セッションのうち {s['planned']} セッションが試験前に収まります"))
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])}) に連続しています。最初の試験の前に2番目の科目の練習を終えてください"))
for day, subjects in exam_days.items():
if len(subjects) > 1:
findings.append(("MEDIUM", "SAME_DAY", f"{day} に {len(subjects)} つの試験: {', '.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", "1日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['session_min']} 分のセッション {s['sessions']} 回(集中学習 {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 h of 50+10 = 3", slots_for(3, 50, 10) == 3)
check("slots: 50 min fits exactly 1", slots_for(50 / 60, 50, 10) == 1)
check("slots: under one session = 0", slots_for(0.5, 50, 10) == 0)
check("slots: 25+5 in 2 h = 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("no sessions on or after exam day", all(t["date"] < "2026-01-08" for t in p["timetable"]))
check("day before exam starts with past paper", p["timetable"][-1]["sessions"][0]["kind"] == "Past paper (timed)")
check("practice questions in last 7 days", all(x["kind"] != "Learn + recall" for t in p["timetable"] for x in t["sessions"]))
subs = [S("Weak", D(2026, 3, 1), w=3, c=1), S("Strong", 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("weak subject gets more sessions", pl["Weak"] > 3 * pl["Strong"])
check("priority = weight x (6 - confidence)", 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("max 2 sessions of one subject per day", all(
sum(1 for x in t["sessions"] if x["subject"] == subj) <= 2 for t in p["timetable"] for subj in "AB"))
check("subjects interleaved while both need time", 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("rest day empty", 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 day empty", 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("exam day: half the slots, other subject only", 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 and 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("clock times with --day-start", p["timetable"][0]["sessions"][1]["time"] == "10:00-10:50")
subs = read_subjects("subject;exam_date;weight;confidence;topics\nMaths;2026-12-03;4,5;2;9\n")
check("semicolon CSV + decimal comma", subs[0]["weight"] == 4.5 and subs[0]["topics"] == 9)
for bad, why in [("subject,exam_date\nA,2026-01-01\n", "missing columns"),
("subject,exam_date,weight,confidence\nA,2026-13-01,1,3\n", "bad date"),
("subject,exam_date,weight,confidence\nA,2026-01-01,1,9\n", "confidence out of range"),
("subject,exam_date,weight,confidence\nA,2026-01-01,x,3\n", "non-number")]:
try:
read_subjects(bad); check("rejects " + why, False)
except InputError:
check("rejects " + why, True)
try:
plan([S("A", D(2026, 1, 1))], D(2026, 1, 1)); check("rejects exam not after start", False)
except InputError:
check("rejects exam not after start", True)
passed = sum(res)
print(f"{passed}/{len(res)} passed")
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="1日あたりの同一科目の最大セッション数(デフォルト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 件のコメント