LoginSignup
22
15

More than 5 years have passed since last update.

技術屋から見たUSIプロトコルのツライところ

Last updated at Posted at 2018-03-06

最近USIプロトコルという通信プロトコルを使って将棋の思考エンジンを呼び出すものを作る機会がありました。
このUSIプロトコルというのは技術屋の立場から見るととてもプロトコルとは呼べないものでけっこう苦労したので書き留めておきます。

USIプロトコルとは

USIプロトコルは将棋アプリのGUI等(以下、UI)と思考エンジン(以下、エンジン)が標準入出力で通信するためプロトコルです。USIプロトコルに対応しているUIとエンジンであれば自由に組み合わせて使うことができます。

UIはエンジンをサブプロセスとして起動して、棋譜データなどのコマンドをサブプロセスの標準入力に送信します。
エンジンはコマンドを受け取ると思考を開始して次の手を標準出力で返します。
コマンドはいくつかあるのですが、共通の仕様は以下の通りです。

  • コマンドの送信は改行コード
  • コマンドとオプションなどは半角スペースで区切る

主なコマンドには以下のようなものがあります。

コマンド 正常時の応答 説明
usi id name ...
id author ...
option ...
usiok
エンジン起動時に最初に送るコマンド
isready readyok 対局開始前に送る
setoption name ... value ... なし オプションの設定
usinewgame なし 対局開始時に送る
position ... moves ... なし 局面を送る
go ... bestmove ... 思考を開始させて次の手を受け取る
quit エンジンを終了させる

以下はUSIプロトコル通信の例です。わかりやすくするためにUIから送るコマンドの行頭に>を付けてあります。

> usi
id name ...
id author ...
option ...
usiok
> isready
readyok
> usinewgame
> positon startpos moves 7g7f
> go byoyomi 1000
bestmove 8c8d
> positon startpos moves 7g7f 8c8d 1g1f
> go byoyomi 1000
bestmove 3c3d

USIプロトコルのツラいところ

USIプロトコルの共通仕様は非常にシンプルなのですが、シンプルであるが故に色々と辛いところがあります。

  • コマンドを送信しても応答がないコマンドがある
  • エラーに関する規定がない

コマンドを送信しても応答がないコマンドがある

一般的に標準入出力やソケット通信などのプロトコルでは、コマンドを受け取った側は正常に処理できたかどうかの結果を返すのが常識です。
ところがUSIプロトコルのコマンドの中には送信した後にエンジンから応答がないものがあります。これではコマンドが正常に実行できたか確認できません。
また応答があるものとないものがあるとUI側でコマンドを実行する作りが統一できません。

エラーに関する規定がない

USIプロトコルではコマンドが不正だった場合などエラーに関する規程が一切ありません。
この為、エンジンや状況によってエラー発生時の挙動が様々です。

例えば将棋所というGUIアプリに付属の Lesserkai では以下のような挙動でした。

不正なコマンドを送信(無反応)
> hoge
不正な指し手書式を送信(エラーメッセージを返す)
> postion startpos moves hoge
illegal move hoge
不正なコマの移動を送信(エラーメッセージを返す)
position startpos moves 1a9i
illegal move 1a9i

ちなみに自分が使っていたエンジンでは以下のような挙動でした。

不正なコマンドを送信(エラーメッセージを返す)
> hoge
info string unknown command: hoge
不正な指し手書式を送信(エラーメッセージを返す)
> positon startpos moves hoge
info string unknown command: positon startpos moves hoge
不正な駒の移動を送信(無視?)
position startpos moves 1a9i
go
info string OptTime 0sec MaxTime 0sec Progress = 1.296% Threads = 4
bestmove 9c9d

このようにエラーの形式がバラバラではUI側では受け取りようがありません。

参考:他のプロトコルのレスポンス

これだけ見ても「何がいけないの?」という人もいると思うので、参考までに他のプロトコルでは応答がどのような形式になっているか書いておきます。
基本的にはプロトコル全体で応答の形式を規定しているのでエラーの発生を確実で受け取れるようになっています。

HTTP

リクエストに対して必ずレンスポンスが返ってきます。
HTTPレスポンスでは1行目はステータス行で、HTTP/1.1 200 OKのようにHTTPステータスコードが含まれています。

POP3

リクエストに対して必ずレンスポンスが返ってきます。
POP3サーバーはコマンドを受け取ると成功、不成功に応じて+OKまたは、-ERRから始める文字列を返します。
エラーの場合には-ERRの後にエラーメッセージを返します。

SMTP

リクエストに対して必ずレンスポンスが返ってきます。
リプライコード+リプライメッセージという形式になっています。

これからプロトコルを設計する人へ

プロトコル設計で重要なのは共通で使える仕様を決める事です。正常時だけでなく異常時の振る舞いも含めて考える必要があります。
通信相手によって送受信する形式が違っていたり、コマンドによって応答やエラーの形式がバラバラではプロトコルとは言えません。
これからソケット通信や標準入出力のプロトコルを設計するという人は、この辺りを踏まえて共通で使えるように設計しましょう。

22
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
15