058 交換する魔法 — 5段階で作るPyxel教材

撃った火球を、すぐ相手が撃ち返せる。それでも今、渡す？
最終05は原作A「大技を持たせない」の通常規則を遊べる独立プログラムです。
01〜03は意図的な実験台。04で1往復、05で正確な予告とUndoを完成させます。
詳しい順序・コードの読み方・実験・原作との差はLESSON.mdへ。

共通条件
・Python 3.11以上（3.10以下を対象にしません）
・Pyxel 2.9.9。requirements.txtはpyxel==2.9.9に固定
・通常のGUI起動には画面が使えるデスクトップ環境が必要
・外部画像、追加の日本語フォント、音声ファイルは不要
・各01〜05.pyは1本だけ別フォルダーへ移しても動く。相互importなし
・ゲーム画面は標準ASCII。説明・コードコメントは日本語
・追加インストールは利用者の環境で行う準備手順です。制作検証では既存環境を使いました

Windows（PowerShell）
1. 教材フォルダーを展開する。日本語・空白を含む場所も指定できます。
2. PowerShellでそのフォルダーへ移動する。例: cd "C:\Users\あなた\Downloads\交換する魔法"
3. py -3 --version を実行して3.11以上か確認する。
4. py -3 -m venv .venv
5. .\.venv\Scripts\python.exe -m pip install -r requirements.txt
6. .\.venv\Scripts\python.exe -B 01_fire.py
仮想環境のactivateは不要。PowerShellの実行ポリシー変更も不要です。
次へ進むときは最後の名前を02_effects.py等へ替えます。

macOS（ターミナル）
1. cd "$HOME/Downloads/交換する魔法" （展開先に合わせる）
2. python3 --version （3.11以上か確認）
3. python3 -m venv .venv
4. ./.venv/bin/python -m pip install -r requirements.txt
5. ./.venv/bin/python -B 01_fire.py

Linux（端末）
1. cd "$HOME/Downloads/交換する魔法" （展開先に合わせる）
2. python3 --version （3.11以上か確認）
3. python3 -m venv .venv
4. ./.venv/bin/python -m pip install -r requirements.txt
5. ./.venv/bin/python -B 01_fire.py
通常起動はデスクトップのある端末で行います。SSH等の画面なし環境では下記headless検証を使います。

この教材内のpythonコマンド表記
LESSON.mdとlessons.jsonの「python -B ファイル名」は、上の仮想環境pythonに
読み替えてください。仮想環境をactivate済みならそのまま実行できます。
-Bは.pycを作らない指定です。ゲーム規則には影響しません。

順に起動
01_fire.py       火球だけでHPを減らす
02_effects.py    4効果と防壁の期限を手動で観察する
03_transfer.py   使った同じ札を相手の手へ移す
04_round.py      敵Aの判断と勝利・敗北・12往復を組み立てる
05_forecast.py   1往復予告と丸ごとUndoで完成させる
各段階は前のファイルを読み込みません。途中段階だけでも実行できます。

操作
全段階: R=初期化、Esc=終了。キーは1回ごとに離してください。
01: 1=火球
02/03: 1=火球、2=火花、3=防壁、4=手当。現在のACTORが所有する札のみ。
       Tab=手動の行動者PLAYER/ENEMYを切り替える。自動交代しません。
04: 1〜4=自分の所有札を使う。敵の反応まで1回で処理。
05: 04の操作 + 左右=自分の手札の予告選択、Space/Enter=選択札を使う、X=一往復戻す。
数字は固定の札番号であり、手札の左から何枚目という意味ではありません。
画面の1〜4は、プログラムの固有ID 0〜3に対応します。
05の勝ち方例: 2 → 1 → 2 → 1。自HP3、敵HP0、4往復で勝利。

意図的に省いたもの
最終版の対象は原作Aのみ。B/Cの配分と敵AI、固定所有権比較、タイトル画面、
一時停止、アニメーション、原作の記録・再生形式、ソルバー、日本語字形は含めません。
02は自HP5/最大7・敵HP6、手札は自=防壁/手当、敵=火球/火花に変更しています。
02/03は手動の効果実験で、HP0でも行動でき、勝敗も12往復制限もありません。
これは原作の対戦規則ではありません。04/05では原作Aの終局規則になります。
01の発射札は消費しません。02の所有権は固定。03以降は必ず相手へ渡します。
LESSON.mdとlesson_meta.jsonに軸ごとの比較表があります。

困ったとき
・python/pyが見つからない: Python公式配布の3.11以上を用意し、端末を開き直す。
  既存環境があるなら、そのPython実行ファイルを指定する。
・No module named pyxel: 実行に使う同じ.venvのpythonでpip installを行う。
  OS共通のpythonへ入れても、この.venvからは見えないことがあります。
・venv/ensurepipが使えない: Linuxでは配布元のPython仮想環境サポートが必要な場合があります。
  OSの公式手順を確認し、管理されたPCでは管理者に相談してください。
・Failed to initialize/window/displayエラー: 通常GUIは画面の使えるデスクトップから起動する。
  headlessなら動いた、という結果だけではGUIを検証したことにはなりません。
・音声ドライバーの警告: ゲームは無音設計です。今回のLinux自動検証はdummy audioで実施。
・押しても動かない: その札のOWNERとACTORを確認。押しっぱなし・同時押しは連打しません。
  02/03ではTab後も一度キーを離す。04/05は終局後ならR、05ならXで戻せます。
・03で札が1枚対3枚: 片側だけ使った途中状態では正常です。相手が使うと2枚対2枚に戻ります。
  04/05で自分が敵を倒した直後も、反撃しないので1枚対3枚が正常です。
・スクリーンショットの出力先: --screenshot/--reportの親フォルダーを先に作ってください。
  相対パスはコマンドを呼び出したCWD基準。ゲームのフォルダーへ勝手に保存しません。
・原作比較ツールの--source: 原作058フォルダーが手元にある場合だけ使います。
  普通の教材テストやゲーム起動には原作フォルダーは要りません。

検証コマンド（教材フォルダーで）
python -B -m unittest -v test_stages.py
python -B tools/render_qa.py
python -B 05_forecast.py --headless-replay 2121 --screenshot qa/try.png --report qa/try.json
python -B tools/check_freeze.py
headlessの操作文字: 1〜4=札、T=Tab、L/G=左右、S/E=Space/Enter、X=Undo、R=初期化。
段階にない操作文字は拒否します。--headless-smokeなら入力なしの初期画面になります。
--headless-smokeと--headless-replayは同時に使いません。
出力は実PyxelのdrawによるPNGと、明示UTF-8のJSONです。OSの実キーを押す試験ではありません。
QA.txt、qa/render_runs.json、qa/isolation_runs.json、qa/canonical_comparison.jsonに実測結果。

ライセンスと限界
LICENSEは原作MITを全文保持し、全Pythonにも同じ許諾文をコメントで保持しています。
原文のNoto字形例外文も保存していますが、本教材はNoto字形・フォントを同梱していません。
Pyxelは別途インストールする外部依存です。
検証はcloud Linux / Python 3.12.14 / Pyxel 2.9.9。Python 3.11そのもの、
Windows/macOS実機GUI、人間の試遊、OSネイティブ入力、ブラウザ、音声評価は未検証です。
原作側の35テストと既存/新規デモの結果は、教材側のテスト数へ合算していません。
