将棋所のponderについて

ひよこカルロ将棋v0.06にponder機能を実装しました。

将棋所で使われているUSIプロトコルなのですがponderの仕様がちょっとややこしかったのでメモしておきます。


・ponder(相手番での思考)をするには、将棋所の対局ダイアログのエンジン共通設定のところにある「相手の手番中に先読み」にチェックを入れる。そうすると思考エンジンに「ponderしていいですよ」という次のメッセージが送られてくる。

setoption name USI_Ponder value true

このメッセージがあるときは、自分が指したあとに相手が指すであろう手をbestmoveコマンドを送るときに付与しておきます。

bestmove 6a5b ponder 4i5h

ここで付与できなければ、次の相手番の思考時間中のponderは無しになります。

ponderの権利を放棄するのは惜しいのでじゃあponderとして何でもいいからつけておけと「ponder resign」などを付与すると、将棋所がバグるのか、自分が投了したことになります。(あれれ?)

ponderのあとに指し手以外の文字列を渡していいのかどうかは規定されていません。
ponderしたければ何がなんでも合法な指し手を渡す必要があります。

ここで合法な指し手が渡せたとします。

そうすると相手の手番中に、こちらに「go ponder」コマンドが送られてきます。いまからponderしていいよというメッセージです。ところが、その局面はさっきの2手先の局面で、自分の手番です。

すなわち「bestmove 76歩 ponder 34歩」と送ると、go ponderの前に送られてくる局面図はこの34歩のあとです。「いやいやいや。そこじゃなくて、76歩と指す前の局面でponderしたいんだけど。ponderの指し手なんてそうそう当たらないし。」という人は、このときに局面図を自力で2つ前の局面に戻さなくてはなりません。

しかし探索ルートを巻き戻すのは連続王手の千日手のカウントなどをすべて元との状態にしないといけないので、結構面倒くさく(例えばBonanzaのunmake_move_root関数)、この実装は結構骨の折れる作業です。

あと初手からponderしたい場合(普通、初手付近は定跡データベースを使うのでしょうから、そういうニーズはあまりないのでしょうけども)もUSIプロトコル仕様では不可能です。これは現局面の2つ先の局面をponderとして送るという設計がおかしい気が少しします。確かにこの仕様で、2つ先の局面だけを調べればいいだけならponderの実装自体は楽なのですが、ponderはなかなか当たらないわけで、そういうことがしたいんじゃないのにと思わないでもありません。


それから、「ponderしていいよ」のメッセージ

setoption name USI_Ponder value true

が来ていないとき(すなわち、"setoption name USI_Ponder value false"のとき)にponderを返すとどうなるか。これもプロトコルには規定されていません。

ponderを返すと将棋所では、「予想手」のところに表示してくれます。これはなかなか気持ちいいですね。ところがponderが的中したときponderhitが送られてきます。いやいやいや。それは送ってこなくていいから!!

ponderhitに対してponderが終わったからとbestmoveを返しますと相手番で指したことになり反則負け扱いになるようです。

規定されていない動作なのでponderが許可されていないときにponderで予想手を返すのがよくないのでしょうけども、それなら予想手を返すコマンドぐらいあってもいいのに…と思わないでもありません。あるいは、ponderが許可されていない状態でponderhitを送ってこないで欲しいなぁと。