天鳳鳳凰卓の牌の危険度表 - koba::blog で天鳳鳳凰卓での牌の危険度と待ちの形の出現度を集計したが、その結果を 電脳麻将 の押し引きに反映する。
まず前回の2つの表の条件を掛け合わせて集計し直した。
単騎 | 双碰 | 嵌張 | 辺張 | 両面 | 合計 | |
---|---|---|---|---|---|---|
字牌 | 0.56% | 1.20% | 1.76% | |||
生牌 | 0.98% | 3.31% | 4.29% | |||
1枚切れ | 0.91% | 1.20% | 2.11% | |||
2枚切れ | 0.21% | 0.06% | 0.28% | |||
3枚切れ | 0.01% | 0.01% | ||||
19牌 | 0.47% | 1.01% | 4.61% | 6.09% | ||
無スジ | 0.43% | 0.96% | 5.25% | 6.65% | ||
スジ | 0.69% | 1.33% | 2.02% | |||
28牌 | 0.48% | 0.89% | 1.18% | 4.66% | 7.20% | |
無スジ | 0.46% | 0.85% | 1.11% | 5.30% | 7.72% | |
スジ | 0.62% | 1.20% | 1.68% | 3.50% | ||
37牌 | 0.38% | 0.66% | 1.18% | 0.97% | 4.74% | 7.94% |
無スジ | 0.34% | 0.62% | 1.11% | 0.91% | 5.44% | 8.42% |
スジ | 0.60% | 0.94% | 1.69% | 1.39% | 4.62% | |
456牌 | 0.44% | 0.67% | 0.83% | 7.62% | 9.56% | |
無スジ | 0.45% | 0.59% | 0.81% | 9.71% | 11.56% | |
片スジ | 0.40% | 0.76% | 0.81% | 5.13% | 7.10% | |
中スジ | 0.51% | 1.03% | 1.26% | 2.81% |
改善内容
現在の電脳麻将は ベタオリのアルゴリズム - koba::blog で定義した表*1にしたがい牌の危険度を決定しているが、スジは考慮されているもののカベは考慮の対象となっていない。そこで先の待ちの形と危険度の統計値を参考に待ちの形ごとに評価値を定め、あり得る待ちの形の評価値を加算して危険度を決定することにした。
評価値を 単騎 = 1、双碰 = 2、嵌張 = 辺張 = 3、両面 = 10 とすれば以下の表のように統計値とほぼ一致する。
単騎 | 双碰 | 嵌張 | 辺張 | 両面 | 合計 | |
---|---|---|---|---|---|---|
字牌 | 1 | 2 | 3 | |||
19牌 | 1 | 2 | 10 | 13 | ||
28牌 | 1 | 2 | 3 | 10 | 16 | |
37牌 | 1 | 2 | 3 | 3 | 10 | 19 |
456牌 | 1 | 2 | 3 | 20 | 26 |
残り枚数、スジ、カベを考慮してあり得ないパターンを減算すると、
- 2枚切れ字牌待ち
- 双碰が否定されるので、単騎のみの 1点
- スジ28牌待ち
- 両面が否定されるので、単騎 + 双碰 + 嵌張 の 6点
- 4が4枚切れの無スジ3待ち
- 両面と嵌張が否定されるので、単騎 + 双碰 の 3点
と危険度を決定できる。
プログラム修正
まず Majiang.SuanPai
の牌の危険度を計算するメソッド .suan_weixian()
を以下に修正する。
suan_weixian(p, l) { let [s, n] = p; n = +n || 5; let r = 0; // 初期値は 0 if (this._dapai[l][s+n]) return r; // 現物は 0点 const paishu = this._paishu[s]; /* 対子もしくは刻子 */ r += paishu[n] >= 2 ? 3 // 生牌・1枚切れ: 単騎+双碰 : paishu[n] == 1 ? 1 // 2枚切れ: 単騎のみ : 0; // 3枚切れ: 単騎、双碰 の可能性はなし if (s == 'z') return r; // 字牌の場合は嵌張、辺張、両面の計算は不要 /* n-2, n-1, n の順子 */ r += n - 2 < 1 ? 0 // 範囲外 : Math.min(paishu[n-2], paishu[n-1]) == 0 ? 0 // カベ : n - 2 == 1 ? 3 // 辺張 : this._dapai[l][s+(n-3)] ? 0 // スジ : 10; // 両面 /* n-1, n, n+1 の順子 */ r += n - 1 < 1 ? 0 // 範囲外 : n + 1 > 9 ? 0 // 範囲外 : Math.min(paishu[n-1], paishu[n+1]) == 0 ? 0 // カベ : 3; // 嵌張 /* n, n+1, n+2 の順子 */ r += n + 2 > 9 ? 0 // 範囲外 : Math.min(paishu[n+1], paishu[n+2]) == 0 ? 0 // カベ : n + 2 == 9 ? 3 // 辺張 : this._dapai[l][s+(n+3)] ? 0 // スジ : 10; // 両面 return r; }
次に Majiang.Player
のメソッド .select_dapai()
で危険度を判定している部分を新しい尺度に変更する。
select_dapai(info) { /* …… */ for (let p of this.get_dapai()) { /* …… */ if (min < 10) { if (n_xiangting > 2 && weixian[p] > min) continue; if (n_xiangting > 0 && ev < 400 && weixian[p] > min) continue; if (n_xiangting > 0 && ev < 1200 && weixian[p] >= 10) continue; } /* …… */ } /* …… */ }
従来は無スジを危険牌としていたが、今回は両面が残っている場合を危険牌とした。
評価
押し引きアルゴリズムの改善(3) - koba::blog と同様に、プログラム同士を1000戦 デュプリケート方式 で対戦させた。
結果 | 改善前 | 改善(1) | ||
---|---|---|---|---|
割合 | 局収支 | 割合 | 局収支 | |
和了 | 10.4% | +6848 | 10.7% | +6861 |
放銃 | 11.3% | -6554 | 11.2% | -6612 |
被ツモ | 31.5% | -2735 | 31.4% | -2749 |
横移動 | 28.5% | -69 | 28.6% | -69 |
流局 | 18.3% | -762 | 18.0% | -750 |
平均 | -1047 | -1027 |
改善前 | 改善(1) | 改善前 | 改善(1) | ||
---|---|---|---|---|---|
対戦数 | 1,000 | 1,000 | 総局数 | 10,480 | 10,488 |
1位率 | .237 | .237 | 和了率 | .213 | .215 |
2位率 | .244 | .250 | 放銃率 | .133 | .133 |
3位率 | .248 | .244 | 立直率 | .231 | .233 |
4位率 | .271 | .269 | 副露率 | .342 | .342 |
平均順位 | 2.55 | 2.55 | 平均打点 | 5,622 | 5,626 |
局収支は改善したが、平均順位はほぼ変化なし、和了率は若干向上した。まずはこの改善を採用することとする。
2021-04-03 追記
集計の際に当該の牌が現物だったケースを除いていないミスがあったので修正しました。
*1:この表自体は『科学する麻雀』の牌の危険度表を元にしている