今回は、Kifu for WindowsとShogiGUIを活用して協力詰めをどんどん解かせてみます。
Kifu for Windowsの活用
前回、将棋所/ShogiGUIでは不要な駒を駒箱のなかに駒をしまうことが出来ないと書きましたが、Kifu for WindowsのツールメニューのところにShogiGUIを登録すれば、アプリ連携のような機能を用いて、Kifu for Windowsで編集した盤面をShogiGUIに渡すことが出来ることをコメント欄で教えてもらいました。
参考)
Kifu for Windowsとの連携
https://sites.google.com/site/shogigui/manual/others/kifu-for-windows
そこで、前回やねうら王miniを使って書いた協力詰めsolverにShogiGUI上で無事協力詰めを解かせることに成功しました。
ばか詰(1) (松本博文ブログ)
http://mtmt-blog.com/?p=1783
の2つ目の問題。
プロ棋士も悩む5手協力詰(プロ棋士も悩む5手協力詰)
http://toybox.tea-nifty.com/memo/2006/03/post_905b.html
の2つ目の問題。
ここまでは余裕ですね。
先手玉がいなくても大丈夫なの?
詰将棋では普通、先手玉は盤上にいません。また、協力詰めでは後手の手駒は「残りすべて」ではなく、「なし」かも知れません。すなわち、使われない駒は駒箱に入っているという考えかたをしないといけません。
KPPの評価関数などで、このような駒箱に入っていて使われていない駒はどう表現されるのでしょうか。
やねうら王miniでは、82升目(0から数えるなら81 = SQ_NB)にあるものとして考えています。
例えば、駒pcをsqの地点においたときの利きを
effect_from(pc,sq)
のように表現するとしたら、この82升目においたときの利き
effect_from(pc,SQ_NB)
は0(利きがどこにもないBitboard)を返すようにしてあります。
また、KPPのテーブルもKはSQ_NBを許容するようにしてあります。こうすることで玉が駒箱に入っているパターンに対応できます。(このときKPPテーブルの値は0)
あと、駒がSQ_NBに移動したときはBonaPiece(KPPのPの値)はゼロとなるようにしてあります。(このときのKPPテーブルの値も0)
つまり、
kpp_table[SQ_NB][p1][p2] は、 0。(玉がSQ_NBにいるパターン)
kpp_table[k][p1][0]
kpp_table[k][0][p2] も 0。(p1とかp2が駒箱に入っていて使われていないパターン)
のようになっています。
こうすることで普通のKPPの差分計算などのコードがそのまま駒落ちでも正しく動作します。落としている駒の分まで評価値の計算をしているのは速度的にはわずかに無駄ではありますが、駒落ちで対戦する機会はあまりないのでそのときにまで最大のパフォーマンスが得られなくてもいいだろうという考えです。
現実的には、駒落ちでも駒落ち用に特別なコードを書かなくていいという利点のほうが大きいでしょう。
AperyやBonanzaでは駒落ちはどうなっているの?
Aperyのコードよく読んでませんが、おそらく、Aperyは駒落ちに対応できないのではないかと思います。FV38をやって駒落ちに対応させるには上のようなhackが必要になるからです。(FV38について知らない人はggrks)
Bonanzaではmake_list()のなかで使われている駒だけを配列に直列化していくので駒落ちでも対応できます。(その代わりmake_listの差分計算がされていなくてその分、遅いです。)
現代ではmake_list()は差分計算するのが普通なので、駒落ちに対応させるのが少し面倒で、そのためFV38をやっているソフトでは駒落ちに対応していないソフトも結構あるかと思うのですが、上のようなhackで対応できるというのは知っておいて良いでしょう。
この協力詰めsolver、遅くない?
さきほどの「プロ棋士も悩む5手協力詰」が1秒程度で解答が出てくるのは圧巻です。しかし1秒って長くないですか?
プロ棋士は、普通の将棋に慣れすぎているので協力詰めは盲点となる指し手であるので解くのに時間がかかるのはおかしいことではありませんが、コンピューターにしてみれば、たかだか5手詰めなのだから、もっと速く解けても良さそうなものです。
そんなわけで、5手詰めでは高速化のときの目安にならないのでもっと難解な協力詰めを持ってきて、それを解かせることに挑戦しましょう。
加藤徹さんの作品を解かせてみる。
「難しい協力詰め、出てこいや~!」ということで、まずは、加藤徹さんの作品から。
協力詰(ばか詰) 51手~99手(詰将棋おもちゃ箱 - 加藤徹 全作品)
http://www.ne.jp/asahi/tetsu/toybox/kato/fbaka2.htm
まずはこの中の最短の詰めである55手のもの(No.58)から挑戦。4秒ほどで解けました。
* 深さ 55 読み筋 ▲1八龍(58) △同 玉(19) ▲1九歩打 △1七玉(18) ▲1八歩(19) △同 と(27) ▲2九桂打 △2七玉(17) ▲2八歩打 △同 と(37) ▲1九桂打 △3六玉(27) ▲3七歩打 △同 と(26) ▲4八桂打 △2六玉(36) ▲2七歩打 △同 と(16) ▲3八桂打 △1五玉(26) ▲1六歩打 △同 と(25) ▲2七桂(19) △2五玉(15) ▲2六歩打 △同 と(35) ▲3七桂(29) △3四玉(25) ▲3五歩打 △同 と(24) ▲4六桂(38) △2四玉(34) ▲2五歩打 △同 と(14) ▲3六桂(48) △1三玉(24) ▲1四歩打 △同 成香(23) ▲2五桂(37) △2三玉(13) ▲2四歩打 △同 成香(14) ▲3五桂(27) △1四玉(23) ▲1三桂成(25) △1五玉(14) ▲1四成桂(13) △2五玉(15) ▲2四成桂(14) △1五玉(25) ▲1四成桂(24) △同 玉(15) ▲1五歩打 △1三玉(14) ▲1四香打
次に短そうな、69手(No.77a)のものに挑戦。1分以内で解けました。
* 深さ 69 読み筋 ▲9六歩(97) △同 玉(95) ▲8八桂打 △8六玉(96) ▲7六桂(88) △8八歩打 ▲同 香(89) △8七桂打 ▲同 香(88) △同 玉(86) ▲8八歩打 △7六玉(87) ▲6八桂打 △6六玉(76) ▲5六桂(68) △6八香打 ▲同 香(69) △6七桂打 ▲同 香(68) △同 玉(66) ▲6九香打 △5六玉(67) ▲4八桂打 △4六玉(56) ▲3六桂(48) △4八香打 ▲同 香(49) △4七桂打 ▲同 香(48) △同 玉(46) ▲4九香打 △3六玉(47) ▲2八桂打 △2六玉(36) ▲1六桂(28) △2八香打 ▲同 香(29) △2七桂打 ▲同 香(28) △同 玉(26) ▲2九香打 △1六玉(27) ▲2八桂打 △2六玉(16) ▲3六桂(28) △2七桂打 ▲同 香(29) △3六玉(26) ▲4八桂打 △4六玉(36) ▲5六桂(48) △4七桂打 ▲同 香(49) △5六玉(46) ▲6八桂打 △6六玉(56) ▲7六桂(68) △6八香打 ▲同 香(69) △6七桂打 ▲同 香(68) △7六玉(66) ▲6八桂打 △8六玉(76) ▲8七歩(88) △9六玉(86) ▲9七歩打 △9五玉(96) ▲9六香打
さらに、67手(No.90)のもの。2分程度で深さ50まで進んだものの、そのあとなかなか進みません。本当に進んでいるのでしょうか。
ログ機能を有効にする
本当に思考が進んでいるのか確認するためにログ表示機能を使ってみましょう。
将棋所では、「デバッグウィンドウ」を表示するとGUI(将棋所)と思考エンジンとのやりとりが確認できますが、ShogiGUIにはこの機能がないようです。
そこで、やねうら王miniのログ機能を活用してみましょう。思考エンジン設定で、”Write Debug Log”(ログの書き出し)オプションを有効(true)にすると”io_log.txt”というファイルに標準入出力でのやり取りが書き出されます。
コマンドラインからやるときは
> setoption name Write Debug Log value true
もしくは
> log
とやれば、ログを書き出せるようになります。
ログ機能の実装
やねうら王miniを使う分にはあまり関係ありませんが、ログ機能は次のように標準入出力(cin/cout)を横取りしてファイルにリダイレクトする形で実装されています。このようにすることで(実際にcin/coutに入出力している部分には)追加コードを一切書かずにリダイレクトが実現できます。これはStockfishのアイデアです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
// logging用のhack。streambufをこれでhookしてしまえば追加コードなしで普通に // cinからの入力とcoutへの出力をファイルにリダイレクトできる。 // cf. http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81 struct Tie : public streambuf { Tie(streambuf* buf_ , streambuf* log_) : buf(buf_) , log(log_) {} int sync() { return log->pubsync(), buf->pubsync(); } int overflow(int c) { return write(buf->sputc((char)c), "<< "); } int underflow() { return buf->sgetc(); } int uflow() { return write(buf->sbumpc(), ">> "); } int write(int c, const char* prefix) { static int last = '\n'; if (last == '\n') log->sputn(prefix, 3); return last = log->sputc((char)c); } streambuf *buf, *log; // 標準入出力 , ログファイル }; struct Logger { static void start(bool b) { static Logger log; if (b && !log.file.is_open()) { log.file.open("io_log.txt", ifstream::out); cin.rdbuf(&log.in); cout.rdbuf(&log.out); cout << "start logger" << endl; } else if (!b && log.file.is_open()) { cout << "end logger" << endl; cout.rdbuf(log.out.buf); cin.rdbuf(log.in.buf); log.file.close(); } } private: Tie in, out; // 標準入力とファイル、標準出力とファイルのひも付け ofstream file; // ログを書き出すファイル Logger() : in(cin.rdbuf(),file.rdbuf()) , out(cout.rdbuf(),file.rdbuf()) {} ~Logger() { start(false); } }; void start_logger(bool b) { Logger::start(b); } |
やねうら王miniのライセンスについて考えちゅう
上のログ出力まわりのコード、Stockfishのコードほとんどそのままで利用していて(あえてなおす理由も別段なくて)、ライセンス的にこの部分を私が書いたと主張するのは無理があるので、やねうら王mini、最初に公開する時点ではStockfishのライセンスに倣い、GPLv3にしようと思います。Stockfishのソースコードを流用している部分を書き直した時点でMIT Licenseに切り替える予定です。
ログ内容
さきほど出力されたログを見ていきましょう。
“>>”で始まる行はGUIから思考エンジンへの入力で、
“<<“で始まる行は思考エンジンからGUIへの出力です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
<< start logger >> isready << readyok >> usinewgame >> position sfen 4K1ks1/8s/6g1n/4llll1/3N4g/9/9/9/9 b 16P2r2b2g2s2n2p 1 >> go mate infinite << info depth 1 << info depth 2 << info depth 3 << info depth 4 << info depth 5 << info depth 6 << info depth 7 << info depth 8 << info depth 9 << info depth 10 << info depth 11 << info depth 12 << info depth 13 << info depth 14 << info depth 15 << info depth 16 << info depth 17 << info depth 18 << info depth 19 << info depth 20 << info depth 21 << info depth 22 << info depth 23 << info depth 24 << info depth 25 << info depth 26 << info depth 27 << info depth 28 << info depth 29 << info depth 30 << info depth 31 << info depth 32 << info depth 33 << info depth 34 << info depth 35 << info depth 36 << info depth 37 << info depth 38 << info depth 39 << info depth 40 << info depth 41 << info depth 42 << info depth 43 << info depth 44 << info depth 45 << info depth 46 << info depth 47 << info depth 48 << info depth 49 << info depth 50 << info depth 51 |
ちゃんと進んではいるようです。
ちなみに、「中断」ボタンを押すと”stop”コマンドがGUIから送られてきますが、まだ”stop”コマンドで停止するようにはプログラムを書いていないのでそのあと思考が続きます。ところがShogiGUIは”stop”コマンドを送信したあとの思考エンジンからの出力は無視しますので(解けていたとしても)画面上に読み筋は表示されません。(このため、この状態で思考エンジンを停止させたいときは、ShogiGUIを終了させたほうが良いです。)
No.90は変化が広い難問?
10分かけて深さ53にまでしか行きませんでした。67手詰めということは深さ67まで進む必要がありますが、ここから指数関数的に増えるとなると丸一日ぐらいかかりかねません。そこでこれが解けるように頑張ってみましょう。
ここまでのまとめ
Kifu for WindowsとShogiGUIの連携、ログの入出力の説明をしました。ログを書き出せるようになると、ShogiGUIから実行させて動作がおかしいときにそのときのGUIから渡されている入力が何であるかがわかるので、思考エンジンを単体起動してデバッガで追いかけるのが楽になります。
協力詰め(先手は王手の連続で迫るもの)に関しては、50手ぐらいの作品までは、特に工夫をしなくとも(置換表等がなくとも)1分程度で解けそうということがわかりました。またそれ以上の長編は何らかの工夫をしないと絶望的ということがわかりました。
次回につづく
(^q^) 一度 GPL にしたものでも 流用部を書き直せば MIT に変えることができるのかだぜ☆?
(^~^) ライセンス運用は謎だぜ☆
(^_^) 囲碁プログラムも GPLから初めて 独自実装に変える感じでやってみるぜ☆
著作者から「もらった側」が「もらったバージョンについて」GPL適用になるだけの話だからね。もらった側はGPLを守る義務を負うが、著作権者はいつでも自分のソースを自由にライセンスを変更して配布して良い。だから無料GPLと商用有料のデュアルライセンスみたいな、相手によってライセンスを変えるみたいな配り方も可能なわけね。
もちろん、一度GPLバージョンで配布したソースは、それが入手者からコピーされ続ける限りGPLのままになるがね
…のはず
ついでに書き忘れたけど
GPL流用部を自分で書き直す=自分の配布物がGPLを含まない=完全に自分で好きなライセンスを選択可能
ってことね
あけまして、おめでとうございます。
本年もまたよろしくお願いします。
・・・という訳で、
>67手詰めということは深さまで進む必要がありますが、・・
これは
深さ67まで進む必要がありますが、・・・
あるいは
depth 67まで・・・でしょうか
修正しました(`・ω・´)ゞ
あけましておめでとうございます。
結構できてきましたね。
iostreamは結構カオスなので中身は触りたくないものです。
そうですねえぇ、ライセンス回避するんだったら同じものを<stdio.h>のFILEで書いてiostream風のインターフェイスにするとか。ナンセンスですけど。
そういえば、C++14だったかで、putfってどうなったんでしょ??
それはそれとして、大分全容が見えてきてちょっとワクワクしています。
> ナンセンスですけど。
うむうむ…。そのナンセンスをライセンス回避のためだけにやらないといけない日が来るような来ないような…。そして、ナンセンスとライセンスって言葉の響き、なんでこんなに似てるのん…。
にゃんぱすー。
実はのんのんのことはよく知らない・・・。Orz