11 February 2020

    将棋と同じにしていると、いろいろ不都合が

     将棋関連のアプリ(5五将棋7七将棋アプリ禽将棋アプリ)と同じ評価関数でチェスアプリをリリースしましたが、いろいろ不都合が出てきたのでチェスアプリの評価関数に将棋アプリには無い独自の属性を追加していろいろ試しました。最終的には不採用にしたものもあるのですが、どんなことを試行錯誤していたのか紹介します。

    1.キャスリングに加点する

     チェスアプリをリリースした当初は、ここはキャスリングする一手だろうと思われるテストケースを用意して、その局面でキャスリングの手を選ぶように評価値を加減していました。先読みの過程で、キャスリングしていない局面からキャスリングした直後の局面の評価値に下駄を履かせて、無理やりキャスリングするようにするわけです。
     例えば以下のような局面です。

    局面1:白番。最善手はキングサイドキャスリング?

    局面図1

    局面2:黒番。最善手はクイーンサイドキャスリング?

    局面図2

     キャスリングが最善手と思われる局面を適当に用意して、キャスリングの手を選ぶように評価値を加減していたのですが、こういう付け焼き刃なやり方はどこかで歪みが出てくるのが常で、chess.comのコンピュータ対戦テスト中にアプリがかなり優勢な局面で悪手と言えるキャスリングを選んだのをきっかけに採用するのを止めました。
     chess.comでコンピュータとの対戦1テスト中に出現した一例が以下の局面です。

    局面3:黒番。キャスリングは悪手

    局面図3

     この局面でアプリ(黒)がクイーンサイドキャスリングしました。キャスリング自体は悪い手では無いと思いますが、h2のクイーンが只で取られてしまいます:sweat_smile:このケースを切っ掛けにキャスリングの評価値に下駄を履かせるのはやめました(Version1.0.1.4)

    局面4:局面3からBf3と指したところ。

    局面図4

     今では上図のように3の局面からBf3+と指すようになりましたが、キャスリングの評価値に下駄を履かせるのを止めた所為か、対局全体を通して滅多にキャスリングをしないチェスアプリになってしまいました。これは評価関数そのものに問題があるのかもしれません。また、局面1のケースではキングサイドキャスリングせずにQc7と指すようになりました。これがキャスリングよりいい手なのかどうかは分かりません。チェス初心者なので尚更分からないのですがどうも自分のチェスアプリは居玉のまま無理攻めしていくような印象があります。

    2.チェスの方が千日手回避し難い

     自分の将棋関連のアプリは、駒の損得が発生しない状況だとあまりにも千日手になるケースが多く、対局が楽しめないのでなるべく千日手を避けるようにしています。アプリが不利な状況の時に負けないために戦略的に千日手を狙うというのではなく、予備の手を用意しておいて千日手になりそうな時は予備の手を選ぶという単純な機能です。勝負に負けないためではなく、千日手を回避することを目的にした機能です。
     将棋アプリだと予備の手を一つ用意しておくだけでほとんど千日手になることは無いのですが、チェスアプリで同じ機能をつけていてもよく千日手になってしまいます。
     例えば以下のようにアプリ側(白)が圧倒的に有利であっても黒が千日手を狙ってくるとリリース当初は簡単に千日手になっていました。

    局面5:

    局面図5

     予備の手を用意していても、この局面ではルークやビショップが一路違うだけで指し手の意味があまり変わらない手がいっぱい存在する局面なので、Bf4,Bg3,Bh2やRg6,Rf6,Re6などの似たような手を繰り返すだけで、黒のキングがb7近辺を動いているだけで簡単に千日手になってしまいます。アプリ側(白)が圧倒的に有利なのにも拘らずです。
     そこで同じ局面が2回出現した時は思い切って駒の重みをある程度ランダムに変更して指し手を変えることにしました(Version1.0.1.4)。

    3.Pawnのランク(行)位置2で駒の価値に加点する

     2.の千日手回避の目的とも関わるのですが、ポーンの位置によってポーンの駒の価値に加点することにしました(Version1.0.1.4)。
     局面5では圧倒的にアプリ側(白)が有利なので、ビショップやルークを動かすよりポーンをゆっくり前に進めてクイーンに成るのが確実な勝ち方だと思います。でも自分のアプリでは3手〜5手読みなのでポーンが一つや二つ前に進んでもポーンの価値は変わらないので、ポーンを前に進める手を選んでくれませんでした。
     そこでポーンのランク位置によって先手なら2ランクにあるポーンより8ランクにあるポーンの方が価値があるという評価関数にしました。先手の場合2ランクから8ランクに到るまで放物線を描くように加点しています。2ランクにあるポーンより3ランクに位置するポーンの方が価値が高いのかどうか難しいところですが、8ランクに辿り着いてクイーンに成るまでにも一応変化を与える必要があるためそうしました。その結果、以下のようにポーンを進めるようになりました。

    局面6:局面5からポーンを進めた(d4)局面

    局面図6

     こういうやり方が必要?なのはアプリの読む手の深さにも関係しています。将棋の場合なら敵陣に歩を打って相手が何か指して次に打った歩を成ればいいので、都合3手以上の読みの深さがあれば「歩」の価値が「と金」の価値となって評価値に反映されますが、チェスの場合は持ち歩を打つという選択がないのでちまちまとポーンを前に進めていく手を読まなければならないので、読みが浅いとポーンがクイーンに成る局面まで評価出来ないことに起因してます。だから巷の深く読んでる強いアプリ(全部Stockfish由来?)は評価関数内でこんなことしてないと思います。

    深く読めないのがもどかしい

     他にもポーンチェーン3に加点するなんてことも試しましたがボツにしました。
     評価関数のパラメータ調整というのでしょうか?いろいろ試行錯誤しましたが、こういう職人技的な作業が必要なのは自分のアプリが深く読めないことが一番の原因です。Javascript製で尚且つデータ構造も人間が理解し易い(所謂高級な)ままなので実行速度が出せません。深く読めば読むほど強くなるわけではないと思います4が、どこまで読めばいいかを語る以前の段階という感じです。Javascriptでこういうアプリを作るのは自分に手枷足枷を課して作っているようにも感じるのですが、アイデアを絞り出して問題解決するのもプログラミングの醍醐味なので、なんとかチェスアプリとして最低限のレベルは確保していたいと思ってます。
     アプリのままだと制約が多いので、一度アプリより深く読む設定でCLI上で実行してchess.comのコンピュータ対戦でどのレベルまで勝てるのか試してみようと思ってます。読みを深くするだけで強くなるようであれば、評価関数の出来自体は悪くないということですし、また新たな問題を見つけることが出来るかもしれません。


    1. chess.comのコンピュータのレベル4をライバル視しています。 

    2. チェスでは横の列(a〜h)をファイルと呼び、縦の行(1〜8)をランクと呼ぶそうです。 

    3. ポーンが斜めに連結している状態 

    4. 5手読みで最善手とされた手が9手読みだと違う手が最善手になったけど、13手読みだとまた5手読みと同じ手が最善手と判断されることもあり得ます。全てのノードを完全に読み切れていないのであるならどこまで深く読んだとしても最善手の結論は出せません。 



    blog comments powered by Disqus