連載やねうら王miniで遊ぼう!1日目

やねうら王miniのソースコードを実際にいじって、盤面を操作したりして遊ぼう!という連載記事です。

※ やねうら王miniのソースコードは年末までにGitHubで公開する予定です。

今回は環境設定からビルド手順まで。

連載の目的

将棋の合法手生成だけでも初めて書くととても大変で、上位のソフト、例えば、Apery並の速度にしようとすると困難を極めるわけである。

こういう部分が、将棋ソフトの開発を難しくてしている一因であり、お手軽に使える高速な指し手生成ルーチン、お手軽に使える(自分のソフトに組み込める)Bonanzaのような三駒の評価関数が必要とされている。

やねうら王miniのソースコードはその基盤となるソフトウェアライブラリとして十分な性能と手軽さ、ソースコードの短さ、わかりやすさを兼ね備えている。

そこで、やねうら王miniのソースコードを利用して、独自の将棋の思考エンジン、もしくは将棋に関する何かのプログラムを作ることを想定し、そのための方法を解説するのが本連載の目的である。

ビルドについて

やねうら王miniは、Visual C++ 2015のプロジェクトファイルを開いて一発でビルドできる。Visual Studio 2015 Express、もしくはVisual Studio Community 2015は無償で入手できる。入手方法はggrks(ググレカス)である。

ソースコードをGitHubから

GitHubからソースコードを取ってくる方法?それもggrksである。
※ やねうら王miniのGitHubのアドレスは公開後にここに追記する。

ターゲットCPUの選択

shogi.hの以下の部分をコメントアウトすれば、AVX2命令を使わない実行ファイル、SSE4.2命令を使わない実行ファイルを作ることが出来る。(AVX2命令が使えるCPUならSSE4.2は使えるはずだ。)

※ shogi.h は types.h と config.hになりました。[2019/05/23]

あとVisual C++ 2015では、やねうら王miniのプロジェクトの設定のところでターゲットCPUがAVX2になっているところを変更しないといけないかも知れない。

※ プロジェクトの [プロパティ ページ]→[構成プロパティ]、[C/C++]→[コード生成]→[拡張命令セットを有効にする]→[Advanced Vector Extensions 2 (/arch:AVX2)]をお使いのCPUに合わせて変更。詳しくはggrksである。

古いCPUの対応について

本来なら、Haswellのpextを使えないなら、pextを使わずにそこそこの速さで動くコードも用意すべきである。Aperyではpextを使わずに遠方駒(香・角・飛)の利きを求めるコードには、magic bitboardが用いられていて、pextが使えない環境でもほとんど速度低下をさせずに動作させることが出来る。それは作者の平岡さんの大変な努力の賜物ではあるが(もともとAperyではmagic bitboardを使って実装してあって、そのあとpextを使う実装を追加したから結果的に両対応になっているとも言える)、やねうら王miniの場合は、新規に開発しているので、近い将来、市場から無くなっていくCPUのためにそこまでサポートしていられないのが実情である。

そこで、別の実装を用意するのではなく、pext命令やpopcnt命令自体をエミュレーションするコードを書くことにした。

…というと格好いいかも知れないが、以下のようにすこぶる遅い実装にならざるを得ない。(このコードを理解する必要はない。興味のある人向け。)

その代わり、ソースコードのなかでpextをいくら使っても都度古いCPUのためにpextを使わない実装を用意する必要がない。これはこれで現代風の解決法であると思う。

とは言え、popcnt命令のエミュレーションコードについてはさらにひどい。

popcnt命令は、ある整数型の変数をbit列とみなしたときに1であるbitを数える命令であるから、もうちょっとマシな実装をしようと思えば古来より伝わる秘伝を用いれば、もちろん色々と出来るわけであるが、結局、古いCPUではとりあえず動けば良いと割りきってある。詳しく知りたい人は”counting 1bits”でggrksである。

追記

コメント欄でpextのもう少しいい実装を教えていただいたので次のようにしてみました。POPCNTも、コメント欄にいただいたコードに差し替えました。ハードウェアで実装するよりは全然遅いですけど、ソフトウェア実装としてはかなり良くなりましたということで…。

次回に続く。

連載やねうら王miniで遊ぼう!1日目」への19件のフィードバック

  1. USE_AVXの部分は、AVXが使えてもPEXTは使えないCPUもあるので、USE_AVX2またはUSE_BMI2としたほうが良いと思います。

  2. >入手方法はggrks(ググレカス)である。

    何というキタナイコマンドなんでしょう!!

    • 古いPCでも一応は動きます!プログラムいじるだけなら古いPCでも全然問題ないと思います。強さはどうせAperyのほうがはるかに強いですし…。

  3. 今思ってる改造の方向性はNDFですね。
    基礎能力は屋根さんのほうははるかに上なのでそこをいじらず、サブの部分を改造するところから初めてどれくらい強くなるか。っていうのを妄想しています。
    まぁ、読めればですけど。
    ちなみに、最近PC買い換えてCPUがスカイレークになりました。ドンとこいデス。

  4. 「自分も将棋ソフト作ってみたい…
    でもプログラミング全然ワカンネ。おやすみー」と思ってる人間は自分だけじゃないはず…
    コンピュータ将棋を身近なものにしてくれそうなこの連載、非常に楽しみにしてます。

  5. やねうら王mini、とても楽しみにしております。
    Bonanzaより強いとなると、やねうらおさんほどの方でも5000行くらいは行くような気がしています。個人的には、ぜひ学習部を解説してほしいと思っております。
    pextの自前実装については、私が調べた限りでは、下で紹介されているコードがもっともスマートかつ高速だと思います。(あまりこのあたりにはこだわっていないのかも知れませんが)
    https://chessprogramming.wikispaces.com/BMI2
    すでにご存知かもしれませんが、参考になれば幸いです。

  6. 流石にpopulation countをループで解決するのはアレなので大体こんな感じになるんですかね。

    inline int32_t POPCNT8(uint32_t a) {
    a = (a & UINT32_C(0x55)) + (a >> 1 & UINT32_C(0x55));
    a = (a & UINT32_C(0x33)) + (a >> 2 & UINT32_C(0x33));
    a = (a & UINT32_C(0x0f)) + (a >> 4 & UINT32_C(0x0f));
    return (int32_t)a;
    }
    inline int32_t POPCNT32(uint32_t a) {
    a = (a & UINT32_C(0x55555555)) + (a >> 1 & UINT32_C(0x55555555));
    a = (a & UINT32_C(0x33333333)) + (a >> 2 & UINT32_C(0x33333333));
    a = (a & UINT32_C(0x0f0f0f0f)) + (a >> 4 & UINT32_C(0x0f0f0f0f));
    a = (a & UINT32_C(0x00ff00ff)) + (a >> 8 & UINT32_C(0x00ff00ff));
    a = (a & UINT32_C(0x0000ffff)) + (a >>16 & UINT32_C(0x0000ffff));
    return (int32_t)a;
    }
    inline int32_t POPCNT64(uint64_t a) {
    a = (a & UINT64_C(0x5555555555555555)) + (a >> 1 & UINT64_C(0x5555555555555555));
    a = (a & UINT64_C(0x3333333333333333)) + (a >> 2 & UINT64_C(0x3333333333333333));
    a = (a & UINT64_C(0x0f0f0f0f0f0f0f0f)) + (a >> 4 & UINT64_C(0x0f0f0f0f0f0f0f0f));
    a = (a & UINT64_C(0x00ff00ff00ff00ff)) + (a >> 8 & UINT64_C(0x00ff00ff00ff00ff));
    a = (a & UINT64_C(0x0000ffff0000ffff)) + (a >>16 & UINT64_C(0x0000ffff0000ffff));
    return (int32_t)a + (int32_t)(a>>32);
    }

    • はい、それが普通でしょうね。よくあるcount 1 bitsのコードですね。POPCNT自体はほとんどソース上で使ってないので影響軽微&ソースコード長くなる&古いCPUはとりあえず動けばいいかぐらいの感じなのでいまのコードにしましたけど、せっかくなので使わせてもらいます!(`・ω・´)ゞ

コメントを残す

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