将棋AIの大会である電竜戦に新規参入者を増やそうとする試みとして準備しつつある1file matchですが,個人的に盛り上がってシリーズ化の勢いです。
1file match(仮)の参考資料 - 48's diary
前回ランダム指しと言うプログラムを提案しましたが,わずか40行くらいなので初級者でもさっと読めたと思います。ただ,動かすと全く勝てない。弱いですね。
ランダム同士だと何しているのか分からないくらい無駄な時間を感じます。
ただ,ランダムって手法自体は古典的で結構有用な方法です。例えば最近ChatGPTなる対人支援AIが流行っておりますが,そんなものより昔からずっと有料で99%以上の粗利を稼ぐ「おみくじ」と言う対人支援AIがランダム選択と言うアルゴリズムで成功を修めています。
そういえば前回numpyという豪華なライブラリをimportしてnumpy.random.choiceだけを使うと言う富豪プログラミングをしてしまいましたが,普通の人はimport randomでrandom.choiceを使えば本件では十分です。numpy.random.choiceは重みを付けたり重複の有無を指定して複数サンプリングができたり高機能です。
で,今回はこのランダムモデルからレート1300以上上げるのが目標です。
界隈でレートと言えばイロレーティングなのですが,簡単には計算サイトがあります。
イロレーティングのレート差と勝率の相互変換 - 高精度計算サイト
基本的には絶対値に意味はなく「差」だけが意味を持ちます。ただし,基準値が固定されれば絶対値に意味が生じます。(現在のfloodgateではgikou2_1cが3300と固定されています。)
せっかくですので,ちょっと考えてみましょう。藤井竜王名人が並のプロ棋士に9割勝つとします。イロレーティングでは大凡400差となります。並のプロ棋士がアマ高段者に9割勝つとします。これもイロレーティングが400差となります。これで藤井さんとアマ高段者の差が800と計算されます。期待勝率は99%ですね。
アマ高段者がアマ初段に9割勝つとすれば,これまたレート差が400です。これで藤井さんとのレート差が1200,期待勝率が99.9%となります。1200と言うのがこういう感じです。
同様に見ていくと恐らくアマ初段と初級者の関係もレート差1200くらい,期待勝率99.9%くらいになると思われます。実際はもう少しは大きいでしょうか。
これで藤井さんと初級者のレート差が2400で期待勝率が99.9999%と概算されます。藤井さんに初級者と1000000回対局してもらうのは無理ですが,適当な相手を置いた対戦を組んでそれぞれ相対レートを求めることが出来れば概算できると言う仕組みです。
結果人間の棋力ってのは2500~3000くらいのレート幅で整理できることが分かります。
将棋指しの方ならプロ相手に二枚落ちでアマ初段,アマ初段相手に二枚落ちで初級者レベルと言った方が伝わるでしょうか。
前置きは長くなりましたが,前回のランダム相手に99.95%以上勝つものを作ります。1999勝1敗でこの数字なのですが,実際の計測は2000戦全勝ですのでこれ以上ということでレート差1300以上とします。(気づいていると思われますが,これから作るものが強いのではなく前回のランダムが弱いのです。)
まず,一手詰めです。これを逃しては将棋ではありません。
級位者では一手詰めが概ねできれば8級認定だそうです。真面目な話をすると王手をかけて,相手にその王手を解除する手が無ければ詰みです。しかしながら,cshogiには便利な関数が既にありmate_move_in_1plyを呼べば一手詰みの手があれば返ってきます。気を付けるのは自玉に王手がかかっていないことを事前確認するだけです。理屈が分かれば,この関数を使わなくても自力で実装するのもそんなに難しくないはずです。
次に駒を取る手です。
人間の場合,ルールを覚えたら真っ先に見える手と言う感じでしょう。
将棋では駒の移動先に相手の駒があれば取れるわけですが,cshogiでは合法手リストを作成したときに既に駒を取る指し手であるかどうかわかっています。
https://github.com/TadaoYamaoka/cshogi/blob/master/src/move.hpp
ここですね。0b00000000111100000000000000000000の部分が取る駒の駒種を表しています。ビット演算でANDを取れば駒を取る手のみ正の値,それ以外は0となります。
成る手です。これも人間の入門者が大好きな一手のはずです。人間では全ての合法手リストを作成するまでもなく指し手候補になると思います。
駒を取る手と同様に駒を成る手は0b00000000000000000100000000000000とAND演算すれば成る手のみが正の値を持ちます。
合わせた0b00000000111100000100000000000000でANDを取るとどうなるか考えてみて下さい。
駒を取る手も成る手も無ければ全部0ですね。
そのときはランダムにしましょう。
ということで効率的に行うためにまず合法手をすべてランダムで並べ替えて,上記フィルタでANDを取った値が最も大きいものを見つけるという手段を取ります。
以上の改造を前回のものに加えたのがgoのところだけ数行ですが以下のようになります。
今回はnumpyを使いませんでしたので
もしておいて下さい。
Python入門者はゆっくりどういう意味かじっくり読んでみて下さい。
ちょっとした技をつかっていることが分かると思います。
難しければ質問など頂ければ可能な限り対応しますが,読む努力をしないと自分で作れるようにはなりませんので時間をかけて頑張ってみて下さい。
---
ちなみに:
これくらいではコンピュータ将棋界最初の壁と呼ばれるLesserKaiには勝てません。
LesserKaiのレートがfloodgate基準で700だとか1000だとか言われていますのでまだまだと言うことです。