牌の危険度計算アルゴリズム(3)

牌の危険度計算アルゴリズム(2) - koba::blog で実現した牌の 相対危険度 を押し引きに適用する。従来は手牌を 愚形*1好形*2超好形*3 の3種、切る牌を 安全*4危険*5 の2種に分類し、以下のパターンで押し引きを決定していた。

安全牌あり 安全牌なし
愚形 ベタオリ(危険度最低の牌を切ってオリる)全押し(危険牌を切ってもよい)
好形 回し打ち(安全牌なら切ってよい)
超好形全押し(危険牌を切ってもよい)

相対的危険度を使えば危険牌をさらに分類できるはずで、それにより上記パターンの 全押し について細分化できるのではないかと期待する。

安全牌の閾値

危険度を測る尺度が絶対危険度から相対危険度に変わったので、まずどこまでを安全牌とみなすべきか具体的な値で決定する必要がある。押し引きパターンを以下に簡略化し、安全牌とみなす 閾値A を 2.0 → 2.5 → 3.0 → 3.5 → 4.0 と変動させ*6、 先制リーチを受けた局の局収支で比較した。

安全牌あり 安全牌なし
愚形 ベタオリ
好形 回し打ち
超好形全押し

1000半荘の デュプリケート対局 の結果は以下の通り。

結果 閾値A: 2.0 閾値A: 2.5 閾値A: 3.0 閾値A: 3.5 閾値A: 4.0
割合 局収支 割合 局収支 割合 局収支 割合 局収支 割合 局収支
和了 10.0% +6812 10.1% +6817 10.2% +6858 10.4% +6896 10.5% +6887
放銃 10.2% -6656 10.3% -6656 10.5% -6629 10.8% -6636 11.2% -6589
被ツモ 31.8% -2738 31.7% -2739 31.7% -2745 31.5% -2757 31.3% -2762
横移動 29.3% -67 29.3% -67 29.3% -69 29.2% -71 29.0% -71
流局 18.7% -770 18.5% -762 18.4% -753 18.2% -749 17.9% -747
平均 -1033 -1030 -1021 -1023 -1031

これにより 危険度 3.0 未満を安全牌とみなす ことにした。

続いて閾値Aを 3.0 に固定した上で以下のように安全牌なしなら全押しとするのだが、このとき安全牌なしとみなす 閾値B を 3.0 → 3.5 と変動させてみた。

安全牌あり 安全牌なし
愚形 ベタオリ 全押し
好形 回し打ち 全押し
超好形全押し

1000半荘のデュプリケート対局の結果は以下の通り。

結果 閾値B: 3.0 閾値B: 3.5
割合 局収支 割合 局収支
和了 10.6% +6820 10.4% +6806
放銃 10.8% -6479 10.7% -6570
被ツモ 31.6% -2752 31.5% -2748
横移動 28.9% -71 29.1% -70
流局 18.2% -734 18.3% -751
平均 -1002 -1017

閾値AとBは一致させた方がよいようなので、危険度 3.0 の牌がない場合は全押し することとした。

全押し上限の閾値

次に危険牌を細分化する。まずは全押しのケースでも押してはいけない 超危険牌 となる 閾値C を定めたい。通っていないスジが残り4本で待ちがこの両面の8種に限られたとすると危険度は 1 / 8 = 12.5% となるので、このあたりを中心に閾値Cを変動させてみた。

結果 閾値C: 11.0 閾値C: 11.5 閾値C: 12.0 閾値C: 12.5 閾値C: 13.0
割合 局収支 割合 局収支 割合 局収支 割合 局収支 割合 局収支
和了 10.3% +6760 10.3% +6770 10.4% +6797 10.4% +6805 10.4% +6805
放銃 10.4% -6460 10.4% -6461 10.4% -6457 10.5% -6476 10.5% -6476
被ツモ 31.8% -2749 31.8% -2749 31.7% -2747 31.6% -2749 31.7% -2749
横移動 29.0% -69 28.9% -69 28.9% -69 28.9% -70 28.9% -70
流局 18.6% -798 18.5% -792 18.6% -778 18.5% -780 18.5% -775
平均 -1020 -1015 -1000 -1002 -1004

この結果から、危険度 12.0 以上の牌は全押しのケースでも切らない こととした。

押し上限の閾値

さらに、安全牌がないため全押しとしているケースについて、押してよい上限の 閾値D を探ってみる。通っていないスジが残り6本でその両面だけが危険牌とすると 1 / 12 = 8.33% なので、この近辺に解がありそうである。

結果 閾値D: 7.0 閾値D: 7.5 閾値D: 8.0 閾値D: 8.5 閾値D: 9.0
割合 局収支 割合 局収支 割合 局収支 割合 局収支 割合 局収支
和了 10.4% +6814 10.4% +6809 10.4% +6799 10.4% +6799 10.4% +6799
放銃 10.4% -6445 10.4% -6456 10.4% -6415 10.4% -6440 10.4% -6430
被ツモ 31.7% -2745 31.7% -2745 31.7% -2747 31.7% -2746 31.7% -2746
横移動 29.0% -70 29.0% -70 29.0% -69 28.9% -69 28.9% -70
流局 18.5% -781 18.5% -782 18.5% -781 18.5% -779 18.6% -780
平均 -1001 -1002 -993 -999 -1000

(安全牌なしのため)押しのケースで危険度 8.0 以上の牌は切らない こととした。

続いて、愚形の押しのケースについて、押してよい上限値の 閾値E を探ったが、3.0 〜 8.0 までの間に適切な値がなかったため、このケースでも好形同様に 8.0 を上限とする。危険度 12.0 までは押すケースを 全押し、危険度 8.0 までは押すケースを 押し とすると、以下の表になる。

安全牌あり 安全牌なし
愚形 ベタオリ 押し
好形 回し打ち 押し
超好形全押し

愚形テンパイ押し上限の閾値

最後に愚形テンパイ時の押しに関して上限とする 閾値F を探ってみる。8.0〜12.0 を探ってみたが、最良なのは 12.0 であった。愚形テンパイでも全押しがよいようである。ならば、形式テンパイ(評価値 0 のテンパイ)の上限の 閾値G は?ということで 4.5〜12.0 で試したが、最良はやはり 12.0 であった。ノー聴罰の収支まで含めると、テンパイ後は全押しした方がよいようだ。

結論として押し引き表は以下となった。

安全牌あり 安全牌なし
愚形 (3シャンテン以前か評価値400未満) ベタオリ (最も安全な牌を切る) 押し (危険度8.0以上は切らない)
好形 (評価値400以上〜1200未満) 回し打ち (危険度3.0以上は切らない)
超好形 (評価値1200以上かテンパイ) 全押し (危険度12.0以上は切らない)

プログラム修正

まず、相対危険度を計算し、最低の危険度とその牌を求める。

    let anquan, min = Infinity;
    let weixian = this._suanpai.suan_weixian_all(this._shoupai._bingpai);
                            // 相対危険度を計算し、それを取り出す関数を取得する。
    if (weixian) {                          // リーチを受けている場合
        for (let p of this.get_dapai()) {   // 全ての可能な打牌について以下を実行
            if (weixian(p) < min) {
                min = weixian(p);           // 最低の危険度を min  に、
                anquan = p;                 // そのときの牌を anquan に設定する。
            }
        }
    }

牌姿の評価値と牌の危険度で押し引き判断する。

        if (anquan && weixian(p) > min) {       // 危険度最低の牌以外を押す場合
            if (12.0 <= weixian(p)) continue;       // 危険度 12.0 以上は押さない
            if (n_xiangting > 2 || n_xiangting > 0 && ev < 400) {   // 愚形
                if (8.0 <= weixian(p)) continue;    // 危険度 8.0 以上は押さない
                if (min < 3.0)  continue;           // 安全牌がある場合はベタオリ
            }
            else if (n_xiangting > 0 && ev < 1200) {                // 好形
                if (8.0 <= weixian(p)) continue;    // 危険度 8.0 以上は押さない
                if (min < 3.0 && 3.0 <= weixian(p)) continue;
                                                    // 安全牌があれば回し打ち
            }
        }

評価

今までの改善の結果は以下の通り。

結果 改善前 改善(1)改善(2)改善(3)
割合 局収支 割合 局収支 割合 局収支 割合 局収支
和了 10.4% +6848 10.7% +6861 10.7% +6854 10.4% +6799
放銃 11.3% -6554 11.2% -6612 11.2% -6609 10.4% -6415
被ツモ 31.5% -2735 31.4% -2749 31.4% -2750 31.7% -2747
横移動 28.5% -69 28.6% -69 28.6% -70 29.0% -69
流局 18.3% -762 18.0% -750 18.1% -749 18.5% -781
平均 -1047 -1027 -1024 -993

改善前 改善(1)改善(2)改善(3) 改善前 改善(1)改善(2)改善(3)
対戦数 1,000 1,000 1,000 1,000 総局数 10,480 10,488 10,488 10,505
1位率 .237 .237 .237 .233 和了率 .213 .215 .215 .213
2位率 .244 .250 .250 .256 放銃率 .133 .133 .132 .128
3位率 .248 .244 .244 .247 立直率 .231 .233 .233 .233
4位率 .271 .269 .269 .264 副露率 .342 .342 .342 .342
平均順位 2.55 2.55 2.55 2.54 平均打点 5,622 5,626 5,625 5,607

*1:3シャンテン以前か評価値400未満

*2:評価値400以上1200未満

*3:評価値1200以上かテンパイ

*4:字牌かスジ

*5:無スジ

*6:牌が1枚も見えていない状態のとき、19牌の相対危険度は 2.25 なのでこれを参考にした