085 役目を交換する砦
ターン戦術 / 日本語 / Pyxel 2.9.9 + Python標準ライブラリ

兵士を動かすか。兵士を残して、役目だけを動かすか。
場所・HP・名前が変わらない役札の受け渡しを、3つの砦で試します。
基本達成は旗を6敵フェーズ守ること、または全敵撃破。速度や交換数の点はありません。

起動
Windows: Python 3を用意し、setup.batを一度実行。その後play.bat。
Linux/macOS: bash setup.sh の後、bash play.sh。
セットアップ時のPyxel取得に通信が必要。起動時の外部通信・アカウントは不要。
launch.shは制作クラウド専用。配布先はplay.sh/play.batを使います。
Windows/macOS実機は未検証。実聴・人の楽しさは未確認。

操作
矢印でマスを移動。味方のマスでZを押すと、その人が白枠で選ばれます。
Tabで移動/攻撃/交換/救起を選ぶ。対象のマスへカーソルを動かしEnterで確定。
Zは人物選択だけです。交換対象の確定にはEnterを使います。
チームで2行動。その後、敵が番号順に行動。誰が2回動いても構いません。
Spaceで残り行動を待ち、敵フェーズへ。選択・説明中に世界は進みません。
Xは一行動undo。自動の敵フェーズも、その直前の味方の一手へまとめて戻します。
Rは確認後同じ砦を最初から。1/2/3はA/B/C。H・Pは説明。
Bは確認後、同じ砦の最初から「交換なし」の比較版へ切り替えます。
M表紙、F12画像、S保存、Q/Escape終了。
遷移や確定後はすべての操作キーを一度離してください。単独操作の競合入力は無効。

規則
身体のHPは3。槍・弓・盾の役札が1枚ずつ。役交換は縦横隣接の味方同士で1行動。
交換しても名前・HP・位置は変わらず、札の効果は直ちに有効になります。
槍は隣接へ2ダメージ、盾は隣接へ1。弓は同じ行/列の2～3マスへ1。
弓の途中に壁・生きた味方・敵がいれば届きません。距離1や斜めは不可。
盾は自分と縦横隣接の味方・旗へのダメージを1減らします。斜めは対象外。
HP0は倒れた身体として残り通行可能。盾効果・攻撃・交換は停止。
そのマスが他の駒と重なっていなければ、隣の味方が1行動でHP1へ救起できます。
倒れた身体にも元の役札が残ります。役札の消滅や複製はありません。
敵はHP2、攻撃1。隣接対象の優先は旗、低HPの味方、味方番号。
対象が隣接しない場合、旗までの最短路で1マス移動。移動した番には攻撃しません。
壁と生きた駒を通れず、同距離なら上・左・下・右の順。道がなければ待機。
右欄は今すぐ敵番にした場合の同じモデルによる予測。未確定の未来2手は含みません。

候補からの調整と確かめた例
初期案は全3砦でSpace6回だけで旗HP3成功でした。Aは入門用として維持。
B: 槍の身体を(1,0)、盾の身体を(1,1)、敵1を(0,1)へ変更。
C: 槍を(2,3)、弓を(3,3)、盾を(3,2)、敵1を(1,4)へ変更。
この段落の座標はコードの0始まり。画面は1始まりのラベルです。
規則・敵HP・予算は変えず、旗のすぐ隣の敵と役の距離を公開しました。
B/Cは待つだけで3敵番目に旗が倒れます。隠れた制限や罰はありません。
A_hold: 待機6回。旗は守れるがアキが倒れます。正当な基本達成です。
A_cover: ルウとフミが役交換してから待機。アキにも盾が届き全員HP3。
B_exchange: アキへ盾を渡し、旗への攻撃0を受け、ルウの槍で敵1撃破。
B_strike: ルウの盾攻撃を2回、敵1撃破。交換なしで旗HP3。
C_relay: ルウ→フミ→アキと盾札を2回で渡し、その場の旗を守る。
C_reposition: アキを左へ動かし敵1撃破。盾の身体を旗隣へ2歩動かす。
policy_results.jsonに全入力・状態・ハッシュを保存。最短・唯一解の主張ではありません。
比較は交換できる/できないの一規則だけ。同じ交換なし策を両版で再生し全状態一致。
交換回数や全員無傷は任意の記録。優劣の得点や追加の達成条件にはしません。

検証と制作物
python -m unittest -v test_model test_ui でモデルと入力検査。テストはmediaを変更しません。
model.pyは描画から独立したState/step。controller.pyは解放待ちを毎フレーム更新。
記録は状況、ルール版、意味入力、論理行動数、初期配置、最終状態と当時のソースを保持。
自動実Pyxel描画とネイティブ入力検査は、それぞれ別のmediaフォルダです。
映像は自動入力・無音の技術資料。人の初見理解・楽しさの証拠ではありません。
動画変換は原GIFの全フレームを各1回、30fpsでMP4へ。実フレーム数はtiming_validation.json。

権利
自作コード/図形はLICENSE.txt。Pyxel全文はassets/PYXEL-LICENSE.txt。
同梱日本語字形はNoto Sans CJK由来。SIL OFL 1.1全文はassets/NOTO-LICENSE.txt。
実行時はフォント・Pillow・ffmpeg不要。tools内のフォント/動画制作補助だけがそれらを使います。
