Skip to content

區間車五型共通運用(EMU500/600/700/800/900)與開關門音效 - #17

Merged
keyang556 merged 2 commits into
mainfrom
claude/train-types-and-sounds-5fb033
Sep 9, 2026
Merged

keyang556 merged 2 commits into
mainfrom
claude/train-types-and-sounds-5fb033

Conversation

@keyang556

@keyang556 keyang556 commented Sep 9, 2026 •

Copy link
Copy Markdown
Owner

這個 PR 做什麼

  1. 把 EMU500、EMU600、EMU700、EMU800 加進系統,讓區間車與區間快由五型共通運用,車輛型式每天重抽。
  2. 補上 11 個開關門音效。

資料來源是使用者提供的四份維基百科條目(台鐵 EMU500/600/700/800 型電聯車)與一批錄音檔。

車輛型式

型式 營運速度 起動加速度 常用/緊急減速度 編組長度
EMU500 110 km/h 2.88 km/h/s 2.84/3.12 km/h/s 81.3 m(4 輛)
EMU600 110 km/h 2.88 km/h/s 2.84/3.12 km/h/s 81.3 m(4 輛)
EMU700 110 km/h 2.52 km/h/s(0~50) 2.88/3.6 km/h/s 163.3 m(8 輛)
EMU800 130 km/h 2.52 km/h/s(0~50) 4.32/4.68 km/h/s 164.3 m(8 輛)

共通運用

運用規則寫在 data/trains.json 新增的 rolling_stock_pools,程式裡不寫死任何車型或線別代碼(規格 §22)。權重=現役車輛數 × 該路段配屬倍率,由上而下第一個命中的規則生效:

規則 結果
花東線 EMU500 100%
沙崙線 / 六家線 EMU500 86%、EMU600 14%
區間快(任何線) 900 65%、800 17%、500 8%、700 8%、600 1%
區間車,經過縱貫線北段 900 54%、800 18%、500 17%、700 8%、600 3%
區間車,其他路段 800 39%、700 25%、500 19%、900 13%、600 4%

抽籤是「日期+車次」的 blake2b 雜湊(src/railway_sim/timetable/rolling_stock.py)。同一天之內固定、隔天可能不同,符合「今天這個車次和明天可能不同車型」。

為什麼是 hashlib 而不是內建 hash:後者每個行程都加鹽,用它抽籤會讓玩家同一天重開遊戲就換一台車。tests/test_rolling_stock.py::TestDeterminism::test_it_survives_a_restart 用子行程把這件事鎖住。

timetables.json 沒有改動,裡面原本的 EMU900 現在只是「這班屬於運用池」的標記。內灣線柴客與對號列車不在 managed_rolling_stock_ids 裡,永遠不會被改派——內灣線與六家線共用 line_id,這道關卡是避免派電聯車去跑未電氣化區間的關鍵。

車次選單、行前提要與駕駛畫面都問同一個函式,因此不可能各自顯示不同的車(規格 §25.5)。

開關門音效

新增 11 個音檔:EMU500/700/800、PP、普悠瑪的開門與關門,以及 EMU3000 的關門。

審閱時值得看的兩個判斷

  • EMU600 的減速度單位,來源印錯了。 條目寫「常用制軔 0.79 km/h/s」,照字面從 110 km/h 煞停要 139 秒、超過兩公里,任何車站都停不進去。同一組數字當成 m/s² 恰好等於同級的 EMU500(2.84 km/h/s = 0.789 m/s²),因此以 m/s² 解讀,標記 derived_from_source,並在 meta.known_source_conflict_emu600 寫明理由。
  • EMU900 的現役輛數 520 是推定值(52 列 × 10 輛採購案),提供的資料裡沒有 EMU900 的條目。它只影響權重比例,已標成 test_data。有確切數字時改 fleet_cars 一格即可。

順手修掉的既有脆弱處

test_stop_point_warning_names_the_station 原本寫死 400 公尺,暗含 EMU900 等級的煞車力。加入五型混用後,抽到 EMU800 的日子就會失敗。改成由該班次實際的車推算制動距離,並把 ATP 裡的 0.7 提成具名常數 WARNING_BRAKE_RATIO。測試日期在 conftest.py 固定,整個測試套件不再依賴執行當天的日曆。

已知缺口

  • EMU600 完全沒有開關門音效,EMU3000 缺開門聲,TEMU1000/DR1000/DR3100/莒光號全缺。這幾型開關門只有文字播報。沒有拿 EMU500 的聲音頂替 EMU600,測試明確擋住這種代用;補音檔進 common/ 就會自動生效,程式不必改。
  • 不模擬重聯:EMU500/600 幹線常態兩組 8 輛、支線單組 4 輛,逐日逐班不同且無公開來源,一律以一組計。

測試

python -m pytest → 834 passed(新增 21 項)。另外把測試基準日換成 2026-07-01、2026-09-09、2026-12-25、2027-03-04、2027-08-19、2028-01-01 各跑一次完整套件,確認不會因為抽到不同車型而失敗。

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no outstanding previous finding or accepted new issue remains.

Summary

  • Defines data-driven assignment pools, route restrictions, fleet weighting, and validation.
  • Uses a process-pinned service date so menus and driving sessions retain the same assigned train across midnight.
  • Adds four train specifications and eleven door-audio assets with metadata and documentation.
  • Updates ATP-related tests to derive warning distance from the assigned train’s braking performance.
  • Both previous findings are resolved in the current code: the service day is pinned consistently, and managed services are validated for rule coverage.

區間車與區間快的車輛型式改為共通運用,並補上各型的開關門音效。

Rolling stock
- Add EMU500, EMU600, EMU700 and EMU800 to data/trains.json, with
  performance figures taken from the Wikipedia articles for each type.
- New `rolling_stock_pools` section holds the assignment rules, so no
  line or stock id is hard-coded in program code. Weights are the number
  of cars in service multiplied by a per-section factor:
  * 花東線 (taitung): EMU500 only.
  * 沙崙線 / 六家線: EMU500 and EMU600 only.
  * 區間快 and locals through 縱貫線北段: EMU900 weighted up.
  * Other locals: EMU800 and EMU700 weighted up.
- `railway_sim.timetable.rolling_stock` draws the type from a blake2b
  hash of (service day, train number). The draw is therefore stable for
  a whole day but differs between days, so a given train number is not
  permanently tied to one type. hashlib rather than the builtin hash:
  the latter is salted per process, so restarting the game mid-day would
  hand the player a different train.
- timetables.json is unchanged; its EMU900 entries now only mark a
  service as belonging to the pool. Diesel branch services and reserved
  seat trains are outside `managed_rolling_stock_ids` and never
  reassigned.
- The menu, the pre-departure briefing and the driving session all ask
  the same function, so they cannot disagree (§25.5).

EMU600's braking figures are printed in the source as km/h/s, but at
that value the train needs over two kilometres to stop from 110 km/h.
Read as m/s² they match the mechanically similar EMU500, so they are
recorded that way and the conflict is documented in
`meta.known_source_conflict_emu600`. EMU900's fleet size is an estimate
(`test_data`); no source for it was supplied.

Door audio
- Import 11 clips: open and close for EMU500/700/800, PP and TEMU2000,
  plus a close for EMU3000. EMU600 has no recording and deliberately
  gets no substitute, so it falls back to the text-only announcement.

Also
- Extract the ATP warning distance's 0.7 brake ratio into a named
  constant, and derive the expected distance in
  test_stop_point_warning_names_the_station from the session's own spec.
  The test hard-coded 400 m, which silently assumed EMU900-class brakes
  and would fail on days that drew a stronger-braking type.
- Pin the service day in conftest so the suite cannot depend on the
  calendar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@keyang556
keyang556 marked this pull request as ready for review September 9, 2026 05:13
Comment thread src/railway_sim/app.py
Comment thread src/railway_sim/data_loader.py
Two problems raised in review.

The rolling stock draw asked the clock afresh at every call site. A player
who opened the service menu before midnight and started the service after
it would drive a different type than the menu showed — different length,
different brakes, different door sounds. `pinned_service_day` now settles
the date the first time it is asked and keeps it for the rest of the run;
restarting the game picks up the new day.

Nothing checked that every service marked as pooled can actually match a
rule. An unmatched service silently keeps the type printed in the
timetable and drops out of the common pool, and the data still loads
cleanly, so a timetable update or a new service class could disable the
feature for a whole group of trains without a symptom. The loader now
names those services as data issues, and a test removes the catch-all
rule to prove the check fires.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@keyang556
keyang556 merged commit 8e11ed5 into main Sep 9, 2026
6 of 7 checks passed
@keyang556
keyang556 deleted the claude/train-types-and-sounds-5fb033 branch September 9, 2026 05:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant