押し引きアルゴリズムの改善(2)

押し引きアルゴリズムの改善(1) - koba::blog で全ての打牌について1つ1つ押し引きを判断できるようになったので、押し引き表の牌姿は評価値何点? - koba::blog で言及した「評価値を基準とした押し引き判断」を実装する。

改善内容

現在1シャンテンでは手牌の良し悪しに関わらず

  • 現物・字牌・スジは押す

としているが、評価値を基準に手牌を 愚形、好形、超好形 の3つに分け、

愚形
ベタオリ(現在の2シャンテン同様)
好形
現物・字牌・スジは押す(現在の1シャンテンのまま)
超好形
全押し(現在のテンパイ同様)

とする改善を行う。具体的には評価値400未満を愚形、400以上1200未満を好形、1200以上を超好形とした*1押し引き表の牌姿は評価値何点? - koba::blog の牌姿と照らし合わせると、

牌姿 子の場合 親の場合
愚形 好形 超好形 愚形 好形 超好形
七対子 +2翻 (なし) (なし) +1翻 +2翻 (なし)
両面 + 愚形平和 平和+1翻
〜平和+2翻
(なし) のみ手平和
〜平和+1翻
平和+2翻
両面 x 2 のみ手平和
〜平和+2翻
(なし) (なし)のみ手
〜平和+1翻
平和+2翻
くっつき (なし)のみ手
〜平和
平和+1翻(なし)のみ手
〜平和
平和+1翻

となる。評価値は2シャンテン以降であれば計算できる*2ので、2シャンテンの場合も上記基準を適用することする。

プログラム修正

    /*  anquan: 危険度最低の牌
        min: 最低の危険度
        weixian: 各牌の危険度を納めるハッシュ
        dapai: 打牌する牌(初期値は危険度最低の牌)
        max: 打牌する牌の評価値                     */

    let n_xiangting = Majiang.Util.xiangting(this._shoupai);
                                                    // 手牌のシャンテン数を取得
    /* ……… */

    for (let p of this.get_dapai()) {   // 全ての可能な打牌について以下を行う

        /* ……… */

        let shoupai = this._shoupai.clone().dapai(p);   // 打牌後の牌姿を作成

        /* ……… */

        let ev = this.eval_shoupai(shoupai, paishu);    // 評価値を計算
        let x  = 1 - paijia(p)/100 + ev;                // 評価値同点の補正

        /* ……… */

        if (min < 6) {          // 打牌可能な牌が全て無スジ以上の危険度なら押す
            if (n_xiangting > 2              && weixian[p] > min) continue;
                                        // 2シャンテン以前はベタオリ
            if (n_xiangting > 0 && ev <  400 && weixian[p] > min) continue;
                                        // 1〜2シャンテンの場合、愚形はベタオリ
            if (n_xiangting > 0 && ev < 1200 && weixian[p] >   5) continue;
                                        // 超好形でなければ無スジは押さない
        }

        if (x >= max) {         // 評価値最大の場合
            max = x;            // max を更新する
            dapai = p;          // dapai を更新する
            max_tingpai = n_tingpai;
        }
    }

評価

前回同様 デュプリケート方式 で1000戦の対局を行った結果は以下の通り。

結果 改善前 改善(1)改善(2)
割合 局収支 割合 局収支 割合 局収支
和了 10.2% +6441 11.6% +6468 11.3% +6721
放銃 10.5% -6209 13.0% -6200 12.0% -6279
被ツモ 32.6% -2690 31.5% -2703 31.9% -2706
横移動 26.3% -57 25.6% -68 26.0% -63
流局 20.4% -827 18.2% -615 18.9% -667
平均 -1057 -1036 -999

改善前 改善(1)改善(2) 改善前 改善(1)改善(2)
対戦数 1,000 1,000 1,000 総局数 10,505 10,465 10,464
1位率 .241 .249 .255 和了率 .209 .218 .215
2位率 .251 .244 .248 放銃率 .128 .141 .137
3位率 .254 .255 .248 立直率 .221 .237 .232
4位率 .254 .252 .249 副露率 .346 .349 .349
平均順位 2.52 2.51 2.49 平均打点 5,492 5,499 5,580

局収支はかなり改善されたが、平均順位の変動はわずかだった。次回はテンパイしていてもオリるべきケースを検討する。

*1:いろいろ変えて試した結果、これがよいバランスと判断

*2:論理上は3シャンテン以前も計算可能だが、時間がかかりすぎるため計算させていない