From d96535376eaec0ec6058802a476829347ad68ab8 Mon Sep 17 00:00:00 2001 From: August Chao Date: Wed, 10 Jun 2026 23:28:19 +0800 Subject: [PATCH] Replace 0611 drill with staged sort-performance lab (timeit + TDD) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 0611-sort-lab.md:四階段專題(timeit 飾詞 → bubble/quick/merge 排序評估 → 加速實驗(Cython/演算法優化)→ matplotlib 實驗圖表) - 新增 0611-sort-starter/:test_timing.py、test_sorts.py 紅燈骨架 - 每階段強制 test:(紅)→ feat:(綠)commit,共八個,納入作業成績 - 移除舊 0611-starter(進位計數);0611-solo-drill.md 保留為備用教案, 改為自行建立工作目錄 - 更新 week-16 README 與 in_class/README 的 6/11 連結與時程(6/17 前補完) Co-Authored-By: Claude Fable 5 --- weeks/week-16/README.md | 12 +- weeks/week-16/in_class/0611-solo-drill.md | 10 +- weeks/week-16/in_class/0611-sort-lab.md | 157 ++++++++++++++++++ .../in_class/0611-sort-starter/README.md | 54 ++++++ .../in_class/0611-sort-starter/test_sorts.py | 45 +++++ .../in_class/0611-sort-starter/test_timing.py | 36 ++++ weeks/week-16/in_class/0611-starter/README.md | 45 ----- .../0611-starter/test_carry_counter.py | 33 ---- weeks/week-16/in_class/README.md | 5 +- 9 files changed, 309 insertions(+), 88 deletions(-) create mode 100644 weeks/week-16/in_class/0611-sort-lab.md create mode 100644 weeks/week-16/in_class/0611-sort-starter/README.md create mode 100644 weeks/week-16/in_class/0611-sort-starter/test_sorts.py create mode 100644 weeks/week-16/in_class/0611-sort-starter/test_timing.py delete mode 100644 weeks/week-16/in_class/0611-starter/README.md delete mode 100644 weeks/week-16/in_class/0611-starter/test_carry_counter.py diff --git a/weeks/week-16/README.md b/weeks/week-16/README.md index 861dc2a70..2b0ae289d 100644 --- a/weeks/week-16/README.md +++ b/weeks/week-16/README.md @@ -1,10 +1,10 @@ # Week 16(115/06/08-115/06/14) - 主題:**TDD + Git PR 加壓演練週**(期末上機考倒數第二個練習週) -- 課堂範例:[`in_class/`](./in_class/) — 6/10 計時演練、6/11 獨立演練 +- 課堂範例:[`in_class/`](./in_class/) — 6/10 計時演練、6/11 排序效能專題 - 解題:本週無 `QUESTION-*.md` -- 作業:依 6/10、6/11 課堂教案完成 PR,**兩天都必須附 `AI_LOG.md`** -- 備註:6/12(五)生成式 AI 論壇,本週除兩個課堂 PR 外無額外作業 +- 作業:依 6/10、6/11 課堂教案完成 PR,**兩天都必須附 `AI_LOG.md`**;6/11 專題的 Stage 3–4 課後完成,**6/17(三)前補進同一個 PR** +- 備註:6/12(五)生成式 AI 論壇 --- @@ -28,10 +28,10 @@ TDD 原則不變:**先測試(紅燈)→ 再實作(綠燈)**,commit | 日期 | 教案 | 題目 | 是否評分 | |------|------|------|---------| | 6/10 (三) | [0610-timed-drill.md](./in_class/0610-timed-drill.md) | 數字根(UVA 11332 簡化版) | 不評分,記錄是否準時開出 PR | -| 6/11 (四) | [0611-solo-drill.md](./in_class/0611-solo-drill.md) | 進位計數(UVA 10035 簡化版) | 不評分,記錄 PR 與 AI_LOG 完整度 | +| 6/11 (四) | [0611-sort-lab.md](./in_class/0611-sort-lab.md) | 排序效能實驗室(timeit 裝飾器、三種排序、加速、視覺化) | **納入作業成績**(評分表見教案) | -> 本週兩題均進入期末考 **B 區候選池(不公開)**。 -> B 區範圍是 6/3 ~ 6/18 的週三、週四課堂題——**缺這兩堂,B 區就少一半。** +> 6/10 題目進入期末考 **B 區候選池(不公開)**;6/11 專題的 timeit 與排序屬 in-class 範圍。 +> B 區範圍是 6/3 ~ 6/18 的週三、週四課堂題——**缺課,B 區就少一塊。** --- diff --git a/weeks/week-16/in_class/0611-solo-drill.md b/weeks/week-16/in_class/0611-solo-drill.md index 244348f61..daf7d0ca7 100644 --- a/weeks/week-16/in_class/0611-solo-drill.md +++ b/weeks/week-16/in_class/0611-solo-drill.md @@ -85,8 +85,14 @@ PR 開出後,先**不翻文件**回答這五題(答得出來=考場上不 --- -## starter 檔 +## 工作目錄 + +本教案不提供 starter,自己建立(這也是考場上的第一步): ```bash -cp -r weeks/week-16/in_class/0611-starter weeks/week-16/solutions/<學號>/0611 +mkdir -p weeks/week-16/solutions/<學號>/0611-carry +cd weeks/week-16/solutions/<學號>/0611-carry ``` + +從空的 `test_carry_counter.py` 開始:先補 ≥3 個 test case(含 edge case 與例外案例)、 +跑紅燈、commit,再建立 `carry_counter.py`。 diff --git a/weeks/week-16/in_class/0611-sort-lab.md b/weeks/week-16/in_class/0611-sort-lab.md new file mode 100644 index 000000000..484c6d72b --- /dev/null +++ b/weeks/week-16/in_class/0611-sort-lab.md @@ -0,0 +1,157 @@ +# 6/11 (四)|分階段專題:排序效能實驗室 + +> 把 Week 10 的 `@timeit` 裝飾器、Week 13 的視覺化、Week 14-15 的 TDD + PR 流程, +> 整合成一個完整的小專題。**每個階段都要先紅燈再綠燈,commit 順序就是你的開發證據。** + +## 學習目標 + +- 用 TDD 開發一個可被測試的 `@timeit` 計時裝飾器 +- 實作 bubble / quick / merge 三種排序,並用自己的裝飾器量測效能 +- 設計至少一種加速方案(Cython 化或演算法優化),用數據證明有效 +- 把實驗結果畫成圖,寫出可信的效能報告 + +--- + +## 專題總覽(四個階段) + +| 階段 | 產出 | 紅燈 commit | 綠燈 commit | +|------|------|------------|------------| +| 1 | `timing.py` — `@timeit` 裝飾器 | `test: stage1 timeit 裝飾器測試` | `feat: stage1 實作 timeit 裝飾器` | +| 2 | `sorts.py` + `benchmark.py` — 三種排序與量測 | `test: stage2 排序正確性測試` | `feat: stage2 實作三種排序與 benchmark` | +| 3 | 加速版排序(Cython 或演算法優化) | `test: stage3 加速版共用正確性測試` | `feat: stage3 加速版與量測數據` | +| 4 | `plot.py` + `assets/benchmark.png` | `test: stage4 繪圖輸出測試` | `feat: stage4 實驗結果圖表與報告` | + +`git log --reverse` 必須能看到 **test → feat 交替出現八次**(可穿插 `refactor:`)。 +任何一個階段「一開始就綠」或「先 feat 後 test」,該階段流程分 0 分。 + +--- + +## Stage 1|`@timeit` 裝飾器(課堂 0:00–0:25) + +寫 `timing.py`,提供裝飾器 `timeit`,規格: + +- 被裝飾函式的**回傳值不變** +- 用 `functools.wraps` 保留 `__name__` / `__doc__` +- 每次呼叫後,把耗時(秒,`float`)記錄在: + - `f.last_elapsed` — 最近一次的耗時 + - `f.records` — 歷次耗時的 list(累積) +- 裝飾器內**不准 `print`**——輸出格式化是 benchmark 的事,計時器保持安靜才能被重複利用 + +> 設計提示:`last_elapsed` 和 `records` 掛在 wrapper 函式物件上。 +> 想想看:為什麼掛在 wrapper 上而不是用全域變數?(這題會出現在課末檢測) + +**必備 test case(≥3)**:回傳值不變、`__name__` 保留、呼叫後 `last_elapsed > 0` 且 `records` 長度遞增。 + +## Stage 2|三種排序 + 量測(課堂 0:25–1:10) + +寫 `sorts.py`,三個函式簽名固定: + +```python +def bubble_sort(data: list) -> list: ... +def quick_sort(data: list) -> list: ... +def merge_sort(data: list) -> list: ... +``` + +- 一律**回傳新的 list,不可修改傳入的 list**(測試會驗) +- **禁用** `sorted()` / `list.sort()`——那是 Stage 3 的對照組 + +**必備 test case(每個函式都要過)**:空 list、單元素、含重複值、反向排序、隨機資料與 `sorted()` 結果比對、原 list 未被修改。 +三個函式共用同一組測試——用迴圈 + `subTest`,不要複製貼上三份。 + +接著寫 `benchmark.py`: + +```python +def make_data(n: int, seed: int = 42) -> list: ... # 固定 seed,實驗可重現 +def run_benchmark(sizes=(500, 1000, 2000, 4000), repeats=3) -> dict: ... +``` + +- 用你自己的 `@timeit` 量測,每個 n 重複 `repeats` 次取 `records` 平均 +- `python benchmark.py` 印出比較表,並把結果存成 `results.json`(Stage 4 的輸入) + +## Stage 3|加速實驗(課後) + +1. **必做**:把內建 `sorted()`(Timsort,C 實作)加入 benchmark 當 baseline +2. **至少一種加速方案**,自選: + - **Cython 化**:把任一排序改寫成 `sorts_fast.pyx`(加上 `cdef` 型別註記), + 用 `pip install cython` + `setup.py build_ext --inplace` 或 `pyximport` 編譯 + - **演算法優化**:bubble 提前停止、quick 改 median-of-three、小區間切換插入排序等 +3. 加速版**必須通過 Stage 2 同一組正確性測試**(把被測函式做成參數,別再寫一份測試) +4. 加速前後的數據都要進 `results.json`,報告要寫出加速比(例:`bubble 4000 筆:2.31s → 0.18s,12.8x`) + +> ⚠️ Cython 編譯產物 `build/`、`*.c`、`*.so` **不准 commit**——只交 `.pyx` 原始碼與編譯指令說明。 + +## Stage 4|畫圖與報告(課後) + +寫 `plot.py`: + +```python +def load_results(path: str) -> dict: ... +def plot_results(results: dict, out_path: str) -> None: ... +``` + +- 折線圖:x 軸 = 資料量 n,y 軸 = 平均秒數(**y 軸用 log scale**,不然 O(n²) 會把其他線壓扁) +- 每個演算法一條線(含 baseline 與加速版),輸出 `assets/benchmark.png` +- 測試提示:用 `tempfile` 驗證 PNG 有產生且大小 > 0;`plot.py` 開頭加 `matplotlib.use("Agg")` 才能在無視窗環境(含 CI)跑 +- 在你的 `README.md` 貼圖並用 2–3 句解讀:誰最快?O(n²) 和 O(n log n) 的線斜率差在哪?加速比多少? + +--- + +## 時程與繳交 + +| 時間 | 內容 | +|------|------| +| 6/11 課堂(90 分鐘) | Stage 1、2 完成並 push;**下課前開出 PR**(之後同分支繼續 push) | +| 課後 | Stage 3、4 | +| **6/17(三)前** | PR 補完全部四階段,完成最終版 | + +- 分支:`feature/wk16-0611-<學號>`,PR 標題 `Week 16 - <學號> - <姓名>` +- 所有檔案只能放在 `weeks/week-16/solutions/<學號>/0611/`(CI 會檢查) + +### 繳交內容清單 + +``` +weeks/week-16/solutions/<學號>/0611/ +├── timing.py test_timing.py +├── sorts.py test_sorts.py +├── benchmark.py results.json +├── sorts_fast.pyx(或演算法優化版) +├── plot.py test_plot.py +├── assets/benchmark.png +├── README.md # 實驗報告:方法、數據表、圖、解讀、加速比 +├── AI_LOG.md # 提示詞逐字記錄(規則同 6/10) +└── TEST_LOG.md # 每階段至少一紅一綠的 unittest 輸出 +``` + +### 評分(納入作業成績) + +| 項目 | 配分 | +|------|------| +| Stage 1 timeit 正確 + 測試完整 | 15 | +| Stage 2 三排序正確 + 共用測試 + benchmark 可重現 | 25 | +| Stage 3 加速有效 + 通過共用測試 + 數據佐證 | 10 | +| Stage 4 圖表正確 + 解讀合理 | 10 | +| Code Style(命名、繁中註解、無重複測試碼) | 20 | +| 報告與紀錄(README / AI_LOG / TEST_LOG / commit 順序) | 20 | + +--- + +## 課末自我檢測(不翻文件回答) + +1. `last_elapsed` 為什麼掛在 wrapper 上,不用全域變數? +2. 為什麼測試要驗「原 list 未被修改」?哪個排序最容易不小心改到? +3. benchmark 為什麼要固定 seed、重複多次取平均? +4. 你的加速方案如果只跑 n=500 看不出差異,該怎麼設計實驗? +5. 八個 commit 的順序是什麼?哪一種順序會直接 0 流程分? + +--- + +## AI 使用規則(同 6/10) + +提示詞自己打、逐字記入 `AI_LOG.md`;「我改了什麼」0 字 = 期末考此項 0 分。 +AI 給的測試齊不齊、排序對不對、圖正不正確——**你自己驗收**,驗收標準寫進 AI_LOG。 + +## starter 檔 + +```bash +cp -r weeks/week-16/in_class/0611-sort-starter weeks/week-16/solutions/<學號>/0611 +``` diff --git a/weeks/week-16/in_class/0611-sort-starter/README.md b/weeks/week-16/in_class/0611-sort-starter/README.md new file mode 100644 index 000000000..d2ac88ad4 --- /dev/null +++ b/weeks/week-16/in_class/0611-sort-starter/README.md @@ -0,0 +1,54 @@ +# 6/11 Starter — 排序效能實驗室 + +## 使用方式 + +```bash +cp -r weeks/week-16/in_class/0611-sort-starter weeks/week-16/solutions/<學號>/0611 +cd weeks/week-16/solutions/<學號>/0611 +``` + +## 檔案說明 + +- `test_timing.py`:Stage 1 測試骨架,**先補齊測試、跑紅燈、commit,再寫 `timing.py`** +- `test_sorts.py`:Stage 2 測試骨架,三種排序共用同一組測試(用 `subTest`) +- 其餘檔案(`timing.py`、`sorts.py`、`benchmark.py`、`plot.py`…)都是**紅燈 commit 之後**才建立 +- 完成後追加 `AI_LOG.md`(範本見 [`week-15/in_class/ai-log-template.md`](../../../week-15/in_class/ai-log-template.md))與 `TEST_LOG.md` + +## 規格速查 + +### Stage 1 `timing.py` + +```python +def timeit(func): ... +``` + +- 回傳值不變;`functools.wraps` 保留 metadata +- `f.last_elapsed`:最近一次耗時(float 秒);`f.records`:歷次耗時 list +- 裝飾器內不准 `print` + +### Stage 2 `sorts.py` + `benchmark.py` + +```python +def bubble_sort(data: list) -> list: ... +def quick_sort(data: list) -> list: ... +def merge_sort(data: list) -> list: ... + +def make_data(n: int, seed: int = 42) -> list: ... +def run_benchmark(sizes=(500, 1000, 2000, 4000), repeats=3) -> dict: ... +``` + +- 排序一律回傳新 list、不可改動輸入;禁用 `sorted()` / `list.sort()` +- 函式名、簽名都不能改,否則測試 import 會失敗 +- `python benchmark.py` 要印出比較表並產生 `results.json` + +### Stage 3 / Stage 4 + +見 [`../0611-sort-lab.md`](../0611-sort-lab.md):加入 `sorted()` baseline、 +至少一種加速方案(Cython 或演算法優化)、`plot.py` 畫圖輸出 `assets/benchmark.png`。 + +## 本日規則 + +- [ ] 每階段先紅燈 commit(`test:`)再綠燈 commit(`feat:`),共八個 commit +- [ ] AI 提示詞自己打,逐字記入 `AI_LOG.md` +- [ ] 課堂結束前完成 Stage 1–2 並開出 PR;Stage 3–4 同分支補 push,6/17(三)前完成 +- [ ] Cython 編譯產物(`build/`、`*.c`、`*.so`)不准 commit diff --git a/weeks/week-16/in_class/0611-sort-starter/test_sorts.py b/weeks/week-16/in_class/0611-sort-starter/test_sorts.py new file mode 100644 index 000000000..4456a8602 --- /dev/null +++ b/weeks/week-16/in_class/0611-sort-starter/test_sorts.py @@ -0,0 +1,45 @@ +"""Stage 2 — 排序正確性測試骨架 + +規格:sorts.py 的 bubble_sort / quick_sort / merge_sort 必須 + 1. 回傳新的排序後 list,不可修改傳入的 list + 2. 禁用內建 sorted() / list.sort()(那是 Stage 3 的對照組) + +設計要求:三個函式共用同一組測試——用迴圈 + subTest,不要複製貼上三份。 + +待辦: + 1. 自己打提示詞跟 AI 討論,補齊測試: + 空 list、單元素、重複值、反向、隨機資料比對、原 list 未被修改 + 2. 跑 `python -m unittest` 確認全紅 + 3. commit: "test: stage2 排序正確性測試" + 4. 寫 sorts.py,全綠後 commit: "feat: stage2 實作三種排序與 benchmark" +""" + +import unittest + +# from sorts import bubble_sort, quick_sort, merge_sort # 完成 sorts.py 後解除註解 + +# 提示:把三個排序函式放進一個 list,每個測試用 +# for sort_fn in SORT_FUNCTIONS: +# with self.subTest(sort_fn.__name__): +# ... +# Stage 3 的加速版只要 append 進這個 list 就能吃到同一組測試。 +SORT_FUNCTIONS = [] # 解除上面 import 後填入 + + +class TestSortFunctions(unittest.TestCase): + def test_basic_cases(self): + # 提示:空 list、單元素、重複值、反向排序 + self.fail("尚未實作 — 自己打提示詞跟 AI 討論後補上") + + def test_random_data_matches_builtin(self): + # 提示:random.seed 固定後產生資料,結果與 sorted() 比對 + # (測試裡可以用 sorted() 當「驗證標準」,被測函式裡不行) + self.fail("尚未實作") + + def test_input_not_mutated(self): + # 提示:排序前先複製一份,排序後驗證原 list 沒變 + self.fail("尚未實作") + + +if __name__ == "__main__": + unittest.main() diff --git a/weeks/week-16/in_class/0611-sort-starter/test_timing.py b/weeks/week-16/in_class/0611-sort-starter/test_timing.py new file mode 100644 index 000000000..219877f93 --- /dev/null +++ b/weeks/week-16/in_class/0611-sort-starter/test_timing.py @@ -0,0 +1,36 @@ +"""Stage 1 — @timeit 裝飾器測試骨架 + +規格:timing.py 的 timeit 裝飾器必須 + 1. 不改變被裝飾函式的回傳值 + 2. 用 functools.wraps 保留 __name__ / __doc__ + 3. 每次呼叫後更新 f.last_elapsed(float 秒)並 append 到 f.records + 4. 裝飾器內不准 print + +待辦: + 1. 自己打提示詞跟 AI 討論,補齊下面三個測試(可再加) + 2. 跑 `python -m unittest` 確認全紅 + 3. commit: "test: stage1 timeit 裝飾器測試" + 4. 寫 timing.py,全綠後 commit: "feat: stage1 實作 timeit 裝飾器" +""" + +import unittest + +# from timing import timeit # 完成 timing.py 後解除註解 + + +class TestTimeit(unittest.TestCase): + def test_returns_original_result(self): + # 提示:裝飾一個簡單函式(例如回傳 a + b),驗證回傳值不變 + self.fail("尚未實作 — 自己打提示詞跟 AI 討論後補上") + + def test_preserves_function_metadata(self): + # 提示:驗證 __name__ 不是 'wrapper' + self.fail("尚未實作") + + def test_records_elapsed_time(self): + # 提示:呼叫兩次,驗證 last_elapsed > 0 且 records 長度為 2 + self.fail("尚未實作") + + +if __name__ == "__main__": + unittest.main() diff --git a/weeks/week-16/in_class/0611-starter/README.md b/weeks/week-16/in_class/0611-starter/README.md deleted file mode 100644 index 463fb925c..000000000 --- a/weeks/week-16/in_class/0611-starter/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# 6/11 Starter — 進位計數 - -## 使用方式 - -```bash -cp -r weeks/week-16/in_class/0611-starter weeks/week-16/solutions/<學號>/0611 -cd weeks/week-16/solutions/<學號>/0611 -``` - -## 檔案說明 - -- `test_carry_counter.py`:測試骨架,**請先補 ≥3 個 test case**(含 edge case 與例外案例) -- `carry_counter.py`:實作檔(尚未建立)。測試紅燈 commit 之後再建立,內容見下方規格。 -- 完成後追加 `AI_LOG.md`(範本見 [`week-15/in_class/ai-log-template.md`](../../../week-15/in_class/ai-log-template.md)) - -## `carry_counter.py` 要寫什麼 - -這個檔案只需要一個函式,規格如下: - -```python -def count_carries(a: int, b: int) -> int: - ... -``` - -- **行為**:回傳直式計算 `a + b` 時發生進位的次數。 - 例:`555 + 555`,個位 `5+5=10` 進位、十位 `5+5+1=11` 進位、百位 `5+5+1=11` 進位, - 所以 `count_carries(555, 555)` 回傳 `3`。注意前一位的進位會影響下一位(`999 + 1` 是 3 次)。 -- **輸入範圍**:非負整數 `a`, `b`(0 ≤ a, b < 10,000,000,000)。 -- **例外**:`a` 或 `b` 為負數時必須 `raise ValueError("operands must be non-negative")`——訊息文字要一字不差,測試會比對。 -- **不需要** `input()` / `print()`:這題只考核心函式,測試會直接 import 來呼叫。 - 檔名、函式名都不能改,否則 `test_carry_counter.py` 的 import 會失敗。 - -**完成的定義**:`python -m unittest` 從全紅變全綠,然後 commit(`feat:` 開頭)。 -AI 給的程式碼你要能解釋,並把過程記進 `AI_LOG.md`。 - -更多範例值見 [`../0611-solo-drill.md`](../0611-solo-drill.md) 的題目表格。 - -## 本日規則 - -- [ ] 不主動發檢查表;卡住可以翻(考試也是 open book),但**翻一次在補強清單記一筆** -- [ ] AI 提示詞自己打,逐字記入 `AI_LOG.md` -- [ ] 60 分鐘內開出 PR -- [ ] 課末完成五題自我檢測,補強清單回 GitHub 用 Edit 補進 PR 描述 - -詳細見 [`../0611-solo-drill.md`](../0611-solo-drill.md)。 diff --git a/weeks/week-16/in_class/0611-starter/test_carry_counter.py b/weeks/week-16/in_class/0611-starter/test_carry_counter.py deleted file mode 100644 index 0f3af6c5f..000000000 --- a/weeks/week-16/in_class/0611-starter/test_carry_counter.py +++ /dev/null @@ -1,33 +0,0 @@ -"""進位計數 — 測試骨架 - -題目:count_carries(a, b) 回傳直式計算 a + b 時發生進位的次數。 - 若 a 或 b 為負數,應 raise ValueError("operands must be non-negative")。 - -待辦: - 1. 自己打提示詞跟 AI 拆 test case,補齊至少 3 個 - - 至少 1 個 edge case(提示一個方向:進位會不會連鎖?) - - 至少 1 個例外案例 - 2. 跑 `python -m unittest` 確認全紅 - 3. commit: "test: add failing tests for carry counter" - 4. 寫 carry_counter.py,全綠後 commit: "feat: implement carry counter" - 5. 寫 AI_LOG.md(提示詞逐字記錄) -""" - -import unittest - -# from carry_counter import count_carries # 完成 carry_counter.py 後解除註解 - - -class TestCountCarries(unittest.TestCase): - def test_basic(self): - self.fail("尚未實作 — 自己打提示詞跟 AI 討論後補上") - - def test_edge_case(self): - self.fail("尚未實作") - - def test_invalid_input_raises(self): - self.fail("尚未實作") - - -if __name__ == "__main__": - unittest.main() diff --git a/weeks/week-16/in_class/README.md b/weeks/week-16/in_class/README.md index 7bfe1486f..c42508a02 100644 --- a/weeks/week-16/in_class/README.md +++ b/weeks/week-16/in_class/README.md @@ -3,7 +3,7 @@ 本週兩堂課的共同目標:**在接近期末考的壓力條件下,把 SOP 跑到不用看表也不會錯。** - 6/10 (三):[計時演練](./0610-timed-drill.md) — 60 分鐘完賽,只准看精簡版檢查表 -- 6/11 (四):[獨立演練](./0611-solo-drill.md) — 不給任何檢查表,全憑記憶 +- 6/11 (四):[排序效能實驗室・分階段專題](./0611-sort-lab.md) — 不發檢查表;課堂完成 Stage 1–2 並開 PR,Stage 3–4 課後完成(6/17 前) --- @@ -48,7 +48,8 @@ ## 相關文件 - [6/10 教案](./0610-timed-drill.md) -- [6/11 教案](./0611-solo-drill.md) +- [6/11 教案:排序效能實驗室](./0611-sort-lab.md)(starter:[`0611-sort-starter/`](./0611-sort-starter/)) +- [6/11 備用教案:進位計數獨立演練](./0611-solo-drill.md)(未排入課程,保留作考前自主練習) - [SOP 檢查表・精簡版](../../week-15/in_class/exam-sop-checklist-lite.md) - [AI_LOG 範本](../../week-15/in_class/ai-log-template.md) - [Week 15 完整版檢查表](../../week-15/in_class/README.md#期末考-sop-檢查表學生版完整版)(本週課堂上**不准看**,課後複習用)