USI (Universal Shogi Interface) の現状調査

# はじめに

将棋の GUI と AI の間でよく用いられている USI (Universal Shogi Interface) ですが、標準化機関が作成するような詳細なドキュメントは存在しません。
事実上のスタンダードである将棋所の文書で網羅されていない部分について、開発者の間でしばしば議論になることがあります。
そこで、筆者が調べた USI の利用実体についての情報を簡単にまとめます。

この文書は批評を目的としたものではありません。
パブリックな場所で USI に関する個人的な不満を述べる人が居ますが、この文書を引用してそういった主張をすることは歓迎しません。

# 仕様策定の経緯

近年の有力な将棋 AI の多くは GUI を組み込まずに、将棋所や ShogiGUI、ShogiHome などのフロントエンドと標準入出力で連携する方法を採用しています。
その際に用いられる仕様が USI と呼ばれるもので、チェスの UCI (Universal Chess Interface) を参考にトード・ロムスタッド氏によって作られました。

- [Tord Romstad - Chessprogramming wiki](https://www.chessprogramming.org/Tord_Romstad)
- [Some thoughts on computer Shogi](http://www.shogi.net/shogi-l/Archive/2007/Njan15-10.txt) ロムスタッド氏によるコンピュータ将棋に関する考察 （2007 年 1 月 15 日付）

USI を実装し、なおかつ多くの人が利用することになった最初の GUI が将棋所です。

- [将棋GUIソフト「将棋所」のページ](http://shogidokoro2.stars.ne.jp/index.html)
- [将棋所：USIプロトコルとは](http://shogidokoro2.stars.ne.jp/usi.html)

将棋所のサイトの USI プロトコルの説明はロムスタッド氏の原案を参考にしているものの、細部において原案と互換性があるわけではありません。

将棋所の登場を機に USI を利用する将棋 AI が増え、それらのほとんどは将棋所と連携して使うことを前提に作られていました。
その後、将棋所以外にも USI に対応した GUI が複数登場しました。
特に ShogiGUI は多くの人に使われていると考えられています。
しかし、 CSA プロトコルを含めた開発者向けの機能が整っているものは限られており、AI 開発者が将棋所の振る舞いを基準にする状況は長年変わっていません。

現在では、ロムスタッド氏の原案のページにアクセスできなくなっており、 WAYBACK MACHINE やその他のサイトに転載されているものしか閲覧できない状態です。
もともと原案を見ている開発者は少なく、将棋所が普及し始めた頃から将棋所の文書が事実上のスタンダードとなっていました。

# USI を実装しているソフトウェアの例

## GUI

- [ShogiHome](https://github.com/sunfish-shogi/electron-shogi)
- [将棋所](http://shogidokoro2.stars.ne.jp/)
- [ShogiGUI](http://shogigui.siganus.com/)
- [WhaleWatcher](http://garnet-alice.net/programs/whalewatcher/)
- [将棋丸](https://shogimaru.github.io/shogimaru/)
- [ShogiBoard](https://github.com/ak110/ShogiBoard)
- 将棋ブラウザQ
- USI将棋

## AI （USI エンジン）

USI エンジンの実装は数が多いので、ソースコードが公開されていて特によく使われているものを例に挙げます。

- [やねうら王](https://github.com/yaneurao/YaneuraOu)
- [DeepLearningShogi (dlshogi)](https://github.com/TadaoYamaoka/DeepLearningShogi)
- [Apery](https://github.com/HiraokaTakuya/apery)
- [技巧](https://github.com/gikou-official/Gikou)

## CLI ツール

- [usi-csa-bridge (ShogiHome)](https://www.npmjs.com/package/usi-csa-bridge)
- [usiToCsa.rb](https://ja.osdn.net/projects/shogi-server/wiki/UsiToCsa)

# 1 手目の局面で moves を書くのかどうか

GUI からエンジンに現在の局面を伝える `position` コマンドは次のように定義されています。

```
position [sfen <sfenstring> | startpos ] moves <move1> ... <movei>
```

局面といっても開始局面と現在の局面までの指し手を記述したものなので、「棋譜」に相当すると言えます。
ここで開始 1 手目のときに `<move1> ... <movei>` は 0 個になるわけですが、その前の `moves` が行末になるのか、それとも `<sfenstring>` や `startpos` が行末になるのか明言はされていません。

実際の将棋所や ShogiGUI の動作を見ると、初期局面では `position startpos` だけが送信され `moves` は含まれていません。
これは UCI を実装した [Arena](http://www.playwitharena.de/) も同じ動作でした。

# setoption は再送信可能か

将棋所の文書では `usiok` と `isready` の間に `setoption` を送信している例が示されています。
実際の将棋所の動作でもそれ以外のケースで `setoption` を送信するケースは見つけることができませんでした。

ShogiGUI の場合は検討機能利用中に「候補手の数」を変更すると、 `stop` -> `setoption name MultiPV value <VALUE>` -> `position` -> `go` の順にコマンドを送信します。
従って、 ShogiGUI の検討機能へ完全に対応するためには、 `setoption` コマンドの再送信による設定の上書きを受け入れなければなりません。

やねうら王は `setoption` の再送信による設定の上書きを受け付けているようです。

# bestmove の取り扱いに関する注意

エンジン側の実装の注意点として `stop` コマンドを受信した時の取り扱いがあります。
`stop` コマンドを受信しても、行き違いで `bestmove` を送信済みの場合があります。
従って `stop` に対して `bestmove` を応答するのではなく、あくまでも探索を中断するシグナルとして扱う必要があります。
この件は既に [stopコマンドでbestmove返すな問題 | やねうら王公式サイト](https://yaneuraou.yaneu.com/2019/04/30/stop%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A7bestmove%E8%BF%94%E3%81%99%E3%81%AA%E5%95%8F%E9%A1%8C/) で述べられています。

また、 GUI 側の注意点もあります。
予測が外れて Ponder を中断する場合、 `stop` に対して送られた `bestmove` の指し手の情報を見る必要はありません。
時間切れで終局する場合も同様です。
しかし、読み捨てたかどうかを気にせず次の `go` コマンドを送信すると、その `bestmove` を新しい `go` コマンドに対する応答だと誤認する可能性があります。
従って、 `bestmove` を受信するまで次のアクションを実行しないか、あるいは読み捨てるべき `bestmove` の件数を表すカウンタを実装する必要があります。
これもやねうら王の開発者が気づいた観点です。

# 連続対局時の振る舞い

将棋所や ShogiGUI には連続対局の機能があり、同じエンジンのプロセスを使い回して新しい対局を始めることが可能です。
そのときに送信されるコマンドが将棋所と ShogiGUI では異なります。

将棋所は `gameover` -> `isready usinewgame` を送信して新しい対局を開始します。

一方で ShogiGUI は何も送信せずに次の `position` コマンドを発行しているようです。

# エラーメッセージの送信

思考中は `info string` コマンドで任意のメッセージを送信できますが、例えば起動直後に問題が発生してもメッセージを送信して画面に表示する方法はありません。

実際に評価関数や定跡のロードに失敗した場合、やねうら王はメッセージを標準出力に送信します。
定義されているコマンドに該当しない行を出力して良いか、USI に明確な規定はありません。
エンジン側からするとエラー発生時に妥当なメッセージの送信先が他に無いため、標準出力に送信せざるを得ないでしょう。

ShogiHome ではエンジンが予期しないタイミングで終了した場合（例えば `readyok` を受信する前にプロセスが終了した場合）に最後の一行をメッセージボックス内に表示しています。

# 文字コード

USI のコマンドそのものは ASCII コードで構成されていますが、例えばエンジン名や `info string` のメッセージ部に日本語を使いたい場合、それを Shift_JIS(CP932) にするのかそれとも UTF-8 あるいは UTF-16 にするのかという問題が生じます。

将棋所と ShogiGUI が Shift_JIS を用いるためエンジン側もそれに合わせているのが実情です。
一方で ShogiHome が扱えるのは UTF-8 のみです。
今のところ文字コードの変換を実装している GUI はありません。

# 予想手を使わない Ponder

USI では `bestmove <最善手> ponder <予想手>` の形式で相手の指し手を予想した上で、 `go ponder` に対して相手番中の思考を行うことになっています。

しかし、エンジンによっては相手の手を 1 つに絞らず探索するものがあります。
むしろ、手の幅が広い局面では予想が高い確率で外れるので、相手の手を限定しない方が自然だと言えます。

将棋所の文書では次のように書かれています。

> bestmove <move1> ponder <move2>ではなく、単にbestmove <move1>だけを返し、相手の手番中に勝手に先読みするようにして下さい。

`go ponder` を受け取らずにエンジンが探索を開始するわけですが、その場合の info コマンドの扱いについては言及されていません。
ただ、 実際に相手番で `info` コマンドを送信すると、将棋所は概ね期待通りの結果を表示するようです。

# go コマンドの引数

ロムスタッド氏の文書では `go` コマンドに `nodes` や `depth` など将棋所で使っていない引数が書かれています。
将棋所ではそれらを今後採用するかどうかについて未定であるとしています。

一方で ShogiGUI は既に検討機能や解析機能で `go nodes` と `go depth` を使っています。

これらの引数も、やねうら王を含む一部のエンジンは対応しています。
エンジン側は対応していることが望ましいと言えますが、将棋所が使っていない以上は対応していないエンジンも多いと考えた方が良さそうです。

また、やねうら王では後述するように独自の拡張コマンドを受け付けていて、ロムスタッド氏の文書にも書かれていない `go rtime` や `go perft` が用意されています。

# やねうら王の独自拡張

やねうら王では独自の拡張コマンドを実装しています。

https://github.com/yaneurao/YaneuraOu/wiki/USI%E6%8B%A1%E5%BC%B5%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89

エンジンに対して送るコマンドを必要に応じて拡張できるものであり、ノーマルな USI コマンドと互換性があります。

# エンジンオプションの翻訳

これは USI そのものの仕様ではありませんが、将棋所では [エンジン設定ダイアログで日本語を表示する方法](http://shogidokoro2.stars.ne.jp/translate.html) を用意しています。
`{エンジンファイル名}_ja.txt` という名前でファイルを配置することで、エンジンオプションの日本語訳を表示することができます。
筆者が確認した限り、この機能に対応しているエンジンは技巧と LesserKai （将棋所同封版）だけです。

![スクリーンショット 2024-08-01 213523.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78005/7b2e39b6-3d37-7014-4502-3a58d9fbf433.png)

ちなみに、ShogiHome ではよく使われている名前に対する日本語訳を GUI 側で独自に持っています。

# 参考事例: 2024 年の電竜戦で発生したトラブル

第2回電竜戦ハードウェア統一戦で、エンジンから送られた USI のコマンドをパースできず対局を続行できないトラブルがありました。
電竜戦の他の大会や世界コンピュータ将棋選手権の場合は参加者が　CSA プロトコルに対応しますが、このハードウェア統一戦では USI のホストを大会側が運用していたようです。

エンジンから送られた `info` コマンドの引数のうち、 `pv` とその値が末尾ではなかったためホスト側が正常にパースできなかったようです。
USI の仕様に関して言えば `pv` が最後に書かれなければならないと明記されているので、エンジン側の間違いだと言えます。
しかし、将棋所はそのようなコマンドを受信しても致命的な影響は発生しないため、問題に気づくのは難しいと言えます。

本稿の執筆時点では USI のバリデーターとなるようなツールは出回っていません。
将棋所や ShogiGUI などの特定の GUI で動作を確認しても、寛容に読み取ってくれているだけかもしれないので、このようなトラブルを防ぐためにはそれらとは別でバリデーターを用意して検査できることが望ましいと言えます。

# 参考資料: USI の状態遷移図

USI の仕様を完全に網羅した状態遷移図を筆者は見たことがありませんが、参考までに 2 つの資料を紹介します。

1 つは「将棋ったー」や「Kifu for JS」の開発者である na2hiro 氏が X に投稿した遷移図です。

https://x.com/na2hiro/status/1704337508354732473

少なくとも X に投稿された段階の図において、反則によるゲームオーバーや詰み探索で生じる遷移は反映されていないようです。
また、先述の ShogiGUI の動作とは異なり `setoption` がゲーム中に送信されないものとして扱われています。

もう 1 つは筆者が ShogiHome を開発する上で作成した遷移図です。
ShogiHome で発生する状態遷移を表したものなので、この図も USI の仕様を網羅したものではありません。

![スクリーンショット 2024-07-13 0.12.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78005/f9b5963b-d696-a6cb-61a8-919e7e9d0664.png)
https://miro.com/app/board/uXjVOgsk6Lo=/?moveToWidget=3458764554934026983&cot=14

この図では `setoption` を起動直後にしか送信しないものとして扱っています。