将棋ソフト用の標準定跡ファイルフォーマットの提案

やねうら王、いままでに何度か定跡ファイルを作っているのですが、過去、SQLiteを用いていました。しかし、そんなに登録する局面が多くなるわけでもないですし、メモリが足りないわけでもないので、いまどきは「起動時に定跡ファイルを丸読みしてstd::mapにでも持っておけばいいじゃん」ということに落ち着くように思います。

また、昔なら、局面のhash keyをキーとして保存しておくのが流行ったのですが、そんなところで省メモリにしても仕方がないですし、何かソフトを作り変えたときに同じ局面でもhash keyの値が変わってしまうこともありますし、hash keyの値をキーとするのはもう流行らないのではないかと思うわけです。

そこで次のようにsfen文字列を1行目に書いて、2行目以降にその局面での指し手、相手の予想される応手(ないときは”none”)、その指し手で局面を進めたときの評価値、この指し手の探索深さ(探索した結果求めたものであるなら)を書くことにします。この構造で1局面における指し手(複数)を定義できて、この構造が繰り返されることで定跡ファイルとなります。

※ 指し手はUSIプロトコルの指し手文字列をそのまま用います。

次に、このファイルを手で作るのは比較的面倒なので、floodgateの棋譜から作る方法を考えます。

CSA形式のファイルからsfen形式のファイルへの変換はBlunder.Converterなどで変換できるので、floodgateから適当な棋譜を持ってきて、sfen形式の1本のファイルにしてしまいます。

次に、sfen形式の棋譜を読み込んで指定手数までを上の形式に変換するプログラムを書きます。というか、書きました。

https://github.com/yaneurao/YaneuraOu/blob/7cd58bfd4b8fbd8c524219235986cf08c9419297/source/extra/book.cpp

やねうら王nanoをビルドして、
> makebook book.sfen book.db moves 24
とすれば、book.sfenを読み込み、book.db(上の形式)というファイルを書き出します。movesのあとに24と指定してあるのは初手から24手目までを定跡として出力するという意味です。

また、私がfloodgateの棋譜を適当に選んで、上の方法で定跡ファイルを作ったものも公開しておきます。ご自由にお使いください。

https://github.com/yaneurao/YaneuraOu/blob/7cd58bfd4b8fbd8c524219235986cf08c9419297/docs/book.db

あと、この形式での定跡編集のための何らか補助ツールか、探索させて評価値を出力するツールか何かをこのあと作るかも知れません。(やねうら王2016の探索部がそれなりに出来てから。)

2016/02/05 15:20追記

指し手の出現頻度等、フォーマットを少し拡張しました。詳しくはコメント欄をご覧ください。

そのコメント欄の修正をした定跡DBも公開しておきます。

https://github.com/yaneurao/YaneuraOu/blob/9518b5870b9cb5fe72d567d4fdf0e52fb988eb05/docs/book.db

2016/07/12 14:00追記

やねうら大定跡を作るに当たって、思考させたエンジンのバージョンが指し手のところに記録されていて欲しかったので、出現頻度(これは自ら思考して生成した定跡であれば不要のはず)のところを、エンジンのバージョンナンバーを100倍(V3.21なら321)したものを埋めることにしました。

また、評価値つきの指し手の場合、手番側から見たスコアが良い順に並んでいて欲しいので、やねうら大定跡ではそのことを保証するように変更しました。

2016/7/15 24:00 追記

sfen文字列は本来は一意に定まる件 にあるように手駒は「飛車、角、金、銀、桂、香、歩」の順番とします。

2020/12/03 24:00 追記

・move(指し手) ponder(その次の指し手) が必須項目(ただしponderが無い時はnone)。そのあとはoptional(あってもなくても)とします。

・move(指し手) ponder(その次の指し手) value(評価値 歩が100点とする) depth(その時の探索深さ) nove_count(出現頻度) …。

のようにoptionalな項目は、続けたければ続けられるものとします。

将棋ソフト用の標準定跡ファイルフォーマットの提案」への25件のフィードバック

  1. こういう手法で定跡やツールの共有ができるようになるととても嬉しいです。

    以下、ざっと思いついた点です。

    – ある局面に対する指し手の選択率列が欲しい人がいそう。

    – 逆に開発者の考え方次第で指し手で不要な列もあるかも。不要な場合の書き方もフォーマットとして決めた方が良いかも(1列目は必須で、2列目以降の不要列は”-“とか)

    – 局面や指し手にコメントも入れたい場合があるかも。そうなると、ASCII以外の文字を書きたいこともあるから、文字コードも決めた方が良いかも(UTF8あたり?)

    – フォーマットのバージョン番号がどこかに欲しいかも。ファイル先頭あたり?

    – フォーマットの名前は?かっこいい名前をつけて欲しい。

    – 左右ひっくり返したら同じになる局面は同一視する?しない?

    – 盤面を180度回転して手番を変えたら同じになる局面は同一視する?しない?

    • > – ある局面に対する指し手の選択率列が欲しい人がいそう。

      追加しておきました(`・ω・´)ゞ
      https://github.com/yaneurao/YaneuraOu/commit/891b8afee640d54699e3c96598528e60d38d9936

      > – 逆に開発者の考え方次第で指し手で不要な列もあるかも。不要な場合の書き方もフォーマットとして決めた方が良いかも(1列目は必須で、2列目以降の不要列は”-“とか)

      2列目不要なら”none”と書けば省略できます。StockfishはMOVE_NONEのとき、文字列として出力するとそう出力されたはずなので一番対応が楽かなと。

      > – 局面や指し手にコメントも入れたい場合があるかも。そうなると、ASCII以外の文字を書きたいこともあるから、文字コードも決めた方が良いかも(UTF8あたり?)

      各行、コメントは書いても無視されます。(規定列以降をparseしないため)
      念のため、”//”のあとに書くようにしておけばいいかと思います。

      また、文字コードはUTF8でいいと思います。(規定列までがASCII文字列として読めれば何でも良いので)

      ただ、起動時に読み込むので少しでも速く読み込みたいため、コメントがあまりたくさんあるのは嬉しくない気もします。

      > – フォーマットのバージョン番号がどこかに欲しいかも。ファイル先頭あたり?

      なるほど。先頭行に “#YANEURAOU-DB2016 1.00” のように書くことにします。

      > – フォーマットの名前は?かっこいい名前をつけて欲しい。

      “やねうら王定跡フォーマット2016″にします。(`・ω・´)ゞ

      > – 左右ひっくり返したら同じになる局面は同一視する?しない?
      > – 盤面を180度回転して手番を変えたら同じになる局面は同一視する?しない?

      同一視しないです。レアケースなのでまあいいかと。

      • ネガティブ定跡は表現可能でしょうか?
        或局面が既に必敗なので入っちゃダメというような。
        先頭に局面自体の評価があればいい?

        • > 先頭に局面自体の評価があればいい?

          評価値自体は3列目にありますのでそこの値を-10000とかにしておけば「その指し手は絶対に指したら駄目」の意味だとソフト側が解釈することは可能かと思います。

          Stockfish系は、RootMoves(探索開始局面での指し手の集合)としてgoコマンドのときに探索させたい指し手の集合を指定するようなことが出来るので、定跡上の指し手の評価値がすべて-10000以下であれば、それらをRootMovesから除外して探索するのは数行書くだけで出来ますし…。

          • どうもです。
            コンピュータ将棋を組む経験はなくて、ゲームはじゃんけんプログラムを組もうとした経験しかないですが、、、

            ネガティブ定跡は、或局面からこっちにいっちゃダメ、というのではなく、どんな局面からでもココに来ちゃダメっていう登録がしたいんじゃないでしょうか。
            通常の定跡を追うのと逆方向ですけど。
            うまく使えるプログラムができるかどうかはべつとして、
            また、ネガティブ定跡でパッチ当てるなんて姑息で美しくないですが、
            フォーマットとして需要はあるかと思います。

            あと、局面の元ネタ情報、誰それのいついつの棋譜、とか、局面の解説情報infostringもあると便利かと思います。

          • > どんな局面からでもココに来ちゃダメっていう登録がしたいんじゃないでしょうか。
            > 通常の定跡を追うのと逆方向ですけど。

            本記事のフォーマットで、ある指し手を指したあとの評価値を書けますので、来て欲しくない局面Xがあるとして、その1手前の局面で、Xに至る指し手の評価値を-10000とかにしておけば、定跡DBを読み込み時に、Xの局面の評価値を-10000として置換表に登録できますので、ご希望の動作になると思います。

            > あと、局面の元ネタ情報、誰それのいついつの棋譜、とか、局面の解説情報infostringもあると便利かと思います。

            なるほろ。まあ、各行、”//”以降にコメントを書くとしてそこの内容、(思考エンジンが)GUIに対して出力したければ出力すればいいのかなと思います。定跡は結局、コンピューターが人間の序盤を遥かに上回ってきたときに(数年後?)、もう人間の対局棋譜自体に意味をなさなくなりますので、「誰がいつ」という情報自体に価値がなくなるのではないかと思うので、個人的には要らないかなと思っています。

            逆に、コンピューターに定跡を作らせるとして、そのときの探索深さには意味がありますので、探索深さを書いておく列があります。

      • もっと長持ちしそうなフォーマット名にするかと思ったら、“やねうら王定跡フォーマット2016″でびっくりしました。来年になったら新しいフォーマットが出そうな名前ですね。せめて、”2016″はフォーマット名じゃなくてバージョン番号(バージョン名?)に入れる方が良いのでは?

        それから、ファイルの拡張子が*.dbになってますが、*.ypo (Yaneuraou Portable Openings)はどうでしょうか?*.yno (Yaneuraou Network Openings)とか、*.yoo (YaneuraOu Openings)も良いかも。

        あと、「起動時に定跡ファイルを丸読みしてstd::mapにでも持っておけばいいじゃん」の件、github上で公開してくださってるsource/extra/book.*で実際にstd::mapに持ってますけど、そこはstd::unordered_mapの方がメモリ消費が少し多くなるので、より、”いまどき”らしいかも。

        その他、色々、了解しました。ありがとうございます。

        • > ”2016″はフォーマット名じゃなくてバージョン番号(バージョン名?)

          なるほど…。まあ、やねうら王の将来のバージョンではこのフォーマット自体使わない可能性もあるので、とりあえず”2016″でいいかなと…。

          > ファイルの拡張子が*.db

          編集のしやすさから言うと*.txtのほうがいいような気もしますけども(中身、本当にテキストファイルなので)、あまり拡張子増えていくの好きでないので、とりあえず”*.db”でいいかなと…。

          > std::unordered_mapの方が

          データ多くなってきたときに読み込みが速いのでそのほうがいいかも知れませんね。なおしておきます。(`・ω・´)ゞ

  2. あらま、先を越されてしまいましたねぇ。
    似たようなことをやろうと思っていたのですが腰が重くて頓挫してました。(もちろん標準フォーマットまで提案しようとは思っていません。)
    まぁ、門外漢なので標準があるならその時の標準を使うまで。
    でも、学習のために時が来たら自己流を試してみますかね。いつのことかは知りませんが。
    しかし、サクッと書けちゃうもんなんですね。さすがにそこは真似したいですよ。

  3. 「昔なら、局面のhash keyをキーとして保存しておくのが流行った」ってどういうことなんですかね?何かのメリットがあって、64-bit に圧縮した局面の hash key で定跡データを保存することが流行っていたってことでしょうか?

    • 64-bitなのはそうですが、圧縮とは普通言わないですね。(不可逆なので) 局面を可逆圧縮するには256-bit必要です。

      64-bitというのは、探索の時に置換表に局面の情報を保存するために計算しているhash keyが64-bitなので、それを使い回すという意味ですね。Aperyとかそうなっています。(いました) そうすると同じ値のhash値を持つ別の局面と混同するケースが稀に出てくるのですが、まあ、それには目を瞑るか、game ply(初期局面からの手数)も定跡DBに保存しておき、game plyが異なれば別の局面とみなすかですね。

  4. YANEURAOU-DB2016 1.00 フォーマットを GPL-3.0 よりもゆるいライセンスで出していただけないでしょうか?例えば、MIT 系のライセンス下のプロジェクトで YANEURAOU-DB2016 1.00 フォーマットに対応する行為はどう捉えられるのでしょうか?

      • > この定跡フォーマットはMIT Licenseとします。

        MIT License はデータフォーマットやそのスペックに適用するものではないと思います。
        パーサーやジェネレーターに適用されるなら分かります。

        > 何も書かないとやねうら王と同様にGPLv3になってしまう

        こちらも同様に趣旨がよく分かりません。

        • フォーマットにはライセンス適用できないのか…そうか…。本文の該当部分を削除しておきました。

          それとは別に、やねうら王の定跡の読み込み部のソースコード、ここは私が独力で書いた部分なのでこれをMIT Licenseとしたく、それでその部分のソースコードは自由に使ってもらえればという感じのことが書きたかったのですが、それとごっちゃになってました。

  5. 質問があります。

    1. 以下ような、局面情報のみから成るのやねうらおう定跡2016形式ファイルや局面が一つもないものは OK ですか?


    #YANEURAOU-DB2016 1.00
    sfen lnsgkgsnl/1r5b1/ppppppppp/9/9/7P1/PPPPPPP1P/1B5R1/LNSGKGSNL w - 2
    // この局面はすごい。
    sfen lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1
    // この局面もすごい。


    #YANEURAOU-DB2016 1.00

    2. 先頭行以外のsfen または USI 指し手文字列以外から始まる行はすべてコメントとなり、sfen または USI 指し手文字列から始まる行は全てコメントでないということでしょうか?
    例えば、


    #YANEURAOU-DB2016 1.00
    この局面はすごい。

    は OK でしょうか?

  6. やねうら王定跡フォーマット2016では、定跡内に複数の同一sfen文字列があった場合、どのような挙動になりますか。

    例1
    角換わり定跡などでは手数違いで同じ盤面などあり、手数によっては登録指し手が異なることがありますが、IgnoreBookPlyをTrueにした場合

    例2
    複数のやねうら定跡を結合することで、初期盤面のsfen文字列がファイル内のあちこちに散逸する場合

    • 同じ局面なので、その場合、(その複数の同一局面に登録されている候補手の)merge動作になる気がします。(検証してないのでわかりません><)
      まあ、検証してみてくださいませ…。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です