5五将棋の CPU のしくみ ― 先読みと機械学習
「5五将棋」の CPU は、外部の将棋ソフトやライブラリを使わず、ルールの処理から思考まで一から作っています。この記事では、CPU が何を考えて 1 手を選んでいるのか、そして機械学習でどうやって強くしたのかを、プログラムの中身にそって解説します。
5五将棋は AI にとってどんなゲームか
5五将棋は 5×5 の 25 マスに、ふたり合わせて 12 枚の駒しかない小さな将棋です。それでも、取った駒を好きな空きマスに打てる将棋のルールはそのままなので、局面の広がりは見た目よりずっと大きくなります。初期局面から何通りの進み方があるかを数えると、次のようになります。
| 何手先まで | 1 手 | 2 手 | 3 手 | 4 手 |
|---|---|---|---|---|
| 局面の数 | 14 | 181 | 2,512 | 35,401 |
1 手ごとにおよそ 13〜14 倍に増えていき、持ち駒が増える中盤以降はさらに選択肢が広がります。全部を読み切ることはできないので、CPU は「限られた時間で、なるべく大事な手を深く読む」工夫を積み重ねて手を選んでいます。
ちなみに上の表の数字は、CPU のルール処理が正しいかを確かめるのにも使っています。5五将棋のこの数字は広く知られているので、自分のプログラムで数えた結果がぴったり一致すれば、駒の動きや二歩・打ち歩詰めの判定にまちがいがないと確認できます。
盤と指し手の表し方
CPU の中では、盤面を 25 個の整数の並びとして持っています。駒の種類を 1〜10 の番号で表し、先手の駒はプラス、後手の駒はマイナスの数にします。指し手も「どこから・どこへ・成るかどうか」を 1 つの整数に詰め込んでいます。数字だけで扱うことで、1 手を指す・戻す操作がとても速くなります。
指せる手を作るときは、まずルール上動ける手をすべて書き出し、実際に指してみて自分の玉に相手の駒の利きが残っていないかを確かめ、残っていれば反則として捨てます。玉に利きがあるかどうかは、玉から 8 方向に順にマスを見ていき、最初にぶつかった相手の駒がこちらへ動けるかを調べるだけで判定できます。5五将棋には桂馬や香車がないので、8 方向を調べれば十分です。
打ち歩詰め(歩を打って詰ませる反則)は、歩を打って王手になったときだけ、相手に逃げる手が 1 つでもあるかを調べて判定しています。
先を読む:αβ 探索
手の選び方の骨組みは、チェスや将棋の AI で昔から使われているミニマックス探索です。何手か先までの展開を木の形に書き出し、末端の局面に「どちらがどれだけ有利か」という点数をつけます。そして「自分の番では自分に一番有利な手、相手の番では相手に一番有利な手が指される」と仮定してさかのぼり、今指すべき手を決めます。
そのままでは読む局面が多すぎるので、次の工夫で無駄な読みを省いています。
- αβ 法:「この手はすでに見つけた手より悪い」とわかった時点で、その先を読むのをやめます。結果は普通のミニマックスと同じまま、読む量を大きく減らせます。
- 手の並べ替え:αβ 法は、良い手から先に読むほどよく効きます。前に読んだときの最善手、駒を取る手(安い駒で高い駒を取る手ほど先)、成る手、ほかの局面で相手の手を打ち切るきっかけになった手、の順に読みます。
- 反復深化:1 手先、2 手先…と少しずつ深く読み、持ち時間を使い切ったら、最後まで読めた深さの結果を使います。端末が遅くても待ち時間は変わらず、読みが浅くなるだけです。
- 置換表:一度読んだ局面の結果を表に覚えておきます。手順が違っても同じ局面にたどり着くことは多いので、読み直しを省けます。
- 静止探索:読みの末端で駒の取り合いが続いている局面に点数をつけると、「次に取り返される」ことを見落とします。そこで末端では、駒を取る手だけをさらに読み、取り合いが落ち着いた局面で採点します。王手をかけられている局面では、逃げ方もすべて読みます。
- 王手の延長:王手をかけられた局面は、詰むかどうかの分かれ目になりやすいので、そこだけ 1 手深く読みます。
詰みは「どんな点数よりも大きい(小さい)値」として扱い、早く詰ませる手ほど高く評価します。そのため、詰みを見つけた CPU は最短手順で詰ませにいきます。
CPU はパソコンで 1 秒あたりおよそ 100 万局面を読み、強さ「つよい」の持ち時間(1 手 2.5 秒)では、だいたい 8 手先まで読み切ります。
千日手も読みに入れる
5五将棋では、同じ局面が 4 回現れると「千日手」で先手の負けになります(王手を続けた結果の千日手は、王手をかけた側の負け)。CPU は読みの途中で同じ局面に戻る手順を見つけると、このルールに沿って「先手に不利な結果」として点数をつけます。後手番の CPU は千日手を狙いにいき、先手番の CPU は避けようとします。
局面に点数をつける
読みの末端で局面に点数をつける部分を評価関数といいます。どれだけ深く読めても、ここの点数がおかしければ CPU はおかしな手を指します。5五将棋の CPU は、次の 6 種類、合計 2,085 個の数値を足し合わせて点数を出しています。単位は「歩 1 枚 = 100 点」くらいです。
| 項目 | 中身 | 数値の個数 |
|---|---|---|
| 駒の価値と位置 | 駒の種類 × いるマス(25 マス)ごとの点数 | 275 |
| 攻めの形 | 駒の種類 × 相手の玉から見てどこにいるか | 891 |
| 守りの形 | 駒の種類 × 自分の玉から見てどこにいるか | 891 |
| 持ち駒 | 駒の種類ごとに 1 枚目・2 枚目の点数 | 18 |
| 玉の危なさ | 玉のまわり 8 マスのうち、相手の駒が利いているマスの数 | 9 |
| 手番 | 指す番であることの有利さ | 1 |
先手の駒の点数を足し、後手の駒の点数を引いたものが局面の点数です。後手の駒は盤を 180 度回して先手と同じ表で数えるので、同じ形なら先手・後手どちらでも同じ点数になります。
最初はこれらの数値を、将棋の感覚をもとに手で決めていました。たとえば「銀は 500 点、金は 540 点」「相手の玉に近い駒ほど少し加点」といった具合です。ただ、2,000 個もの数値を手で正しく決めるのは無理があります。そこで、数値を機械学習で決めることにしました。
機械学習で点数を決める
考え方:「どちらが勝ったか」を当てる
良い評価関数とは、「点数が高い局面ほど、実際にその側が勝ちやすい」評価関数です。そこで、たくさんの局面とその対局の勝敗を集め、点数から勝敗をできるだけ正しく予想できるように数値を調整します。チェスの AI 作りで「Texel 法」と呼ばれている方法で、中身は統計でいうロジスティック回帰です。点数を勝率に変換し、予想した勝率と実際の勝ち負けのずれが小さくなる方向へ、2,085 個の数値を少しずつ動かしていきます。
データ:CPU 同士の対局 2.5 万局
手本にする棋譜は、CPU 同士を対局させて作りました。毎回同じ進行にならないよう、序盤の数手だけは良さそうな手の中からランダムに選ばせています。
集めた局面のうち、王手をかけられている局面や駒の取り合いの途中の局面は使いません。こうした局面は、次の 1 手で形勢ががらりと変わるので、静止した局面の点数を学ぶ手本には向かないからです。
学習は 2 回に分けて行いました。
- 手作りの評価で指す CPU どうしで 15,573 局を指し、そこから 31 万局面を集めて学習
- 1 回目で強くなった CPU どうしでさらに 8,933 局(20 万局面)を指し、両方を合わせた 51 万局面で学習し直し
学習には使わなかった 1 割の局面で予想の当たり具合を確かめ、学習用の局面だけに合わせすぎていない(丸暗記していない)ことも確認しています。
結果:学習前の CPU に 8〜9 割勝てるように
強くなったかどうかは、学習前と学習後の CPU を直接対局させて確かめました。同じ序盤から先手・後手を入れ替えて 2 局ずつ指し、序盤の運の良し悪しが勝率に影響しないようにしています。
| 対戦 | 1 手の持ち時間 | 対局数 | 勝率 |
|---|---|---|---|
| 1 回目の学習 vs 学習前 | 0.1 秒 | 300 | 81% |
| 2 回目の学習 vs 1 回目の学習 | 0.1 秒 | 300 | 62% |
| 2 回目の学習 vs 学習前 | 0.1 秒 | 300 | 82% |
| 2 回目の学習 vs 学習前 | 0.4 秒 | 120 | 89% |
読む時間が長いほど差が開いたのは、評価が正確になったぶん、深く読んだ先の判断がより的確になるからだと考えられます。今のゲームで使っているのは 2 回目の学習の結果です。
学習でわかったこと
学習した数値を見ると、5五将棋らしい特徴がいくつか表れています。まず、駒の価値(盤上のマスごとの点数を平均したもの)です。
| 駒 | 盤上 | 持ち駒(1 枚目) |
|---|---|---|
| 歩 | 100 | 125 |
| 銀 | 506 | 504 |
| 金 | 544 | 609 |
| 角 | 635 | 560 |
| 飛 | 723 | 720 |
| と(成った歩) | 559 | ― |
| 成銀 | 538 | ― |
| 馬(成った角) | 862 | ― |
| 龍(成った飛) | 982 | ― |
歩は 1 枚 100 点なのに、成って「と」になると 559 点と金並みの価値になります。盤が狭い5五将棋では歩がすぐ敵陣に届くので、と金づくりは大きな得になります。また、持ち駒の金は盤上の金よりはっきり高く評価されました。金は相手の玉の頭に打つだけで詰みにつながりやすいので、「いつでも打てる金」の価値が高いのは将棋の感覚にもよく合っています。一方で持ち駒の角は盤上より低く、角は盤上で利きを通してこそ働く駒だという特徴が出ています。なお、盤上の駒には位置や玉との距離の点数も加わるので、この表だけで単純に比べられないことには注意してください。
もうひとつ特徴的なのが、玉のまわりの危なさです。玉のまわり 8 マスのうち、相手の駒が利いているマスの数ごとの点数は次のようになりました。
| 利かれているマス | 点数 |
|---|---|
| 0 | +93 |
| 1 | +35 |
| 2 | −62 |
| 3 | −80 |
| 4 以上 | −69 〜 −96 |
1 マスまでなら大きな問題はないのに、2 マス利かれた時点で一気に 100 点近く悪くなる、という結果です。逃げ道の少ない5五将棋では、玉の近くに相手の利きが 2 本入ると、もう詰みが見えてくる、ということを数字が示しています。
強さを 3 段階に作り分ける
CPU の強さは「やさしい」「ふつう」「つよい」から選べます。どのレベルも同じ探索と評価関数を使い、読む深さと最善手以外をどれだけ選ぶかで強さを変えています。
| 強さ | 読む深さ | 手の選び方 |
|---|---|---|
| やさしい | 2 手先 | 最善手から 700 点(歩 7 枚分)以内の手の中から、点数が高いほど選ばれやすいくじ引きで選ぶ |
| ふつう | 3 手先 | 最善手から 140 点以内の手の中から、同じようにくじ引きで選ぶ |
| つよい | 持ち時間 2.5 秒でできるだけ深く(約 8 手先) | いつも最善手を選ぶ |
手を選ぶ「くじ引き」は、点数の差に応じて確率が決まるので、ひどい悪手ほど選ばれにくくなっています。また、「やさしい」「ふつう」でも、次に詰まされてしまう手は、ほかに手がない場合を除いて選びません。手加減はしても、あっけなく負けて興ざめにならないようにするためです。反対に、読んだ範囲で詰みを見つけたときは、どのレベルでも必ず詰ませにいきます。「やさしい」が詰みを逃すのは、2 手先までしか読まないので、それより長い詰み筋に気づかないときです。
機械学習で評価が強くなると、「やさしい」「ふつう」も同じように強くなってしまいます。そこで、学習後のこの 2 つのレベルは、学習前の同じレベルとの対局でほぼ五分(「やさしい」は 48%、「ふつう」は 55%)になるように、読む深さとくじ引きの幅を調整し直しています。強くなったのは「つよい」だけ、ということです。
ブラウザの中で考える
CPU の思考は、すべてお使いのブラウザの中で動いています。サーバーに局面を送って考えてもらうのではないので、通信が遅くても CPU の手は遅れません。思考は Web Worker という画面とは別の処理で行うので、CPU が考えているあいだも画面は固まりません。学習した 2,085 個の数値は、6KB ほどの小さなファイルとしてゲームと一緒に読み込まれています。
まとめ
- 手の選び方は、αβ 探索による先読み。手の並べ替え・置換表・静止探索などの工夫で、1 手 2.5 秒でおよそ 8 手先まで読む
- 局面の点数は 2,085 個の数値の足し算。駒の価値と位置、玉との位置関係、持ち駒、玉のまわりの危なさを数える
- 数値は CPU 同士の 2.5 万局から、勝敗を当てる機械学習で決めた。学習前の CPU に 8〜9 割勝てるようになった
- 「やさしい」「ふつう」は読む深さとくじ引きで手加減し、学習の前後で強さが変わらないように合わせてある
今の評価関数は「数値の足し算」という単純な形なので、さらに強くするなら、小さなニューラルネットワークで局面を評価する方法も考えられます。強くなったら、またこのページで紹介します。