今回は、中編(100手以上~1000手未満)の協力詰めが解けるsolverを作ります。
MovePickerの設計
ここまで、LEGALで合法手のみを生成しているのですが、これはいったんすべての指し手を生成して、合法かどうかをひとつずつテストしているので無駄が多いというのは以前書きました。
また、先手は王手のみと限定できるならLEGALではなくCHECKS(王手)の指し手を生成したほうが生成の時間が短くて済みます。
やねうら王miniには高速なCHECKSの指し手の生成ルーチンがあります。おそらく、Bitboardを用いた高速なCHECKSの指し手の生成ルーチンが公開されるのはこれが始めてでしょう。書くのにずいぶん苦労しましたが、うまく動いているようですのでこれを使って書き換えてみましょう。
指し手生成を高速化した協力詰めsolver
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 |
namespace CooperativeMate { // 協力詰め用のMovePicker struct MovePicker { MovePicker(const Position& pos_) : pos(pos_) { // 協力詰めであれば段階的に指し手を生成する必要はない。 // 先手ならば王手の指し手(CHECKS)、後手ならば回避手(EVASIONS)を生成。 endMoves = (pos.side_to_move() == BLACK) ? generateMoves : generateMoves } // 次の指し手をひとつ返す // 指し手が尽きればMOVE_NONEが返る。 Move next_move() { if (currentMoves == endMoves) return MOVE_NONE; return *currentMoves++; } private: const Position& pos; ExtMove moves[MAX_MOVES], *currentMoves = moves, *endMoves = moves; }; } // end of namespace |
No.90に再挑戦
置換表も出来たことですし、再度加藤徹さんのNo.90を解かせてみるんですが、63手目で王手が続かなくなったようです。なんでかなーと思って解答を見たところ…
1 2 3 4 5 6 |
13 2三歩打 ( 0:00/00:00:00) 14 2一玉(22) ( 0:00/00:00:00) 15 2二歩(23) ( 0:00/00:00:00) 16 1一玉(21) ( 0:00/00:00:00) 17 2一歩成(22) ( 0:00/00:00:00) 18 同 銀(12) ( 0:00/00:00:00) |
http://www.ne.jp/asahi/tetsu/toybox/kato/rsk/kato090.kif
これはすごい手順ですね。歩打って王手して、玉引いて、歩不成で進んで、玉を横に交わして、歩成って、同銀…。協力詰め特有の魔法のような手順です。
そして、以前書いたように、やねうら王miniではLEGALの指し手生成以外では、歩の不成などは生成していません。王手の指し手生成(CHECKS)や王手回避(EVASIONS)もご多分に漏れず、です。
MovePickerで歩の不成も生成する
そこで、MovePickerで歩の不成なども生成してみます。
これは次のように CHECKS_ALL , EVASIONS_ALLと “_ALL”を末尾につけるだけです。
※ 以前、LEGALは歩の不成も含むと書きましたが、これらと統一するためにLEGAL_ALLを不成を含むようにして、LEGALは不成を含まないように変更しました。過去の記事でそうなっているのがあれば脳内で修正してください。
1 2 3 4 5 6 7 |
MovePicker(const Position& pos_) : pos(pos_) { // 協力詰めであれば段階的に指し手を生成する必要はない。 // 先手ならば王手の指し手(CHECKS)、後手ならば回避手(EVASIONS)を生成。 endMoves = (pos.side_to_move() == BLACK) ? generateMoves : generateMoves } |
あと、以前も書きましたがmovegen.cppの末尾のところでこのtemplateの実体化は必要と。
1 2 |
// 協力詰めのときは必要 template ExtMove* generateMoves |
67手詰め、解けるかな?
ShogiGUIで実行させると…。
1 |
* 深さ 67 読み筋 ▲3二歩打 △2二玉(31) ▲2三歩打 △3二玉(22) ▲2二歩成(23) △同 玉(32) ▲2三歩打 △3一玉(22) ▲3二歩打 △同 銀(21) ▲2二歩成(23) △同 玉(31) ▲2三歩打 △2一玉(22) ▲2二歩(23) △1一玉(21) ▲2一歩成(22) △同 銀(12) ▲1二歩打 △2二玉(11) ▲2三歩打 △1二玉(22) ▲2二歩成(23) △同 玉(12) ▲2三歩打 △1一玉(22) ▲2二歩成(23) △同 銀(21) ▲1二歩打 △2一玉(11) ▲1一歩成(12) △同 銀(22) ▲2二歩打 △3一玉(21) ▲2一歩成(22) △同 銀(32) ▲3二歩打 △2二玉(31) ▲2三歩打 △3二玉(22) ▲2二歩成(23) △同 玉(32) ▲2三歩打 △3一玉(22) ▲3二歩打 △同 金(33) ▲2二歩成(23) △同 金(32) ▲3二歩打 △同 玉(31) ▲3三歩打 △4三玉(32) ▲5三桂成(65) △3三玉(43) ▲4三成桂(53) △2三玉(33) ▲3三成桂(43) △1二玉(23) ▲2二成桂(33) △同 玉(12) ▲1二金打 △2三玉(22) ▲1三金(12) △3二玉(23) ▲2三金(13) △3一玉(32) ▲4三桂打 |
1秒かからず瞬殺でした。置換表、恐るべし。
No.45(153手詰め)
では張り切って153手詰めもやってみましょう。
協力詰(ばか詰) 101手~999手(加藤徹 全作品)
http://www.ne.jp/asahi/tetsu/toybox/kato/fbaka3.htm
から、No.45。
http://www.ne.jp/asahi/tetsu/toybox/kato/rsk/kato045.kif
※ kifファイルをテキストエディタで開いて、盤面のところコピーして、将棋所とかShogiGUIにCtrl+Vで貼り付けをすると盤面の入力がされます。便利ですね、将棋所&ShogiGUI。そしてkifファイルを公開してくださっている加藤徹さんに感謝!
MAX_PLYは128を想定しているのでこれ以上にするには、shogi.hの次のdefineの値を変更する必要があります。
1 2 |
// 通常探索時の最大探索深さ #define MAX_PLY_ 128 |
これをもっと大きな数にして…。
1 |
* 深さ 153 読み筋 ▲9二桂成(84) △同 玉(91) ▲8四桂打 △8一玉(92) ▲7二桂成(84) △9一玉(81) ▲8一成桂(72) △9二玉(91) ▲9一成桂(81) △8二玉(92) ▲8一成桂(91) △7二玉(82) ▲7一成桂(81) △8二玉(72) ▲8一成桂(71) △9二玉(82) ▲9一成桂(81) △8二玉(92) ▲9二成桂(91) △7一玉(82) ▲7二歩打 △同 と(61) ▲8二成桂(92) △6一玉(71) ▲7二成桂(82) △同 と(62) ▲6二歩打 △7一玉(61) ▲6一歩成(62) △8一玉(71) ▲7一と(61) △8二玉(81) ▲7二と(71) △9一玉(82) ▲8一と(72) △9二玉(91) ▲9一と(81) △8二玉(92) ▲8一と(91) △7二玉(82) ▲8二と(81) △6一玉(72) ▲6二歩打 △同 と(51) ▲7二と(82) △5一玉(61) ▲6二と(72) △同 と(52) ▲5二歩打 △6一玉(51) ▲5一歩成(52) △7一玉(61) ▲6一と(51) △7二玉(71) ▲6二と(61) △8一玉(72) ▲7一と(62) △8二玉(81) ▲8一と(71) △7二玉(82) ▲7一と(81) △6二玉(72) ▲7二と(71) △5一玉(62) ▲5二歩打 △同 と(41) ▲6二と(72) △4一玉(51) ▲5二と(62) △同 と(42) ▲4二歩打 △5一玉(41) ▲4一歩成(42) △6一玉(51) ▲5一と(41) △6二玉(61) ▲5二と(51) △7一玉(62) ▲6一と(52) △7二玉(71) ▲7一と(61) △6二玉(72) ▲6一と(71) △5二玉(62) ▲6二と(61) △4一玉(52) ▲4二歩打 △同 と(31) ▲5二と(62) △3一玉(41) ▲4二と(52) △同 と(32) ▲3二歩打 △4一玉(31) ▲3一歩成(32) △5一玉(41) ▲4一と(31) △5二玉(51) ▲4二と(41) △6一玉(52) ▲5一と(42) △6二玉(61) ▲6一と(51) △5二玉(62) ▲5一と(61) △4二玉(52) ▲5二と(51) △3一玉(42) ▲3二歩打 △同 成香(21) ▲4二と(52) △2一玉(31) ▲3二と(42) △同 成香(22) ▲2二香打 △3一玉(21) ▲2一香成(22) △4一玉(31) ▲3一成香(21) △4二玉(41) ▲3二成香(31) △5一玉(42) ▲4一成香(32) △5二玉(51) ▲5一成香(41) △4二玉(52) ▲4一成香(51) △3二玉(42) ▲4二成香(41) △2一玉(32) ▲2二香打 △同 成桂(12) ▲3二成香(42) △1二玉(21) ▲2二成香(32) △同 成桂(11) ▲2四桂打 △2一玉(12) ▲1二桂成(24) △3一玉(21) ▲2二成桂(12) △4一玉(31) ▲3一成桂(22) △4二玉(41) ▲4一成桂(31) △3二玉(42) ▲4二成桂(41) △2二玉(32) ▲3四桂打 △2一玉(22) ▲3二成桂(42) △1二玉(21) ▲2二桂成(34) |
1秒足らずで解答が表示されました。置換表凄すぎ!というか、協力詰めって、きっとほぼほぼ一本道なんでしょうね…。
No12a(263手詰め)
http://www.ne.jp/asahi/tetsu/toybox/kato/rsk/kato012a.kif
落ちました。stack overflowで…。まあ、MSVCでは、デフォルト1MBしかないですしね。
仕方ないので、構成プロパティの
リンカー→システム→スタックサイズ
byte単位で指定するようなので419430400(400MB)を指定。
これで数万手になっても(解けるかどうかは別として)stack overflowにはならないようです。
1 |
* 深さ 263 読み筋 ▲8四歩打 △9三玉(83) ▲8三歩成(84) △同 玉(93) ▲9四と(95) △同 玉(83) ▲9五歩打 △9三玉(94) ▲9四歩(95) △8三玉(93) ▲9三歩成(94) △8四玉(83) ▲8三と(93) △9四玉(84) ▲8四と(83) △9五玉(94) ▲8五と(84) △同 玉(95) ▲8六歩打 △8四玉(85) ▲8五歩(86) △8三玉(84) ▲8四歩(85) △9三玉(83) ▲8三歩成(84) △9四玉(93) ▲8四と(83) △9五玉(94) ▲9四と(84) △8五玉(95) ▲9五と(94) △8六玉(85) ▲9六と(95) △同 玉(86) ▲9七歩打 △9五玉(96) ▲9六歩(97) △9四玉(95) ▲9五歩(96) △9三玉(94) ▲9四歩(95) △8三玉(93) ▲9三歩成(94) △8四玉(83) ▲8三と(93) △8五玉(84) ▲8四と(83) △8六玉(85) ▲8五と(84) △9六玉(86) ▲8六と(85) △9七玉(96) ▲8七と(86) △同 玉(97) ▲8八歩打 △8六玉(87) ▲8七歩(88) △8五玉(86) ▲8六歩(87) △8四玉(85) ▲8五歩(86) △8三玉(84) ▲8四歩(85) △9三玉(83) ▲8三歩成(84) △9四玉(93) ▲8四と(83) △9五玉(94) ▲8五と(84) △9六玉(95) ▲8六と(85) △9七玉(96) ▲9六と(86) △8七玉(97) ▲9七と(96) △8八玉(87) ▲9八と(97) △同 玉(88) ▲9九歩打 △9七玉(98) ▲9八歩(99) △9六玉(97) ▲9七歩(98) △9五玉(96) ▲9六歩(97) △9四玉(95) ▲9五歩(96) △9三玉(94) ▲9四歩(95) △8三玉(93) ▲9三歩成(94) △8四玉(83) ▲8三と(93) △8五玉(84) ▲8四と(83) △8六玉(85) ▲8五と(84) △8七玉(86) ▲8六と(85) △8八玉(87) ▲8七と(86) △9八玉(88) ▲8八と(87) △9九玉(98) ▲8九と(88) △同 玉(99) ▲9八銀打 △8八玉(89) ▲9七銀(98) △8七玉(88) ▲9六銀(97) △8六玉(87) ▲9五銀(96) △8五玉(86) ▲9四銀(95) △8四玉(85) ▲8三銀成(94) △8五玉(84) ▲8四成銀(83) △8六玉(85) ▲8五成銀(84) △8七玉(86) ▲8六成銀(85) △8八玉(87) ▲8七成銀(86) △8九玉(88) ▲8八成銀(87) △7九玉(89) ▲8九成銀(88) △6九玉(79) ▲7九成銀(89) △5九玉(69) ▲6九成銀(79) △4九玉(59) ▲5九成銀(69) △3九玉(49) ▲4九成銀(59) △2九玉(39) ▲3九成銀(49) △1九玉(29) ▲1八金(17) △同 玉(19) ▲1七金(16) △1九玉(18) ▲1八金(17) △同 玉(19) ▲1七金(27) △1九玉(18) ▲1八金(17) △同 玉(19) ▲2九成銀(39) △1七玉(18) ▲1八成銀(29) △1六玉(17) ▲1七成銀(18) △2五玉(16) ▲1六成銀(17) △同 玉(25) ▲1五と(14) △1七玉(16) ▲1六と(15) △1八玉(17) ▲1七と(16) △1九玉(18) ▲1八と(17) △2九玉(19) ▲1九と(18) △3九玉(29) ▲2九と(19) △4九玉(39) ▲3九と(29) △5九玉(49) ▲4九と(39) △6九玉(59) ▲5九と(49) △7九玉(69) ▲6九と(59) △8八玉(79) ▲7九と(69) △9八玉(88) ▲8八と(79) △9九玉(98) ▲9八と(88) △8九玉(99) ▲8八と(98) △7九玉(89) ▲8九と(88) △6九玉(79) ▲7九と(89) △5九玉(69) ▲6九と(79) △4九玉(59) ▲5九と(69) △3九玉(49) ▲4九と(59) △2九玉(39) ▲3九と(49) △1八玉(29) ▲2九と(39) △1七玉(18) ▲1八と(29) △1六玉(17) ▲1七と(18) △2五玉(16) ▲3五金(45) △1五玉(25) ▲2五金(35) △同 玉(15) ▲1六と(17) △3五玉(25) ▲2五と(16) △4五玉(35) ▲3五と(25) △5五玉(45) ▲4五と(35) △6四玉(55) ▲5四と(45) △6五玉(64) ▲6四と(54) △5五玉(65) ▲5四と(64) △4五玉(55) ▲4四と(54) △3五玉(45) ▲3四と(44) △2五玉(35) ▲3五と(34) △1五玉(25) ▲2五と(35) △1六玉(15) ▲1五と(25) △1七玉(16) ▲1六と(15) △1八玉(17) ▲1七と(16) △1九玉(18) ▲1八と(17) △2九玉(19) ▲1九と(18) △3九玉(29) ▲2九と(19) △4九玉(39) ▲3九と(29) △5九玉(49) ▲4九と(39) △6九玉(59) ▲5九と(49) △7九玉(69) ▲6九と(59) △8八玉(79) ▲7九と(69) △8七玉(88) ▲8八と(79) △8六玉(87) ▲7七と(88) △8五玉(86) ▲8六と(77) △9四玉(85) ▲9五歩打 △8四玉(94) ▲8五と(86) △9三玉(84) ▲9四と(85) |
詰将棋エンジンの作法
将棋所やShogiGUIから詰将棋を解くボタンを押すと
> go mate infinite
というメッセージが送られてきます。(“infinite”のところは思考時間のときも)
これに対して解図できたときはUSIプロトコルでは
> checkmate 指し手..
詰まないときは
> checkmate nomate
と出力するようです。(知りませんでした)
停止シグナル
USIプロトコルで”go …”(思考開始)のあと”stop”(強制停止)が送られてきた場合、”bestmove XXX”とベストな指し手を返すことになっているのですが、”go mate infinite”(詰将棋探索をせよ)のあと、”stop”が送られてきたときに”bestmove resign”を返すのか、”checkmate nomate”を返すのか、いまひとつよくわかりません。
ともかく、”stop”コマンドが送られてきたときに、やねうら王miniではSignals.stopがtrueになりますので、探索部においてはときどきこのフラグを確認してtrueであれば探索を中断して終わる必要があります。
このとき正しい指し手が返せる必要はありませんが、置換表に変な値を書き込んでしまったりすると次の探索のときにその値が使われてしまうと探索結果がおかしくなるので、そういう注意は必要でしょう。
ここまでのまとめ
置換表を実装すると200手ぐらいの協力詰めが解けるようになりました。
次回は長編(1000手~)に挑戦します。
1秒でズバッととけちゃうなんてすごいことになってますねぇ。
そこに痺れるあこがれる~。
絶対自分がやると、頭フットーしてしまいます。
>長手数の協力詰めsolver書いた経験からかdf-pnの論文見ると一瞬で理解できた。・・・
まことに「長手数の協力詰めsolverの霊験あらたかなる効果」でありますなあ。
正月そうそう縁起の良い話であります。
https://twitter.com/yaneuraou/status/683555083003412480?ref_src=twsrc%5Etfw
通常の詰将棋より緩い条件である、協力詰めを足がかりにしたのはアプローチ的に正解だったということですな…。
横型探索のperft depth = 7~8相当のノード数ですね。
それで探索深さ49909まで潜るのですから、、、。
縦型探索恐るべし、、、であります。
https://twitter.com/yaneuraou/status/683539246339112960?ref_src=twsrc%5Etfw
反復深化と置換表が恐るべしということですね…。