09 November 2019

    詰み判定処理導入でレスポンス改善

     今回は前回の記事で紹介したもう一つの方法、詰み判定処理を導入したやり方(前回の記事の「方法1」)で試した結果について書いてみます。既存のアプリ(3三将棋5五将棋7七将棋禽将棋)は全て相手玉を取れば勝ちという簡潔な評価関数(「方法2」)を使っていて特別な詰み判定処理を行っていなかったのですが、今回チェスアプリで二つの方法を試してなかなか有用だということがわかったので、今後7七将棋禽将棋にも採用しようと思っています。詰み判定処理を使うと何が良いかというと、一つは全体的に読みの深さを浅く出来る(玉、キングを取るところまで読む必要がない)ことで、テストスクリプト内の読みの深さのパラメータを全て一手少ない値にしたのに、テスト結果が同じなんてことになります。もう一つの利点は局面の評価をする際に細かく制御出来る点です。

    詰み判定導入で局面に依って読みの深さが変わる

     例えば評価関数内でこういう条件が成立すれば王手放置で先手の勝ちと結論が出たとします、結論が出たらすぐに評価関数からreturnするのですが、そうじゃない場合(if〜else文のelseの場合)には新たに読みの深さを指定して先読みを継続するという形になります。評価値を計算する計算式は同じでも、局面評価のタイミングの違いによって指し手が変わるようです。今までは何手先まで読むと指定すれば全局面を一律に評価して効率的な枝刈りはαβ法に任せていた1わけですが、評価関数内で詰み判定(終了判定)することでより細かく制御できます。巷の将棋ソフトで「局面に依って読みの深さを変える」という機能を耳にしたことはあるのですが、こういうことなのかもしれません。他の人の将棋ソフトのソースコードを追ったことはないのであくまで想像ですが…。
     言葉で説明しても違いがよく伝わらないと思うので、いずれ安定したら3三将棋アプリ同様に何らかの形(CLI版だけとか)で公開したいと思います。

    前回の問題で指し手が変わった

    例1:Bf6のステイルメイトを避ける

    (クリックで画像拡大)

    テスト1

     評価方法を変えたらステイルメイトに対応しているはずなのに、ステイルメイトになる手(Bf6)を選んでしまいました。
     調べてみるとこれは前々回の記事のようにステイルメイトの局面を勝ちの局面と誤って評価したわけではなく、ステイルメイト(引き分け)にした方が先手にとって良いと判断したようです。前回の記事でステイルメイトの場合はDraw(評価値=0)を返すようにしたわけですが、この局面は評価値0よりも先手(White)にとって悪い局面で、引き分けにした方がいいと判断されたようです。評価値を計算する数式は変更していないのですが、評価関数に詰み判定を導入した(前回記事の「方法1」)ことで指し手が変わりました。
     ところでステイルメイトの局面の評価値は一体どのように計算すればいいのでしょうか?打ち歩詰めの評価値は「打ち歩詰めをした方が負け」相手玉を詰めたら勝ちの将棋だけど「打ち歩詰め」の場合は相手玉を詰めた方が負けという分かり易いルールなので、局面の静的評価値に−1を掛けて評価を真逆にしました。しかしステイルメイトの場合はステイルメイトの局面にした方が負けというわけではないので−1を掛けるのはやり過ぎだと思います。単純に引き分けだから0がいいだろうと思ってそうしたのですが、多くの場合ステイルメイトは劣勢な側が何とか引き分けに持ち込んで負けを逃れる類のものなので、優勢な側は出来ればステイルメイトを避けたいはずです。かと言ってステイルメイトでいきなり負けになるわけでもないので−1を掛けるのではなく、−0.7を掛けることにしました。
     すると以下のように指し手が変わりました。 (クリックで画像拡大)

    テスト2

     ナイト(♘)をe6に移動(Ne6)として見事にステイルメイトを避けました。前回の記事の指し手(Nf7)より良い手のような気がします。
     あと、実行時間が大幅に短縮されているところも見逃せないところです4277ms -> 70ms
     ちなみに前回の記事の「方法2」でもステイルメイトの局面に-0.7を掛ける処理に変更したところ、今回と同じ手(Ne6)を指すようになりました。-0.7という数値が妥当かどうかは不明ですし、評価値自体に問題があるのかもしれませんが、取り敢えずこのやり方にしました。

    例2:c8=Qのステイルメイトを避ける

    (クリックで画像拡大)

    テスト3

     前回記事の例題2では、ステイルメイトの局面の評価値を0にしても-0.7を掛けても同じ指し手(c8=B)でした。例題1と違い、先手(White)が圧倒的に有利なので当然こうなるべきでしょう。

    2種類の評価関数の比較

     方法1(詰み判定処理有り)と方法2(玉を取るまで読む)では、上記の例以外にもいろいろ指し手の違いが出てきます。既存のアプリで採用している「方法2」の方が以前の記事で紹介したように詰みを読むことに関しては正確だと思いますが、いくら正確に読んでいると言っても、実際のアプリではレスポンス改善のために候補手を削っていますので最善手を逃しているケースも多いと思います。7七将棋アプリ禽将棋アプリでは時間短縮のために全ての指し手の20%も読んでいないと思います。結局時間との兼ね合いで妥協せざるを得ないのなら「方法1」のやり方に移行してもいいだろうと考えています。
     また、以前の記事で「駒の働き(モビリティ)」について書いたことがありますが、詰み判定処理をする際に王手(チェック)が掛かっているか、相手の駒の利きに入っているかなどを検証する必要が出てくるのですが、その処理を評価値計算の処理に流用して、より複雑な評価値計算を効果的に出来るのも「方法1」の有用な点です。


    1. 全局面を一律に評価していると言っても、評価値順にソートして評価値の低い手は読まない等の独自の枝刈り処理は行っています。 



    blog comments powered by Disqus