まちの停電係: 独立した五段階Pyxel教材

Python 3.11以上 / Pyxel 2.9.9。手順は日本語、ゲーム内はASCII表記です。
架空の整数配分パズルであり、現実の電気工事・設備設計・蓄電池安全の助言ではありません。
ZIPをすべて展開し、このREADMEのあるフォルダで実行してください。

Windowsの起動例:
py -3 -m venv .venv
.venv\Scripts\python -m pip install -r requirements.txt
.venv\Scripts\python 01_supply.py
.venv\Scripts\python 05_undo.py

macOS/Linuxの起動例:
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python 01_supply.py
.venv/bin/python 05_undo.py

これは利用者向けの導入例です。本制作では追加インストールしていません。
Windows/macOSのネイティブGUIを実測したという意味ではありません。
各.pyは完全な単体ファイルで、実行に他の教材やassetsは必要ありません。
再配布時は各コード先頭の権利表示とLICENSE.txt、Noto通知を保持してください。

01_supply.py: 一期間の供給、必須不足、任意点灯、抑制。線容量・電池なし。
02_wires.py: 同じ一期間に幹線3・支線2の容量を追加。
03_battery.py: 原作A。充電も共有線を使い、古い電池残量から放電。
04_forecast.py: 原作ABC、全期を守れるかの有限探索と予測。
05_undo.py: 受理された期の全状態と提出した計画をXで復元。

上/下で経路、左/右で値0〜2、Space/Zで一期間確定。
Cは案だけ消去、Rは現在の状況を初期化、Escで終了。
04/05の1/2/3でA/B/C選択。05のXは結果後もUndo。
一つの操作キーを押し、すべて離してから次へ。通常同時押しは拒否します。
新しいRは待機中でも優先。確定後は数値だけ0に戻り、選択経路は維持します。
Rは状況Aへ切り替える操作ではありません。Aへは1を使います。
05の空履歴Xは原作同様にState不変・計画を0にします。

まずLESSON.mdの01から実行・説明・実コード・練習・検証済み回答を順に進めます。
lessons.jsonは五段階の機械可読本文、lesson_meta.jsonは対応と違いです。
diffs/には隣の段階への実際のコード差分があります。

重要な規則:
充電は発電・幹線・東支線を使います。放電は古い電池からBへ直接届きます。
電池容量3、各期の充電/放電各2まで。同じ期の充放電は同時にできません。
違反は一切更新しません。必須不足のある合法計画は確定でき、最後にLOSTとなります。
全期の必須不足0ならWON。任意点灯は別の加点です。
04/05の予測NOは「今の案の後で全期必須を守れない」の意味です。
考えている間は時間も電池も減りません。予告・描画はStateを書き換えません。

トラブル:
No module named pyxel: 起動と同じ.venvのpythonでrequirements.txtを導入してください。
ファイルがない: ZIP全展開後、READMEのあるディレクトリで起動してください。
操作が進まない: 画面へフォーカスし、全キーを離してから一つずつ押します。
TRUNK/EAST/GENERATION: 線容量または発電量の超過。充電も流量へ入れて計算します。
EMPTY: 古い電池が不足。FULL: 更新後に電池3超過。
SIMULTANEOUS: 充電と放電が両方非ゼロ。片方を0へ。
DEMAND: 供給が当期の必須＋任意を超過。余る分は抑制します。
LASTとPREVIEWが違う: LASTは前の操作、PREVIEWは編集中の案です。
WONなのに予測NO: TERMINALでは次の計画がないため。結果欄のWONを読みます。
画面初期化エラー: GUI/OpenGL対応環境が必要。headless合格は全PC動作保証ではありません。

検査（標準ライブラリのみ、Pyxel不要）:
python -B test_stages.py
元ゲームがなければ原作比較は明示SKIP。他のテストは実行します。
原作を指定する場合、環境変数ORIGINAL_GAME_DIRをmodel.pyのあるフォルダへ設定します。
比較は原作のコピーを読み込み、原ファイルは変更しません。

実Pyxel自動描画（Pyxelが必要）:
python -B qa/render_check.py
手動で一枚なら:
python 05_undo.py --headless-smoke --demo-checkpoint --screenshot checkpoint.png
--screenshotと--demo-checkpointは--headless-smokeと併用します。
--qa-framesは12〜600の整数だけ。デモを完了できない短い値は拒否します。
未知の引数、拡張子違い、範囲外などをPyxelのimport前に拒否します。

凍結ファイル検査:
python -B qa/verify_freeze.py
結果と実測範囲: qa/REVIEW.md / qa/results.json / qa/render-results.json。
画像は各段階の初期・チェックポイント・改名単体起動の計15枚です。
実Pyxel headless描画、合成のアプリ入力、Linux上の自動テストを確認しました。
ブラウザ、OSキーボード入力、音声、学習効果、native Windows/macOSは未検証です。
このフォルダは未公開の制作成果物です。Siteや元ゲームを変更しません。
