今回から、やねうら王miniを強くしていく連載が始まります。12回でBonanzaより強くなる。(かも)
今回は、協力詰めsolverを作ってみます。
詰将棋から始めてみよう
指し将棋のAIを作るのは楽しいですが、強くなったかどうかの計測をするのが結構難しく、自己対戦させると時間も馬鹿にならないので、まずは詰将棋AIを作るところから始めたいと思います。詰将棋であれば、正解・不正解がわかりやすく、また詰将棋の問題が解けるまでの時間から探索性能を測れるからです。
詰将棋用のAIであっても、基本的な探索技術は必要となります。また、製作の過程で指し将棋のAIの探索部を作る上で役に立つ知見も色々得られます。
詰将棋の指し手とは
詰将棋は、先手(攻め方)が王手の連続でなくてはなりません。後手(受け方)は王手回避手の連続となります。
厳密に言うとスティールメイトという、後手に指し手がなくなるパターンでの詰みもあるのですが、普通の詰将棋では後手は持ち駒を豊富に持っているので、これはまず起こりません。
つまりは、指し手の種類で言うと、
・先手はCHECKS
・後手はEVASIONS
を生成することになります。
また、先手も後手も最善を尽くすということが前提としてあります。
この最善の定義は非常に難しいですが、ここでは先手は手数が最短になるように、後手は手数が最長になるような指し手を選択するいうことにしておきます。
詰将棋を一般化すると…
普通の詰将棋では、先手と後手の指し手の種類が、CHECKSとEVASIONSに限定されていることがわかりました。これを一般化しようと考えた場合、この条件を緩和してやることが考えられます。例えば、先手は王手でなくても良いだとか。
別の一般化としては、先手・後手が最善を尽くすのではなく、先手は最善、後手は最悪(詰むのに協力)を選択するというのも考えられます。これは協力詰め(ばか詰め)と呼ばれます。
詰将棋の分類
先手が最悪(詰まそうとしない)、後手が最悪(詰むのに協力)を選択すると「最悪詰め」と呼ばれます。先手が最悪、後手が最善を選択すると「悪魔詰め」と呼ばれます。
つまり、後手玉を詰めるとしたときに、次のように分類されます。
先手 後手
最善 最善 :詰将棋
最善 最悪 :協力詰
最悪 最悪 :最悪詰
最悪 最善 :悪魔詰
協力詰めのほうが詰将棋より(コンピューターには)たぶん簡単
普通の詰将棋だと、詰みを見つけても後手が他の指し手を選んだときにも詰むことを証明しなくてはなりません。後手の取りうるあらゆる指し手に対して先手が詰ませる変化がなくてはなりません。
協力詰めのほうは違います。一つでも詰む変化を発見すればそれが解答(の一つ)です。
ということは、協力詰めのほうが詰将棋より、条件が緩いということがわかります。
探索の用語
探索開始局面から、先手が指し手aを指して、局面Bになって、そこで後手が指し手bを指して、局面Cになって…。
探索開始局面での指し手は複数あるでしょうし、そのあとの局面での指し手も複数あるのが普通です。そう考えると、その組み合わせを紙の上に書こうとしたときに樹形図のようなものが出来あがります。
これをゲーム木と呼びます。
このように、探索のことを考えるときに木に見立てるとわかりやすいので、探索ではグラフ理論の以下の用語を使います。
・node(節点) = 局面(盤面+手駒+手番)のこと。
・edge(枝) = nodeとnodeとを結ぶ経路(指し手)のこと。
・path(道) = あるnodeからそのnodeにいたるまでの経路(手順)のこと。
・tree(木) = あるnodeから到達できるnodeをedgeでつないだもの。
・root(根) = root node。探索開始局面のこと。
・leaf(葉) = leaf node。ゲーム木の(木に見立てて)末端の局面のこと。
将棋の探索において、グラフ理論の用語は上記以外はそれほど多く出てこないので、あとは出てきたときに勉強すれば良いでしょう。
縦型探索と横型探索
「縦型探索(深さ優先探索)」と「横型探索(幅優先探索)」についてはggrks。
縦型と横型とどちらがいいかという話になるのですが、ざっくり書くと、横型探索では次に展開する接点をメモリに保持しておかないといけないので、最短経路が求められているようなタイプの問題でなければ縦型探索のほうが好ましいことが多いです。
実際、通例、将棋ソフトでは縦型探索を用います。
いままで将棋ソフトにおいて横型探索を用いていたソフトは、10年以上過去の、ごくごく一部の特殊なソフトだけです。[要出典]
そこで、現代では、縦型探索一択だと思って間違いありません。
協力詰めsolverを書いてみる
協力詰めには先手は王手の連続でなければならないという条件がつけられているのが普通ですが、ここではまずは先手の指し手は王手でなくても良いものとします。
やねうら王miniを使って、プログラムを書いてみます。探索は縦型探索です。プログラムの流れを目で追いかけて、縦型探索のプログラムを理解しましょう。(あるいは「縦型探索」とか「深さ優先探索」とかでggrks。)
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 |
// --- 協力詰め探索 // 現在の探索深さ int search_depth; // 詰みが見つかったか bool found_mate; // 協力詰め // depth = 残り探索深さ void cm_search_sub(Position& pos,int depth) { StateInfo st; for (auto m : MoveList { pos.do_move(m.move, st); if (pos.is_mated()) { // 後手の詰みなら手順を表示する。先手の詰みは必要ない。 if (pos.side_to_move() == WHITE) { sync_cout << "info depth " << search_depth << " pv " << pos.moves_from_start() << sync_endl; // 開始局面からそこまでの手順 found_mate = true; } } else if (depth > 1) { // 残り探索深さがあるなら再帰的に探索する。 cm_search_sub(pos, depth - 1); } pos.undo_move(m.move); } } void cm_search(Position& pos) { found_mate = false; for (int depth = 1; depth < MAX_PLY; ++depth) { sync_cout << "info depth " << depth << sync_endl; search_depth = depth; cm_search_sub(pos,depth); if (found_mate) break; } } // 探索開始時に呼び出される。 // この関数内で初期化を終わらせ、slaveスレッドを起動してThread::search()を呼び出す。 // そのあとslaveスレッドを終了させ、ベストな指し手を返すこと。 void MainThread::think() { // 詰み探索モードで呼び出されたなら協力詰めsolverを呼び出して終了。 if (Limits.mate) { cm_search(rootPos); return; } } |
再帰の流儀
上のプログラム、再帰を使って書かれていることは一目瞭然で、再帰について知らない人はggrks。
depthが残り探索深さで、日本語で書くと次のようなコードとなっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
cm_search(pos,depth) { if (depth == 0) { if (詰み) その手順を表示。 return ; } for(auto&m : この局面でのすべての合法手) { mで1手進める。 cm_search(pos,depth-1); mで1手戻す。 } } |
depth == 0というのが、leaf nodeかの判定というわけです。leaf nodeは、そこが終端のnodeですから、何らかの処理をしてreturnせねばなりません。leaf node以外では、nodeを展開せねばなりません。つまり、そのnodeから辿れるnodeを調べるために、再帰的に自分自身の関数を呼び出すことになります。
再帰的なプログラミングでは上のようなコードを書くのが普通なのですが、depth == 0を判定するときに関数呼び出しが1回あるのが気にくわないので、次のように書き換えることがあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
cm_search(pos,depth) { for(auto&m : この局面でのすべての合法手) { mで1手進める。 if (depth <= 1) // (depth - 1) == 0 { if (詰み) その手順を表示。 continue; } cm_search(pos,depth-1); mで1手戻す。 } } |
leaf node以外でも詰みのチェックをして詰んでいればその手順を表示したいのであればさきほどのソースコードのようになるというわけです。
将棋所から詰将棋エンジンとして用いる
さきほどのプログラムをやねうら王miniに組み込んでコンパイルすると、将棋所から詰将棋エンジンとして登録して、詰将棋エンジン代わりに使うことが出来ます。
さっそく将棋所で盤面編集をして以下のばか詰めを解かせようとしたのですが、将棋所もShogiGUIも盤面編集で手駒を無くすことは出来ないようです。
※ Kifu for Windowsで盤面編集をして、ShogiGUIにツールメニュー連携で局面を渡して、ShogiGUIで解かせることは出来ました。https://sites.google.com/site/shogigui/manual/others/kifu-for-windows
ばか詰(1) (松本博文ブログ)
http://mtmt-blog.com/?p=1783
仕方ないので、コマンドプロンプトから直接USIプロトコルで解かせてみましょう。
さきほどのソースコードのままだと、手順がUSIプロトコルで表示されてわかりにくいので、まず、
sync_cout << “info depth ” << search_depth << ” pv ” << pos.moves_from_start_pretty() << sync_endl; // 開始局面からそこまでの手順
として、日本語で指し手が表示されるようにします。
次に、sfenで直接局面を入力します。sfenについてはggrks。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
> position sfen 9/9/9/3bkb3/9/3+R1+R3/9/9/9 b - 1 > go mate infinite info depth 1 info depth 2 info depth 3 info depth 4 info depth 5 info depth 5 pv 1六龍[4六] 3五角[4四] 6四龍[6六] 4五玉[5四] 1二角打 info depth 5 pv 1六龍[4六] 3五角[4四] 6四龍[6六] 4五玉[5四] 1八角打 info depth 5 pv 1六龍[4六] 3五角[4四] 6四龍[6六] 4五玉[5四] 2三角打 info depth 5 pv 1六龍[4六] 3五角[4四] 6四龍[6六] 4五玉[5四] 2七角打 info depth 5 pv 1六龍[4六] 3五角[4四] 6四龍[6六] 4五玉[5四] 3四角打 info depth 5 pv 1六龍[4六] 3五角[4四] 6四龍[6六] 4五玉[5四] 5六角打 … |
同じような手順がたくさん出てきます。同じ手順ばかり見ていても面白くないので、指し手を限定させたいです。捕獲する指し手を除外してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// 移動先に駒がある(=捕獲する指し手)はskip if (pos.piece_on(move_to(m.move)) != NO_PIECE) continue; pos.do_move(m.move, st); > position sfen 9/9/9/3bkb3/9/3+R1+R3/9/9/9 b - 1 > go mate infinite info depth 1 info depth 2 info depth 3 info depth 4 info depth 5 info depth 5 pv 1六龍[4六] 1九角成[6四] 6七龍[6六] 5五玉[5四] 5六龍[1六] info depth 5 pv 1六龍[4六] 1九角[6四] 6七龍[6六] 5五玉[5四] 5六龍[1六] info depth 5 pv 1六龍[4六] 2八角成[6四] 6七龍[6六] 5五玉[5四] 5六龍[1六] info depth 5 pv 1六龍[4六] 2八角[6四] 6七龍[6六] 5五玉[5四] 5六龍[1六] info depth 5 pv 1六龍[4六] 3一角[6四] 6七龍[6六] 5五玉[5四] 5六龍[1六] info depth 5 pv 1六龍[4六] 3七角成[6四] 6七龍[6六] 5五玉[5四] 5六龍[1六] info depth 5 pv 1六龍[4六] 3七角[6四] 6七龍[6六] 5五玉[5四] 5六龍[1六]… |
なるほど。このパターンも飽きました。56龍で詰め上がる指し手を除外してみましょう。
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
if (depth == 1 && move_to(m.move) == SQ_56) continue; pos.do_move(m.move, st); > position sfen 9/9/9/3bkb3/9/3+R1+R3/9/9/9 b - 1 > go mate infinite info depth 5 pv 1六龍[4六] 4五玉[5四] 2七龍[1六] 3五玉[4五] 3六龍[6六] info depth 5 pv 2六龍[4六] 4五玉[5四] 2七龍[2六] 3五玉[4五] 3六龍[6六] info depth 5 pv 3五龍[4六] 4二角[6四] 6五龍[3五] 5三玉[5四] 6三龍[6五] info depth 5 pv 3五龍[4六] 5三角[6四] 7六龍[6六] 6四玉[5四] 6五龍[3五] info depth 5 pv 3五龍[4六] 7三角[6四] 5六龍[6六] 6四玉[5四] 6五龍[3五] info depth 5 pv 3六龍[4六] 3三角[4四] 5六龍[6六] 4四玉[5四] 4五龍[3六] info depth 5 pv 3六龍[4六] 5三角[4四] 5六龍[6六] 4四玉[5四] 4五龍[5六] info depth 5 pv 3六龍[4六] 5三角[4四] 6五龍[6六] 4四玉[5四] 4五龍[6五] info depth 5 pv 3六龍[4六] 5三角[4四] 7五龍[6六] 4四玉[5四] 4五龍[7五] info depth 5 pv 3七龍[4六] 4二角[6四] 6七龍[3七] 5三玉[5四] 6三龍[6六] info depth 5 pv 3七龍[4六] 4五玉[5四] 2七龍[3七] 3五玉[4五] 3六龍[6六] info depth 5 pv 4七龍[4六] 1一角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 1七角成[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 1七角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 2二角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 2六角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 3三角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 3五角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 5三角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 6二角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 6二角[4四] 4六龍[6六] 5三玉[5四] 4三龍[4六] info depth 5 pv 4七龍[4六] 7一角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4七] info depth 5 pv 4七龍[4六] 4二角[6四] 6七龍[4七] 5三玉[5四] 6三龍[6六] info depth 5 pv 4八龍[4六] 1一角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 1七角成[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 1七角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 2二角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 2六角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 3三角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 3五角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 5三角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 6二角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 6二角[4四] 4六龍[6六] 5三玉[5四] 4三龍[4六] info depth 5 pv 4八龍[4六] 7一角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4八] info depth 5 pv 4八龍[4六] 4二角[6四] 6八龍[4八] 5三玉[5四] 6三龍[6六] info depth 5 pv 4九龍[4六] 1一角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 1七角成[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 1七角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 2二角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 2六角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 3三角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 3五角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 5三角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 6二角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 6二角[4四] 4六龍[6六] 5三玉[5四] 4三龍[4六] info depth 5 pv 4九龍[4六] 7一角[4四] 3六龍[6六] 5五玉[5四] 4五龍[4九] info depth 5 pv 4九龍[4六] 4二角[6四] 6九龍[4九] 5三玉[5四] 6三龍[6六] info depth 5 pv 5七龍[4六] 4五玉[5四] 2七龍[5七] 3五玉[4五] 3六龍[6六] info depth 5 pv 5七龍[6六] 6五玉[5四] 8七龍[5七] 7五玉[6五] 7六龍[4六] info depth 5 pv 6七龍[6六] 6二角[4四] 4七龍[6七] 5三玉[5四] 4三龍[4六] info depth 5 pv 6七龍[6六] 3一角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 4二角[6四] 6六龍[4六] 5三玉[5四] 6三龍[6六] info depth 5 pv 6七龍[6六] 4二角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 5三角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 7三角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 7五角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 8二角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 8六角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 9一角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 9七角成[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6七龍[6六] 9七角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6七] info depth 5 pv 6八龍[6六] 6二角[4四] 4八龍[6八] 5三玉[5四] 4三龍[4六] info depth 5 pv 6八龍[6六] 3一角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 4二角[6四] 6六龍[4六] 5三玉[5四] 6三龍[6六] info depth 5 pv 6八龍[6六] 4二角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 5三角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 7三角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 7五角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 8二角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 8六角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 9一角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 9七角成[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6八龍[6六] 9七角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6八] info depth 5 pv 6九龍[6六] 6二角[4四] 4九龍[6九] 5三玉[5四] 4三龍[4六] info depth 5 pv 6九龍[6六] 3一角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 4二角[6四] 6六龍[4六] 5三玉[5四] 6三龍[6六] info depth 5 pv 6九龍[6六] 4二角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 5三角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 7三角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 7五角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 8二角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 8六角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 9一角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 9七角成[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 6九龍[6六] 9七角[6四] 7六龍[4六] 5五玉[5四] 6五龍[6九] info depth 5 pv 7五龍[6六] 3三角[4四] 5六龍[4六] 4四玉[5四] 4五龍[7五] info depth 5 pv 7五龍[6六] 5三角[4四] 3六龍[4六] 4四玉[5四] 4五龍[7五] info depth 5 pv 7五龍[6六] 6二角[4四] 4五龍[7五] 5三玉[5四] 4三龍[4五] info depth 5 pv 7六龍[6六] 5三角[6四] 3五龍[4六] 6四玉[5四] 6五龍[3五] info depth 5 pv 7六龍[6六] 5三角[6四] 4五龍[4六] 6四玉[5四] 6五龍[4五] info depth 5 pv 7六龍[6六] 5三角[6四] 5六龍[4六] 6四玉[5四] 6五龍[5六] info depth 5 pv 7六龍[6六] 7三角[6四] 5六龍[4六] 6四玉[5四] 6五龍[7六] info depth 5 pv 7七龍[6六] 6二角[4四] 4七龍[7七] 5三玉[5四] 4三龍[4六] info depth 5 pv 7七龍[6六] 6五玉[5四] 8七龍[7七] 7五玉[6五] 7六龍[4六] info depth 5 pv 8六龍[6六] 6五玉[5四] 8七龍[8六] 7五玉[6五] 7六龍[4六] info depth 5 pv 9六龍[6六] 6五玉[5四] 8七龍[9六] 7五玉[6五] 7六龍[4六] |
次に、攻め方(先手)の指し手は必ず王手でなければならないという条件をつけてみましょう。協力詰めは、普通この条件がついてますし、さきほどの出題図にも本当はこの条件がついています。
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 |
StateInfo st; pos.check_info_update(); for (auto m : MoveList { if (pos.side_to_move() == BLACK && !pos.gives_check(m)) continue; pos.do_move(m.move, st); > position sfen 9/9/9/3bkb3/9/3+R1+R3/9/9/9 b - 1 > go mate infinite info depth 1 info depth 2 info depth 3 info depth 4 info depth 5 info depth 5 pv 4四龍[4六] 6三玉[5四] 3三龍[4四] 5四玉[6三] 1八角打 info depth 5 pv 4四龍[4六] 6三玉[5四] 3三龍[4四] 5四玉[6三] 2七角打 info depth 5 pv 4四龍[4六] 6三玉[5四] 3三龍[4四] 5四玉[6三] 3六角打 info depth 5 pv 4四龍[4六] 6三玉[5四] 3三龍[4四] 5四玉[6三] 6三角打 info depth 5 pv 4四龍[4六] 6三玉[5四] 3三龍[4四] 5四玉[6三] 7二角打 info depth 5 pv 4四龍[4六] 6三玉[5四] 3三龍[4四] 5四玉[6三] 8一角打 info depth 5 pv 6四龍[6六] 4三玉[5四] 7三龍[6四] 5四玉[4三] 2一角打 info depth 5 pv 6四龍[6六] 4三玉[5四] 7三龍[6四] 5四玉[4三] 3二角打 info depth 5 pv 6四龍[6六] 4三玉[5四] 7三龍[6四] 5四玉[4三] 4三角打 info depth 5 pv 6四龍[6六] 4三玉[5四] 7三龍[6四] 5四玉[4三] 7六角打 info depth 5 pv 6四龍[6六] 4三玉[5四] 7三龍[6四] 5四玉[4三] 8七角打 info depth 5 pv 6四龍[6六] 4三玉[5四] 7三龍[6四] 5四玉[4三] 9八角打 |
このように色々と制約条件をつけて探索させたいとき、ソースコードを直接いじって条件を付与できることは大変便利です。こうして見ると、詰将棋作家は検討のために簡単なプログラムは書けたほうがいいのでしょうね。
ここまでのまとめ
縦型探索を用いて協力詰めsolverを書くことが出来ました。次回はもっと難解な協力詰めを解かせてみましょう。
次回に続く
やねうら王mini自体はどれくらい完成しているのですか?
記事とともにデバッグしてる状態でしょうか。
この前書いた探索と、ゲーム木検索で256手まで検索して、カーナビ256っていうソフトを妄想したのですが、ゲーム木検索を書く気がしなくて頓挫しています。
知性とロジックの寒い戦いが見たいような気がするので作りたいのですが、やっていいものかどうか・・・。Orz
あぁ、これ。ただのネタですよ。ただのネタですよ。
考えて思ったのですが、自分には知性の創造は無理そうです。
どうしても冷たいものができてしまう。
記事書きながら、やねうら王miniのソースコードも書いてます(`・ω・´)ゞ
記事書きながらなのでなかなか進みません。
手駒はkif for windowsを使えば無くせるのではないでしょうか
なるほど。Kifu for Windows→ShogiGUIの連携でShogiGUIに局面渡せますね。本文記事に追記しました。ShogiGUIで無事、解答を表示できました。近日中に長手数の協力詰めの解ける思考エンジンを公開しますね。
>厳密に言うとスティールメイトという、後手に指し手がなくなって指し手がなくなるパターンでの詰みもあるのですが・・・
圧縮してみました。
後手に指し手がなくなるパターンでの詰みもあるのですが・・・
修正しました(`・ω・´)ゞ
>こうして見ると、詰将棋作家は検討のために簡単なプログラムは書けたほうがいいのでしょうね。
・・・次の出版はぜひ「やねうら王miniで学ぶC++基礎講座」をお願いします。
そんな難しいテクニックは出てこないので、ここにあるサンプルだけでもそこそこ真似して書くのは出来るのではないかと..。
わかりました。
それではここはBasicしかしらない読者が一通り「やねうら王mini」を読めるようになる(であろうと思われる)、一番優しく書かれたC++入門本の紹介、、、ということで手を打ちましょう。
やねうら王miniのソースコード自体まで理解しようと思うと少しハードルが上がるような…。
@ITのC++の記事、斜め読みするぐらいから始めてみては。
ページ紹介、ありがとうございます。
「やねうら王mini」というのは、とてもよい目標になりそうです。
samuraiさんはBASICできるのですね。
自分もBASIC組でして、小学校のころパソコンクラブでBASICを触ったのが最初です。
高校に入ってポケコンで自由にBASICでミニゲームを作れるようになった後、偽専門当たりでCを初めて最近はC++を触っています。
C/C++が読めるようになるとほんとすそ野が広がりますのでステップアップをおすすめします。
アルゴリズムを編むのは楽しいですよ!
ちなみにCでミニゲーム作るときにネックなのが何かというと、コンソールでのキーコード取得なのですが、VCにはっていう非標準のヘッダがありまして、それの判定に_kbhit()というのを使います。取得がgetch()です。
とりあえず、BASICのコードを移植して覚えるというのもなかなかハードですが楽しいですよ。ウィンドウを出すのは大変ですが、文字使ったゲームは十分移植できます。
あら、消えちゃった。
<conio.h>っていうヘッダにコンソールのIO関係が入っています。
非標準なのでどのコンピュータでもとは生きませんがVCのバイナリが動く範囲では有効です。
うぅ。書くとこ間違えた。
手落ちが多くて泣ける。
テスト。
>conio.h<
ご案内、ありがとうございます。
参考にさせていただきます。
やねうら王をDLしてコンパイルして、exeのあるディレクトリで
YaneuraOu-Debug-mate.exe test_mate_engine
と叩いたんですが、局面は認識してくれるものの解いてくれません。
Position: 6p1l/1+R1G2g2/5pns1/pp1pk3p/2p3P2/P7P/1L1PSP+b2/1SG1K2P1/L5G1L w N2Prbs2n3p 1
bestmove resign
Position: lng3+R2/2kgs4/ppp6/1B1pp4/7B1/2P2pLp1/PP1PP3P/1S1K2p2/LN5GL b RG2SP2n3p 1
bestmove resign
===========================
Total time (ms) : 53
Nodes searched : 0
Nodes/second : 0
Nodes searched(main thread) : 0
Nodes/second (main thread) : 0
なんかコマンドの指定方法がまずいんでしょうか。
USI拡張コマンド.txtにも載っていないもので、申し訳ありませんが教えてください。
将棋所からでもそうなりますか?
まずは、将棋所からその局面を解かせてみて、将棋所のデバッグウインドウ開いて、流れているコマンドを見れば良いような?
将棋所で局面を並べたらちゃんと解けました
1:usinewgame
>1:position sfen 3sks3/9/4+P4/9/9/+B8/9/9/9 b S2rb4gs4n4l17p 1
>1:go mate infinite
<1:info string pn 0 dn 100000000 nodes_searched 133
<1:info time 10 nodes 133 nps 13300 hashfull 0
1:quit
test_cmd.cppの1951行目にsfenの配列があって、1981行目のtest_mate_engine_cmdの中にforでぐるぐる回しているような記述があったので、”test_mate_engine”コマンドを使うとこれらの局面を次々読んでくれるものなのかと勝手に思ってました。
DEBUG用だと思うので、今後の開発時に使いたいなぁ……と思っていたんですが、TestMateEngineSfen[]の問題群を解かせるのはどのようにやればいいんでしょうか(すいません質問が下手で)。
その機能は搭載してないので、benchmarkコマンド改造するか、Ayane使うか(少し改造必要かも)、ですかね…。(^^ゞ
そうだったんですね。
頑張ってみます。ありがとうございました。変な話で申し訳ありません。