FC2ブログ

*All archives* |  *Admin*

<<05  2017/06  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30  07>>
シャンテン数と一次有効牌枚数と局収支の関係
AI開発の課題の中で、4シャンテン以上だと枚数しか見てなくて、3シャンテンでも2択に絞り込むのに枚数だけを使っているという現状があって、
広さ(一次有効牌の多さ)と初手危険度の間を取り持つ指標が必要になるかと思ってこの2日くらい牌譜解析をやっていました。

他家の高打点仕掛けが入っているのに自手の都合(枚数)しかみないのはちょっと問題であろうと。
というわけで、シャンテン数と一次有効牌の枚数に対応する局収支を実測から取ってみて、そこから初手危険度指数(放銃率×放銃時失点の和)から差し引く…とかでなんとかうまいこといかないかなぁと。

それで牌譜解析をやったんですけど、毎順シャンテン計算と有効牌枚数計算をやるため、かなり時間がかかりました。
その結果がこちら。
左が巡目、上が一次有効牌枚数
集計条件は特になし(他家の挙動は無視)
170618-01.png
同じシャンテン数・巡目では一次有効牌枚数が多いほど局収支も高い傾向にあるようです。

ただ、取ってみたのはいいけれど、これを実際使えるかというとびみょうです。
この数値は何も条件を付けてないので、自手の手牌価値と等価になっていなくて、多くの場合は途中でベタオリに回ることが入っているためです。
ちょっと失敗でしたかね。(数値自体は無意味ではないかもしれませんが。)

そうすると4シャンテン以上と3シャンテンの手牌評価が手詰まり気味です。
初手危険度の評価と安牌(大体の場合、字牌)を手に残す場合の価値の評価とか。
うーん、どうしようか。

とりあえず今考えているのは、いったんこの問題は棚上げにして、前に進めて(再帰パート自分鳴き処理部分)、
AIを実際の牌譜にかけて、その結果をなにかしら頑張って分析して、打牌決定のアルゴリズムを決める、みたいな。
ものすごく行き当たりばったりでまるでできる気がしないなぁ。
分析するにしても方向性がないとどんな数値を出力すればいいのかわからないし。
牌譜の数も多いし、AIにかけるのも1試合当たりに時間が結構かかるから、無駄なことはできないし。

現状は少なくとも細かい押し引き判断(2シャンテン以下)についてはAIで実際の牌譜を計算させてディープラーニングっぽいことをやらせることは確定なので、それがうまいこといってからまた考えようか。(すごくてきとー。)
3シャンテン以上の押し引き、打牌候補選定だとディープラーニングっぽいのをやるのに再帰計算はかけないので、シャンテン計算と有効牌計算だけでまた2日くらい時間を食うんだろうけど、そこまででかいコストではないから試行錯誤でもなんとかならんかなぁ、と希望的観測。
麻雀AI開発その22・ログの調査中
AI製作の続きです。
引き続き、1試合通しで計算させたログ(1打1打ごとの評価値)を見て、バグ潰しとかをしていきます。

1試合分のログ16000行のうち6000行くらいまでチェック終わりました。
とりあえず今日のところは重大なバグは出ていなくて小康状態といったところです。

ログをゆっくり眺めているとAIの特徴とか改善点がちょっとずつ見えてきます。

・かなり守備型のAIである。
上がりの可能性が薄い状況で、字牌とか2者に対する端牌現物とかを残したがる傾向がかなり強いです。

例えば次のような状況です。普通なら手牌に何の関係もない1mはツモ切りなんですけど…
170615-01.png
再帰パート(他家和了無視)では余剰牌なしで1mを切るのが圧倒的によくなっていますが、(この段階で1mと3sの二択に絞られる)
シミュレーションパートでは逆転して打3sが有利という結果を返してきます。

中身の数値を見てみると、和了率は7%前後ともともとの数値がかなり低いので、両者そこまで差がつかない一方、
放銃率では1.5%くらい打3sの方がいいということになっています。

現状は全員動きなしなので1mも3sもほぼ通るという一方、聴牌打牌が異なるので、将来の危険牌である3sを先に処理する方が放銃率的に有利である、という計算だと思われます。

ダイレクトのカン2s受けがある場合でさえこれなので、ただの変化(例えば両面+愚形+真ん中浮き牌)でしかない場合はよけいに字牌を残して浮き牌が切られる傾向が強いです。

これだけならまぁそういう(守備型)傾向がある、というだけで済む話なのですが、
さすがにドラの浮き牌とか23赤5s北とかからでも字牌を残してドラを切ろうとするのはいかがなものか、という気がします。
まぁ理屈はわからんでもない(上がりの可能性が低いので打点UPよりも将来の危険牌先切りを優先)のですが、ちょっと釈然としないものがあります。
局収支等の数値の求め方自体はがっちり決まってしまっているので、どうにも修正のしようがない感じです。


・シミュレーションパートの結果のばらつきが結構激しい。
10000回の試行だと局収支で±数十点はふつうにばらつくのですが、細かい牌効率系だと局収支の差がその誤差の範囲内(±数十点)での勝負になることがかなり多いです。
なので、人間の目から見れば明らかな上位互換になる打牌(例えば孤立役牌>孤立オタ風)でもその影響度が小さいと、
ちょっとシミュレーションで片側に上振れ下振れを引くと逆転してしまうケースがかなり多くみられます。
これも構造的な問題なので、すぐに解決はできそうにないです。(シミュレーション回数を増やすのが一番手っ取り早いが、計算時間がかなり増える)


・序盤の手組が実際の打牌となかなか一致しない。
3シャンテン(枚数の多い2打牌候補について手替わり0回再帰計算+シミュレーション)とか4シャンテン以上(一次有効牌の枚数のみ)とかの実際の打牌との一致率が極めて低いです。(体感でたぶん5割もない)
上がりまで遠いので、この時の方がむしろ実際の打ち手は字牌を残して端寄りの浮き牌とかから処理していく傾向が強いです。
また、他家に仕掛けが入った後についても、3シャンテンとかの枚数で2択に絞るところで、枚数のみなので危険度が低い牌を優先して切るみたいなことはできていません。

これについては枚数と危険度の比較なので、一見難しそうですが、手がないわけではないです。
「シャンテン数」と「一次有効牌の枚数」ごとに局収支の実測値をパラメータとして取って、そこから危険度指数(Σ(放銃率×放銃時失点))分だけ差し引けば、危険度との兼ね合いを測ることができる…かもしれないです。

字牌を残す問題については孤立字牌に対して守備力を評価して±何枚かの補正をつける、とか。


現状、こんなところですかね。いつになったら自分鳴き処理に入れるんでしょうね。
麻雀AI開発その21・こまごまとした修正3
AI製作の続きです。
引き続き、1試合通しで計算させたログ(1打1打ごとの評価値)を見ながら、こまごまとした修正をかけていきます。

・3シャンテンの再帰計算
前回予定で述べた通り、まずは第一段階で一次有効牌の枚数を比べて、そのうち上位2つの打牌候補について、手替わり0回再帰計算とシミュレーションをさせることにしました。
また、
七対子手のときに孤立字牌を優遇(例えば枚数+2枚評価とか)
面子手のときに隣に雀頭やメンツにくっついてる浮き牌を優遇(例えば枚数+2枚評価とか)
打牌候補がドラになるときの評価(枚数―2枚補正とか)
について、第一段階評価時に枚数に補正をつけることにしました。

当初思ってたよりは計算時間はかからずに済みそうです。だいたい手替わり1回一向聴と同じくらいです。
手替わり1回二向聴の計算時間に比べればまだ耐えられる、というレベルですが。

・パラメータの不備を修正
他家リーチ者がいて、自分はリーチしてない状況での他家の切る牌分布の計算について、
参照するパラメータが「自分リーチに対する切られる牌分布」になってたのが発覚したので、
「他家リーチに対する切られる牌分布」のパラメータを新たに採取(牌譜解析)して、該当部分を修正しました。

・バグ修正
まだまだ激重いバグがありました。

再帰パートで最終結果(局収支とか和了率とか)への代入処理の場所を間違えていて、他家のツモ番のところが全く反映されていなかった(もしくは全くでたらめな数値)。

再帰パートで流局まわり処理で残り山枚数を1枚多く計算していたのが発覚。

フーロ手シャンテン数計算で字牌雀頭のときに鳴いて晒した部分をメンツとしてカウントしてなかったバグが発覚。

3つのバグとも残りツモ1回(海底が自分)の形式聴牌の状況で和了率が完全に0になっているという不自然な状況からたどっていって見つけることができました。
いずれも重要度が高いところでした。比較的わかりやすく不自然さが際立っていたので見つけることができましたが、ここで見逃してたら大惨事なところでした。

同じ試合のログばかりを眺めてバグが見つかったので、直して再度試合の最初からチェックし直しという作業がエンドレスに続いていてモチベーション的にたいへんよろしくないです。
もうそろそろテストとバグ潰しも飽きてきたので次のステップ(再帰パートの自分鳴き処理)に行きたいところですけど、現在のバグの発覚が止まらない状況ではそんなことは言ってられない状況ですしねぇ。
麻雀AI開発その20・こまごまとした修正2
AI製作の続きです。
引き続き、1試合通しで計算させたログ(1打1打ごとの評価値)を見ながら、こまごまとした修正をかけていきます。

・バグ修正
まだまだ激重いバグが何個か見つかりました。
大半のバグの原因が、
自分のプレイヤー番号(0~3のいずれか)が従前の四麻計算機のコードだと0番固定になっていたのが、
今回は可変になった影響です。
今は変数名「turn」でプレイヤー番号を管理しているのですが、従前のコード内で直接「0」と書かれているところを見逃して修正できていなかったことでバグが発生しています。
コード本文で「0」という一文字だけで検索してもどえらい個数がヒットして修正の役には立たないのがたいへんです。(置換なんてもってのほか)

・2シャンテンと手替わり
従前だと2シャンテンは計算時間の都合で、手替わり0回計算にしていたのですが、
メンツ候補が足りてるけど愚形が残ってる時に、真ん中の浮き牌にくっつけて両面変化狙いで残すという超基本手筋がAIでは考慮できなくなってる(後の危険度で字牌を残したがる)ので、やっぱり手替わり1回を見たいところです。

ただ、そうすると正確性の代わりに計算速度が犠牲になります。考えるべき変化の数が手変わり0回や一向聴以下と比べて、かなり膨れ上がるので計算速度の低下は避けられません。
まず手替わり0回で再帰計算をした後、そのうち上位2つの打牌候補に限って手替わり1回再帰計算をした後シミュレーションにかける、という方法を取ってみても1打につき10~20秒くらい余計にかかってしまいます。実戦的にこれだと結構厳しいです。

AIとして実際にfloodgate for mahjongで打たせるのが目標ではしんどいですが、牌譜検討ソフトを目標にするならこれでもなんとかぎりぎり持ちそうです。
さいわい、第一段階(手変わり0回再帰計算)で打牌候補を二つに絞って仮の打牌候補と評価値は出せるので、計算速度が必要な場面では手替わり0回の計算のみ、正確に検討したいときには手替わり1回で正確に計算する、という使い分けも可能です。

ただ、この手法でもまだ不十分な点があります。
それは、第一段階の計算で選外となってしまった打牌はその後の計算はされないということです。
例えば、ヘッドレス状態で2m7s西の浮き牌選択するとき、手変わり0回計算だと本当は最善であるはずの打西が第一段階で選外になってしまう(横伸びが考慮されず、直接シャンテンの進む縦重なりしか考えていないため)ということが起こります。
これを防ぐには打西についても手替わり1回で計算させたいのですが、どういうケースだと3番手の打牌候補も計算させるか、というのをコンピュータに指示するかがよくわからないので現状はできてないです(一律で2番手の打牌候補までしか計算しない)。


ここまでが今日まででできたことです。

ここからは明日以降に実装する予定のもの。

・3シャンテンの計算
3シャンテンだと手替わり0回ですら計算時間がかかるので、単純な有効牌の枚数だけしかみてません。
さすがにこれでは不正確に過ぎるので、2シャンテン計算と同じく、上位2つの打牌候補に絞って手替わり0回再帰計算+シミュレーションを入れようかと考え中です。

・3シャンテン以上の浮き牌評価
七対子手のときに孤立字牌を優遇(例えば枚数+2枚評価とか)
面子手のときに隣に雀頭やメンツにくっついてる浮き牌を優遇(例えば枚数+2枚評価とか)
打牌候補がドラになるときの評価(枚数―2枚補正とか)
など。
麻雀AI開発その19・こまごまとした修正
AI製作の続きです。(floodgate for mahjongで打つこと以外の主目的ができたので、通し番号そのままでタイトルを変えました。)

1試合通しで計算させたログ(1打1打ごとの評価値)を見ながら、こまごまとした修正をかけました。

・聴牌でリーチとダマの評価値が似たような数値になってる。
初手をダマにした場合も次順以降はリーチが有利と判断すれば上がり牌や変化できる牌以外を引いてもツモ切りリーチをするためと思われる。
なので、再帰パートでダマ聴牌状態からツモ切り(ツモ牌と切る牌が同一のとき)になるときは最適打計算からツモ切りリーチの場合を除外するように変更しました。

・ツモ番のない状態でもリーチをかける選択も計算している。
ほとんどのケースはリーチ棒を失う分、ツモ番のないリーチは有利にならないので、大勢に影響はないですが、
ルールに即してツモ番がない時は初手打牌選択、及び再帰パート内計算でリーチの選択を除外するように変更しました。

・残りスジ本数と放銃率
前の四麻計算機を参考にして今回AIを作っていますが、そのときに入ってなかった要素として、残りスジ本数と放銃率の関係があります。今のタイミングがちょうどいいので、その部分を新たに作ることにしました。
パラメータは前の研究で採取済みなので、それをいつも通り(元になる放銃率に対して係数を掛け算する方式)シミュレーションパートに組み込みます。
少し手間取ったけど、無事に入れることに成功。


まぁ、修正点が見つかるのはいいのですが、
1試合のログ(テキストファイルで15000行超)を1打1打自分の目でチェックするのが思いのほか重労働です。長時間ログを見てると集中力が散漫になりがちです。
この間の有効牌計算関数でたらめ事件があったので、少しでも説明がつかないような変な打牌があればその部分をピックアップして内部変数を調べる、みたいなことも必要なので、時間を食っています。

設計とかコーディングとかとは違って、単純なテスト作業はやった分だけ目に見える成果につながらないので、精神的にちょっとこたえます。
普通にコーディングする上ではバグは避けられないので、テストとバグ潰しも重要なんですが、いかんせんモチベーションを維持するのが大変な感じですね。

とまぁ、ブログを書いて気分転換もしたので、またログのチェック作業に戻りましょうか。
floodgate for mahjong へ参戦その18・バグ潰し中
AI製作の続きです。
テストで1試合分計算させてみたところ変な挙動をしているところがあったので、その原因を調べるのをここ最近やってました。

バグ1・四人リーチ率の異様な高さ
この(↓)局面で打6m立直を打った時の不聴流局率(四人リーチ流局とトリプルロン流局が入る)が0.5%という高い数値がでていたのでどうしてなのかいろいろいじって調べていました。
170606-02.png
最初は他家が無筋を多く切って立直されやすい環境なのかなーと思って切られ率とかを調べていたのですが、この局面については1m序盤外側、1sワンチャンス、3p6p2枚飛びなので、片無筋4pがカベ効果で切られやすいということで無筋に分類される1mと1sと4pが出やすい部類になっているようでした。

ただ、四人リーチ率の実測値を調べると(1軒目の立直がかかった時点で他3人が非リーチ面前のときに局結果が四人リーチかどうかをカウントする)、
170606-01.png
0.05%あたりの数値なので、一けたも違います。
いやいや、いくらなんでも場況的な問題だけで一けたは変わらんだろうと。

実際、他の面前聴牌の局面でもAIの不聴流局率が0.1%はおおむね越えてました。
何か構造的な問題が起きてるんだろうなーと、さんざん悩んだのですが、ようやくバグの原因を特定できました。

「自分が1軒目の立直の時の先制立直からの経過巡目が自分の番が回ってきても正しく+1されていなかった」
そりゃぁ、常にリーチ経過巡目が0(リーチ直後の状態)だったら追っかけリーチ発生率がものすごく高くなるわけです。

バグのやばさ度合い「相手リーチに字牌で放銃したらリーチ一発チートイ裏裏だったとき」


バグ2・1235m445r56p23457s ドラ5mから打2sが推奨される問題。
これは問題が漠然としてるので、原因特定が難しかったです。
再帰パートでブレークポイントを設定して途中で止めるにしても、疑似再帰処理(実際はループで作ってる)がいろんなところを行ったり来たりしているのでデバッグもしづらいと。

とりあえずわかりやすい残り1巡の場合でやってみる。
→それでも2sが局収支高いと出る。(25sで聴牌できる分、打7sが有利なはずなのだが。)

最後の1巡のツモ牌ごとに局収支・和了率・聴牌率を見てみる
→?!なぜか打7sのときツモ2sが聴牌になってない。

1235m445r56p2345sの形での記憶されてる有効牌を見てみる
→やっぱり2sだけ有効牌になってない。

有効牌計算関数の中に入って1行ずつ動かしてみる

とステップを踏んでようやく原因の特定できました。
有効牌計算関数の中の非孤立牌計算(面子手有効牌となりうる距離±2以内のものだけを取り出す)が全くのでたらめなことをやってました…。
Boolean型の判定で数牌のところで間違えてNotをつけてしまっていた+赤5牌の影響でビットシフト演算が一けたずれていた。

有効牌計算とかいう根幹にかかわる関数がまったくでたらめだったという衝撃は半端なかったです。
むしろなんで今までエラーで止まるなどせずに1試合走破できたのかが不思議なくらいです。

ちょっとこれから有効牌計算関数を集中的にテストして方がよさそうです。

バグのやばさ度合い「白ポンの他家がいるときに先制リーチをかけたら発中を続けてポンされた上にツモられてパオで全額払いとなったとき」
まじで狂気じみてるやばさだ…。本当に今の時点で見つかってよかった…。

一見地味に見える違和感が実は超重大なバグだったという。こういうのがあるとまだ見つかってないやばいバグがまだあるんじゃないか、と不安でしょうがないです。
floodgate for mahjong へ参戦その17・シミュレーションパートの時間短縮と調整
前回に引き続き、麻雀AIの話です。
シミュレーションパートの大枠は大体できた(自分鳴きと点棒状況以外)ので、コードの中身を最適化して、より高速に計算できるように試みます。

一番計算時間がかかる部分が他家のツモ番で、切る牌を選択する関数です。
単純に3人いるので呼び出される回数が多いのと、毎順ごとに37種類の牌すべてについて、どの程度切られやすいかを各入力変数(現物か無筋かとか枚数とかカベ効果とか)ごとに倍率で掛けて計算する必要があるためです。

掛け算とかで時間を食うのはしょうがないのですが、本筋と関係ないところで無駄に時間を使っているところはなるべく回避していきます。
・再帰パートでは手牌とか見えてる枚数とか現物筋変数とかが頻繁に更新されるので、Long型を使っていたが、シミュレーションパートでは更新の頻度よりも枚数等を参照する頻度の方が多いので、いちいちLong型から枚数の情報を取り出す演算が余計にかかっている。よってこれら変数をInteger型配列に戻した。
・牌種類(端寄り中寄りとか役牌オタ風とか)を頻繁に関数を使って計算していたのが無駄だったので、各プレイヤーごと・37種類の牌ごとに牌種類を直接参照できるように配列でデータを置いておくことにした。

後は明らかに劣ってる打牌はシミュレーションパートを計算しないようにしました。再帰パートで1番目と2番目に局収支がいい打牌候補2つ+他家リーチがあるときはベタ降りの2択か3択でのみ考えることにしました。

テスト風景はこんな感じ。
(牌姿は6巡目1235m445r56p23457s ドラ5m)
170601-01.png
正直、まだ計算時間的には不満(1打牌候補につき2秒くらい)なんですが、高速化の手法のネタ切れなので今のところこれ以上の改善は無理そうです。

それで、計算時間の件はいったんおいておいて、正しく動作するかどうかを1試合分の牌譜を通しで計算させてみました。

今のところ出ている問題点はこちら。
・自分聴牌でリーチしたときを開始時点にすると、四人リーチ流局率が0.5%とやけに高い数値が出ている。
プログラムを途中で止めたりしながら見ていると、どうやら無筋の切られる頻度が感覚より高いような感じになっています。

170601-03.png
↑こちらはある捨て牌状況での、各牌が切られる率です。
一番左が牌番号(1~37)、中央がその牌が切られる率、右側がリーチ者の筋現物変数(0が現物、1が両筋・字牌、3が片無筋、4が両無筋)
一番下が現物が切られる確率の総和と無筋が切られる確率の総和です。

無筋が切られる確率が17%というのはかなり大きいような気がします。

↓が先制立直からの経過巡目別の、リーチを受けた側が先制立直に対して切った現物枚数・無筋枚数の分布(実測値)です。
170601-02.png
5巡以上経過しているケースでも半分以上は無筋を1枚も切っていない(無筋0現物2)の状態であることが分かります。

それに対してAIの計算では現物を切った場合と無筋を切った場合の時にコードをストップして切ってる無筋現物数を調べると明らかに無筋0現物2になってる頻度が半分以上はないです。
AIの計算の中では他家が無筋を切ってるケースが多いので、追っかけリーチの発生率が高い数値のところが参照されて、四人リーチが発生しやすいという構図だと思われます。

このようになってる原因として考えられるのは牌が切られる確率の計算は現状だと、
各牌ごとに独立して行っていて最後に総和が1になるように帳尻を合わせている方式になっています。
当然、現物の方が無筋よりも切られやすいというのは考慮されているのですが、ある現物牌は通常の2倍切られやすい、ある無筋牌は通常の切られる率の半分程度、などといったものの積み重ねなので、
特に現物の種類(見えてない枚数)が少なくて、無筋の種類(枚数)が多いようなケースだと半分の切られ率の無筋も多数種類あると塵も積もれば山となるみたいな感じで、各牌の数値を積み上げた結果、切られる率が過大評価されるということが考えられます。

これを防ぐ方策として考えられるのは、先に現物が切られる確率の総和(どの現物が切られるかは問わない)や無筋が切られる確率の総和(どの無筋が切られるかは問わない)を枠として確保しておいて、第一段階で現物が切られるか無筋が切られるかを乱数で判定する→仮に現物が切られると決定されたら、第二段階として現物の中から枚数等の情報からどの現物を実際に切るかを選択する、みたいな案があります。

別途パラメータの取得は必要になるし、計算ステップが増えることで計算時間が増えそうなのもちょっと気がかりです。
まぁでも明らかに変な挙動のまま、放っておくわけにもいかないし、やるしかないかー。

・何か↑でやったテスト牌姿で再帰パートが打7sより打2sの方を和了率・局収支が高いとおっしゃっておられる。
どう考えても25sのどっち引いてもいいように打7sだと思うのだが、中で何が起こっているんだろう。意味が分からないです。

・塔子がぎりぎり足りているヘッドレス2シャンテンで、浮き牌比較の時に中寄りの牌を切って、端寄りや字牌を残したがる傾向があるみたい。
手変わり0回なので、浮き牌にくっつくことを考慮していなくて、ヘッドになりやすさで中寄りの牌を切っていると思われる。
これは手替わり1回にすれば解決すると思われるが、計算時間がどの程度増えるかが未知数なので、まだ触ることができていない。


というわけで、けっこうあやしい挙動が多数あるので、しばらくはバグ潰しや調整に時間がかかりそうです。
プロフィール

nisi5028

Author:nisi5028
FC2ブログへようこそ!

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
FC2カウンター
フリーエリア
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード