将棋所で動く思考エンジンのサンプルプログラムにLesserkaiというのがある。将棋所の作者のページからダウンロード出来るので、USIプロトコル対応のプログラムを書く上で公式のサンプルプログラムだと言っても過言ではないのだが、ちょっと困った問題がある。
このLesserkaiのmain関数の冒頭で次のように標準入出力のバッファリングを無効にしている部分がある。
1 2 3 4 |
int main() { setvbuf(stdout, NULL, _IONBF, 0); // これが必要(標準出力のバッファリングを無効にする) setvbuf(stdin, NULL, _IONBF, 0); // これは不要かもしれないけど念のため。 |
Visual C++の古いランタイムでは標準出力がリダイレクトされているときにflushを呼び出しても標準出力のバッファをすべて吐き出さないことがあったような気がしないでもないが(おそらく実装上のバグ)、いまやそんなことはないので、こんなことはする必要はない。
必要はないというか、Visual C++2015でこれをしてしまうと、iostreamを使った標準入力は、改行が二回来ないと入力されない気がする。詳しく調べていないので理由はよくわからないが、上のコードを書いては駄目だということは私はわかっている。
この件でうさ親さんがハマっていたようだ。他にもハマっている人がいるかと思うので記事にしておく。
. @dasapon17 if (cin->_cnt>0) return 1; をコメントアウト、代替コードもコメントアウト、入力のバッファリングを有効にしたら、現在正しく動いております。 ponderも正常に動いているようにみえますので、多分これで大丈夫かと。ありがとうです。
— Yasuhiro Ike (@YasuhiroIke) December 23, 2015
Visual Studio 2015はexpress edition(or community edition)なら無償で使えるし、この無償の環境で十分将棋ソフトが開発できるので、お勧めしたいのだが、上のように2015にupdateしたら(自分の作っている)将棋ソフトが動かなくなったという事案がなくはない。本記事が、その解決の一助になれば幸いである。
あと、本件に関して、詳しいことがわかる人がいればコメントお願いします。
わかんないっす。(開き直り!)
お客様のなかでわかる方はおられませんかー?
分かってたらハマってないっす。
WCSC26で導入されるフィッシャールールについて御意見下さい。
やねうら王も当然対応させますよね?(出場して欲しい直喩)
選手権については考え中です…。
Julia (私がハマっている言語)で自作エンジン作ろうと思って、USI でやりとりするところだけ作ろうとしているのですが、将棋所にエンジン登録しようとするとそのまま、登録中のまま、止まってしまうので、Electron将棋 などの他の GUI とかでも試していたのですが、うまく行かず、C とか C++ で書いたら正常に動き、Python で書くとうまく行かず、flush してないせいなのかとおもって、flush すると Python のやつは、Electron 将棋でうまくいき、将棋所ではうまく行かず、Julia のやつはどっちでもうまく行かず、困り果てています。どうも、Julia インタープリタ自体がエンジン登録しようとすると起動しないみたいなのですが、謎です。そして、将棋所では Python (flush 付き) のやつがうまく行かないのが、謎です。なにか、コンピュータ将棋界隈で知られていることはありませんか?
Python のやつはこんな感じなんですけどねえ…
#!/usr/bin/env python3
while True:
line = input()
if line == “quit”:
break
elif line == “usi”:
print(“id name PythonEngine”, flush=True)
print(“id author Paalon”, flush=True)
print(“usiok”, flush=True)
“usi”を受け付ける前にエンジン側は起動時に”id name …”~”usiok”を送ってしまってはどうでしょう?(“usi”は無視する)
あとはPython版のdlshogiでも同様の現象になるかやってみるだとか。
それと、input()で本当に何も来てないのかログに書き出して確認したいところですな。改行だけ送られてきているとかそういうパターンもありますし。
あとそのコードはbash使ってるのだと思いますが、bashがバッファリングしているということはないでしょうか。(バージョンによるのか知りませんが)
そういえば、1行目1文字目の#!が通用するような環境にはstdbufとかいうコマンドがあったりして、わざわざsetvbufのようなものとかを書き足したりしなくてもそのあたりのバッファリングの有無の差の実験とかもできたような?
GNU Coreutils に stdbuf https://www.gnu.org/software/coreutils/manual/html_node/stdbuf-invocation.html があるんですね。
ちょっとやねさんのヒントを元に色々やってみていますが、情報をまとめきれていないです。とりあえず、Electron 将棋はエンジン追加するときにここ https://github.com/sunfish-shogi/electron-shogi/blob/a94e5ff04531762be7fa33ca0087f9bf42006942/src/ipc/background/usi/engine.ts#L236-L260 を呼んでいるようなので色々調べるつもりです。
Electron 将棋 v1.3.0 のリリースされたものだと Julia で書いたやつを登録しようとすると、timeout になってエラーが出ますが、git clone して v1.3.0 の tag のやつを自分で npm run electron:serve したやつだとエラーが出ずに正常に登録されました。なぜそうなるのかはまだ分かりません。そして将棋所は登録しようとすると、クラッシュするのは相変わらずです。
shebang で env コマンドを使っていると登録に失敗するようです。
ほほー..(使ったことないので知らない)
Electron 将棋におけるこの問題の原因は解決しました。詳細は以下の通りです。
https://github.com/sunfish-shogi/electron-shogi/issues/231#issuecomment-1279851724
> macOS で Finder 上でクリックしたり、Spotlight から起動したアプリケーションの環境変数はデフォルトだと /usr/bin:/bin:/usr/sbin:/sbin となっていて、/usr/local/bin は入っておらず、
>
> sudo launchctl config user path /usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin
>
> などとして設定(要再起動)しないと、いけない
というわけで標準入力のバッファリング問題は関係なさそうです。
将棋所では相変わらず動かないです・・・将棋所の作者さんに聞いてみます。
将棋所で動かない問題、解決しました!将棋所は shebang とか関係なく、テキストファイルは全て Unix シェルのスクリプトとして解釈するみたいです。なので、例えば指定したいファイルが
$ENGINE_PATH/engine
としたら、$ENGINE_PATH/engine-for-shogidokoro
に$ENGINE_PATH/engine
とでも書いて$ENGINE_PATH/engine-for-shogidokoro
を登録すれば実行できる仕様なようです。へんてこりんですね。後進が同じ轍を踏まないように、どこかに記事としてまとめてもらったほうがいいかもですねー。