前回は、200万件を超えるテストが通っていても、人間が遊ぶと見つかる問題の話でした。リリース候補の1.3.0で、スマートフォンでも遊べるようになりました。
あとは遊ぶだけ、のはずでした。日付が変わった深夜1時すぎ、外部チャットにこう書いています。
むきーこれ千日手つか負けだ。むーん
最終回は、この対局から生まれたルールの話です。CPUが同じ往復を繰り返して、対局が終わらない。最初はAIの暴走を止める修正を考えました。でも、最終的に直したのはAIではなく、ルールの方でした。
※Claude Codeは、ファイルの作成やコードの実装・テストなどをAIに任せられるAnthropicの開発ツールです。今回はモデルにClaude Opus 5.5を使いました。詳しくはClaude Codeとはをご覧ください。
131ターン、左右に行ったり来たり
スマートフォンで遊んでいた対局です。TURN 131、経過6分41秒。敵の損失16枚に対して、自軍の損失は22枚。大将も軍旗もすでに取られ、盤上に残ったこちらの駒は9枚でした。
俺の少将が最後の砦なんだが司令部前にいるの多分佐官。少将で勝てるが永遠に左右行ったり来たり
総司令部の左のマスにこちらの少将、右のマスの前に敵の駒がいます。これまでの動きから、たぶん佐官です。こちらの少将なら勝てるはずの相手です。こちらの大佐や少将も敵陣の前まで攻め込んでいますが、自陣の守りは少将1枚です。状況を図にすると、次のようになります。
図では、相手を大佐として描いています。総司令部は2マスあり、敵の駒はその前を左右に1マスずつ動きます。敵の駒が横にずれるたびに、こちらの少将も総司令部の中で、その正面へ動いてふさぐしかありません。ふさがなければ、空いた方のマスへ入られます。佐官なら、占領されて負けです。
少将の手番が来たとき、敵の駒は斜め前にいるので、隣り合っていません。こちらから戦いを仕掛けることもできません。敵の駒も、少将に当たれば負けるので当たってきません。こうして、同じ往復が延々と続きました。
第1回で、初対戦の感想に「アンドゥリドゥ的な動かし方」「千日手嫌ってこちらが折れる感じ」と書きました。それが、終盤の一番大事な場所で起きたわけです。
最初に考えたのは、AIの往復を止める修正だった
外部チャットでは、まずAIの問題として話が進みました。
局所的な評価だけなら、CPUの駒にとっては「少将に当たれば負ける。左右に逃げれば生き残る」が常に最善です。だから逃げ続ける。そこで出てきた案は、直近の数手で同じ2地点を往復していて、評価も情報も変わっていないなら、その手の評価を徐々に下げる、というものでした。AIが「逃げ続けるのが一番安全だけど、永久往復は許されないから次善策を選ぶ」ようにする考え方です。
同時に、別の注意も出ていました。「同じ盤面が3回で引き分け」のような普通の千日手のルールを入れると、軍人将棋では問題があるかもしれない。盤面が同じでも、双方が持っている情報は違うからです。
実は、CPUには1.0.0の時点から、直前にいたマスへ戻る手を少し減点する仕組みが入っていました。それでも往復を選んでいます。減点しても、往復のほうが得だと評価していたことになります。
往復は、どちらにとっても合理的だった
この状況を、盤面の側から見直してみます。
こちらの少将は、敵の駒の正面へ動き続けるしかありません。ほかの手を指した瞬間に、その駒が佐官以上なら総司令部を占領されて負けです。
CPUの駒は、少将に当たる理由がありません。当たれば負けます。一方で、総司令部の前に居続ければ、少将を釘付けにできます。こちらから見て「たぶん佐官」でも、本当は占領できない駒のはったりかもしれません。それでも、動かなければ脅しは効き続けます。
つまり、どちらも自分からは崩せません。崩した側が不利になるからです。
実際に人間同士で遊ぶなら、ここで審判が「同じことを繰り返していますよ」と声をかける場面でしょう。第1回で書いたとおり、軍人将棋にはもともと第三者の審判がいます。
CPUの往復は、暴走ではなく合理的な手でした。そこで私は、AIの考え方を調整するのではなく、ルールの側で解決することにしました。足りなかったのは、この状況を扱う審判です。
この審判は、1.4.0として実装されました。実装された処理には、次の説明が書かれています。
Some positions make shuffling back and forth the rational best play for both sides (e.g. a defender must mirror an attacker in front of its headquarters, and the attacker – possibly a bluff – need not do anything else). The game would then never progress.
局面によっては、往復が双方にとって合理的な最善手になる。司令部前では守る側が攻める側に合わせて動くしかなく、攻める側(はったりかもしれない)は、それ以外に何もする必要がない。そうなると対局は進まない、という意味です。
AIを直すのではなく、審判を置いた
1.4.0で入ったのは、膠着したときに審判が介入するルールです。CPUの評価関数には手を入れていません。
- 同じ公開局面が5回目に現れたら、その反復について一度だけ審判が介入する。公開局面とは、全部の駒の番号と位置、そして手番です。
- 介入する相手は、反復に使われている相手の駒に、自分の総司令部が近い側。つまり、崩すと危ない側です。盤上の距離だけで決め、同じ距離なら両者。
- プレイヤーには「同じ局面が繰り返されています」と伝え、投了するか続行するかを一度だけ確認する。続行したあとの手に制限はない。
- CPUが介入を受けた場合は、その後、選んだ手が同じ反復に戻る場合だけ、CPU自身の評価で次に良い手に替える。
審判が見るのは公開された局面だけで、双方が何を知っているかまでは比べません。そのため、同じ局面が繰り返されても自動で引き分けにはせず、声をかけるきっかけにだけ使っています。
131ターンの対局にこのルールを当てはめると、審判が声をかける相手は少将の側、つまり私です。総司令部を脅かされていたのはこちらでした。審判は投了するか続行するかを確認するだけで、どちらが有利かは教えてくれません。追加の手番がもらえるわけでも、CPUの往復が止まるわけでもないので、膠着そのものが自動的に解けるわけではありません。
当時の私は、それまでの戦闘で分かったことから、この往復をやめればほぼ負けると見ていました。往復を続けていれば負けはしません。戦闘のない状態が160手続けば、以前からのルールで引き分けになります。ただ、負けたくないからといって、規定の手数まで往復を続けて引き分けに持ち込むのは、時間の浪費でしかありません。
残る手は、相手の動きがはったりだと賭けて、ほかの駒を援軍に呼ぶことでした。図に書いた「支援を呼ぶ」は、この賭けのことです。審判の確認は、投了するか、賭けに出るかを決める区切りになります。
この審判にも、「カンニング禁止」が効いています。判定に使うのは、駒の番号と位置、手番、公開された移動の記録だけです。駒の正体、占領できる駒かどうか、CPUの推定や評価値は使いません。第1回で書いた、駒の正体を持たない観測情報の部品の中に置いてあり、正体にはそもそも手が届きません。
もし審判が駒の正体を見て判断していたら、「審判が介入した」という事実そのものが、相手の駒のヒントになってしまいます。テストでは、敵の駒の正体を入れ替えても同じ介入になることを確認しています。
.NETのテストは36スイート、2,530,813件のチェックが通り、CPUの評価指標は1.1.1と全項目一致しました。スマートフォンでは、開発用のPixel 7 Proで、審判の確認画面が出て対局と時計が止まり、続行できることを実際のタップで確かめています。
一方で、HISTORYには正直な一文があります。1.4.0の審判は、意図的に膠着を再現するのが難しいため、実戦では経過観察とされていました。外部チャットでも、こう話していました。
昨晩の合理的膠着みたいなのは、探して作るより自然発生した方が価値ある。
その自然発生は、記事を書いている途中に来ました。二日目の夜、スマートフォンで遊んでいた対局で、審判が実際に介入しました。
TURN 137、経過4分31秒の画面です。「同じ局面が繰り返されています」と表示され、投了するか続行するかを聞かれています。続行した場合も手の選び方に制限はないことが、画面にも書かれています。
私は続行を選びました。
続行したあとの盤面です。赤枠で囲んだ2枚が、往復を続けていた駒です。こちらの総司令部の左のマスに中将、右のマスのすぐ前に敵の駒。先ほどの図と同じ形です。131ターンの対局では守りが少将でしたが、今回は中将でした。
ここで、前に書いた賭けに出ました。総司令部の前にいる駒が、占領できない駒だったら、飛行機で潰す。そう考えて、敵陣にいた飛行機を横に1マス動かしました。
次の手で、敵の駒が総司令部の右のマスに入りました。CPUの勝ち(総司令部占領)です。終局後に敵駒開示をONにすると、入ってきたのは大佐でした。はったりではありませんでした。
賭けは外れました。それでも、同じ往復を続けて引き分けを待つより、自分で決めて負けた方が納得できます。審判の確認は、その決断の区切りとして働きました。
タップのずれと、スマートフォンの使い分け
1.4.0と同じ朝、1.4.1ではスマートフォンの操作も直しました。前回、改善候補として記録してもらった、移動先を狙ったタップが外れると選択が解除される件です。
移動できないマスや駒のない場所をタップしても、選択は保つようにしました。解除されるのは、盤の外をタップしたときと、攻撃できない敵の駒をタップして観測情報を見るときです。近くの移動先へ自動で補正する案もありましたが、採用していません。Claude Codeは、誤った移動を推測で実行しないことを理由にしています。この変更はPCのクリックにも共通で、Pixel 7 Proの実機試験は45項目が通りました。
1.4.1は、私が指示して普段使いのGalaxy S26 Ultra(以下、S26)へも入れてもらいました。前回の件のあと、開発中の試験はPixel 7 Pro、S26への転送は明示的に指示したときだけ、というルールにしていたからです。
これで開発はいったん止めて、普通に遊ぶ期間に入りました。
記事を書きながら、終局後の振り返りを足した
普通に遊びながら、この記事を書き始めました。書いている途中で、いくつか改修しています。その一つが、1.5.0の終局後の「棋譜再現」と「敵駒開示」です。
終局すると、上部のボタンで1手ずつ戻ったり進んだりできます。TURN 0は初期配置です。盤の駒、両軍の損失、判明情報は、そのTURNの時点に合わせて表示され、先の情報が過去のTURNに出ることはありません。見るだけの機能なので、駒は動かせません。
局面は、新しく棋譜を保存して作っているわけではありません。初期位置と公開された着手の記録から組み立て直しています。自動テストでは、全TURNの局面と判明情報が、対局中に記録した内容と一致することを確かめました。
「敵駒開示」は、情報を隠すという原則の、私の指示による例外です。このボタンは終局後だけのもので、対局中には使えません。終局直後も裏向きのままで、ボタンをONにしたときだけ、盤上の敵駒と敵軍の損失の正体を表示します。毎回OFFから始まり、次の対局には引き継ぎません。
開示をONにして、右の中央丸にいる敵の駒をタップしたところです。観測情報は「正体不明」のままです。こちらの少佐に勝ったという記録だけでは、少佐より強い駒のどれかまでしか絞れません。開示すると、中佐でした。TURN 0まで戻せば、CPUが最初にどう並べていたかも分かります。
対局中は、見えない駒を推理するゲームです。終局後なら、自分の推理がどこまで合っていたかを答え合わせできるようになりました。
もう一つは1.5.1で、スマートフォンの縦画面の初期配置に、操作説明を常に出すようにしました。
「初期配置」の見出しのすぐ下に、「自軍の駒をタップ → 置きたいマスをタップで入れ替え」と出ます。「盤を広く表示」で下のパネルを閉じても消えません。上部のバーの高さは変えず、ロゴと見出しを詰めて場所を作ったので、盤の表示領域は変わっていません。
公開の前に残したもの
ソースを公開する前に、もう一つ確認したことがあります。駒の文字に使った筆文字フォント「KSO闘龍」は、私が購入した市販のフォントです。
Claude Codeに、使用許諾の確認と、フォント本体がどこにも混ざっていないかの監査を頼みました。許諾では、ゲームで画像として使うことは認められ、フォントそのものの組み込みや再配布は認められていません。このゲームは、フォントで描いた駒の画像を生成してコミットし、ゲームはその画像を表示するだけです。Gitの全履歴、配布用のZIP、AndroidのAPKを調べ、フォント本体は含まれていないという判定でした。
そのうえで、フォントを持っていない人のことも考えてもらいました。GitHubからソースを取得した人が、駒の画像を作り直すスクリプトを動かすと、KSO闘龍がなくて止まってしまいます。そこで、KSO闘龍がないときはWindowsの日本語フォントなどに切り替えて最後まで生成するようにしました。KSO闘龍がある環境では、作り直した33ファイルが、コミット済みの画像とバイト単位で一致することも確かめています。
外部チャットのまとめは、こうでした。
正式版は闘龍。
物好きclone民はYu Gothic。
もっと物好きなら好きなフォントへ改造。
ソースと素材のライセンスは、公開の直前まで決めていませんでした。ソースコードと、画像などの素材を同じ条件で配ってよいかは別の話だからです。最終的に、ソースコードはMIT License、自分で作った画像などはCC BY 4.0にしました。参照や改変、商用利用も含めて自由に使って構いません。ただし、名前・ロゴ・アイコンと、KSO闘龍で描いた駒の文字の画像は対象外です。複製したものを公開する場合は差し替えてもらう条件にしています。
GitHubへのpushも、この記事を書き終えるまで止めていました。記事を書くと、説明のために挙動を確かめ直すことになり、何か見つかるかもしれないからです。実際、書いている間に1.5.0と1.5.1の改修が入りました。課題が残っていても公開できる水準と判断して、1.5.1を公開版としてpushしました。
初日の作業で、どれだけ使ったか
最後に、今回使ったClaude Codeの利用量です。私の契約は、AnthropicのProプランです。
日付が変わった0時23分、1.3.0とフォントまわりの作業を終えたときの画面です。週の利用枠の44%を使っています。1.0.0ができた直後、初日の16時20分の画面では20%でした。
下の「製品別使用状況」は、週の使用量の内訳です。98%がClaude Codeでした。最初にこの欄を見たときは、外部チャットで念のため確認しています。
95%は内訳だよな?あと5%しか使えませんじゃなくて
初日の画面では、Claude Code、チャット、Coworkなど4項目の合計が100%になっていました。残りではなく内訳です。
作業の流れを並べると、次のとおりです。
| 版 | 完成 | 主な内容 |
|---|---|---|
| 1.0.0 | 初日 16:16 | 推理するCPU、思考モニター、カンニングできない構成 |
| 1.1.0 | 初日 17:53 | 対戦モードと研究モード、あそびかた、CPUの強さ |
| 1.1.1 | 初日 18:40 | 判明表示、ツールチップ(Codexが担当) |
| 1.2.0 | 初日 21:00 | プリセット、設定、効果音、暗転の修正 |
| 1.2.1 | 初日 21:40 | 鳴らない効果音の修正 |
| 1.2.2 | 初日 22:23 | 背後に届くクリックの修正 |
| 1.3.0 | 初日 23:59 | 占領できる駒がないときのルール、Android版 |
| 1.4.0 | 二日目 10:50 | 膠着の審判 |
| 1.4.1 | 二日目 11:29 | タップで選択が外れにくい操作 |
| 1.5.0 | 二日目 17:28 | 終局後の棋譜再現と敵駒開示 |
| 1.5.1 | 二日目 17:58 | 縦画面の初期配置に操作説明 |
審判がいる軍人将棋
企画の最初に、軍人将棋は1対1なのに審判が必要なゲームだ、と書きました。コンピュータなら審判の問題はなくなり、しかもコンピュータ自身が対戦相手になれる。
作ってみると、CPUは観測から駒を絞り込み、ときには「勝利確定手」で地雷に突っ込みました。人間より記憶力のいい相手に対しては、盤上の事実だけで確定した情報を画面で補いました。200万件を超えるテストが通っても、音が鳴らないことや、裏まで届くクリックは、人間が遊んで見つけました。
そして最後に出てきたのは、AIのバグではなく、双方が合理的に動いた結果の膠着でした。直したのはCPUではなく、ルールです。審判を置きました。
コンピュータが審判と対戦相手の両方を務める軍人将棋は、最後にもう一度、審判の仕事を必要としていました。
前の記事:テストは通っていた。人間が遊んで見つけたもの。Claude Codeと作る軍人将棋【第3回】
ソース一式と最新バイナリー
AF-MilitaryShogiのソース一式と、現在の公開版はGitHubから利用できます。この記事は制作当時の記録で、最新バイナリーの内容とは異なる場合があります。Android版のAPKは配布していません。
駒の文字には、昭和書体「闘龍」(KSO闘龍)を使用しています。フォント本体はリポジトリにも配布物にも含まれていません。












コメント