聴牌確率・和了確率・点数期待値の考え方

目次

概要

このページでは、何切る評価で使う聴牌確率和了確率点数期待値の考え方を説明します。

目的は、ある局面で候補となる打牌を比べることです。各打牌について、次の値を計算します。

  • 聴牌確率: 最終巡までに聴牌できる確率
  • 和了確率: 最終巡までに自摸和了できる確率
  • 点数期待値: 自摸和了したときの点数まで含めた平均的な価値

謝辞

本記事に記載のある確率計算の考え方は tomohxx 氏の 6. 和了確率 – 麻雀アルゴリズム で解説されている方法に依拠しています。 同記事では、手牌変化をグラフとして表し、巡目を逆向きにたどる動的計画法で和了確率・得点期待値を求める方法が説明されています。詳細な導出や背景については、同記事をご参照ください。

何切る問題

何切る問題とは、麻雀において 14 枚の手牌からどの牌を切るべきかを考える問題です。

ここでは説明を簡単にするため、他家の動向は考えず、終局または和了まで自摸と打牌を繰り返す「一人麻雀」として扱います。

たとえば、点数を重視するなら点数期待値が最大となる打牌を、オーラスのトップ目で和了そのものを重視するなら和了確率が最大となる打牌を選ぶ、という考え方ができます。

実戦では、点棒状況、牌の危険度、場に出ている牌の枚数なども含めて判断する必要があります。そのため、一人麻雀での最善手がそのまま実戦の最善手になるとは限りません。それでも、牌効率や手牌価値を定量的に見るための基礎として、一人麻雀の計算は有用です。

受入枚数と点数期待値

何切る問題では、受入枚数を基準に打牌を選ぶことがよくあります。受入枚数は、次の自摸で向聴数を 1 つ下げられる牌が何枚残っているかを表す指標です。

そのため、受入枚数が最大となる打牌は、次の自摸で手を進める確率を最大化する打牌だと言えます。ただし、受入枚数は「次の自摸」だけを見る指標なので、その後の変化までは直接表しません。

たとえば、直前の受入枚数は少なくても、その後に良形変化しやすい打牌や、一気通貫・全帯么九などの役を狙いやすい打牌の方が高く評価されることがあります。

そこで、受入枚数だけでなく、聴牌確率、和了確率、点数期待値を使って打牌を評価します。これにより、次の自摸だけでなく、その先の手牌変化や和了時の点数まで含めて比較できます。

計算モデル

実際の麻雀は 4 人で打ち、相手の打牌や鳴き、ロン和了などが絡みます。これらをすべて考えるとモデルが複雑になるため、ここでは次のような一人麻雀モデルで考えます。

  • 他家の手牌、打牌、鳴き、ロン和了は考慮しない
  • 和了は自摸和了のみを評価する
  • 途中のポン、チー、カンは考慮しない。ただし、計算開始時点ですでにある副露は設定できる
  • 自分は毎巡、1 枚自摸して 1 枚切る
  • 切った牌は山に戻るものとして扱う
  • 打牌後に次の自摸を待つ状態では、山の総枚数は巡目によらず一定とみなす(実際は自摸のたびに減るが、計算を簡単にするための近似)

点数は、局面情報を使って評価します。

  • 場風、自風、親子、ドラ、赤ドラを考慮する
  • 門前で聴牌を維持する打牌を選んだ後は、立直したものとして扱う
  • 本場、供託棒、不聴罰符は考慮しない
  • ダブル立直・一発・海底撈月を考慮しない
  • 役がない和了形は 0 点として扱う(副露した手では立直・門前清自摸和がつかないため、役がないことがある)

基本方針

麻雀の進行には、2 種類の場面があります。

  • 自摸後の状態: 14 枚の手牌から、どの牌を切るかを自分で選べる
  • 打牌後の状態: 13 枚の手牌で次の自摸を待つ。何を引くかは確率で決まる

この違いが、計算全体の中心です。

自摸後の状態: 自分で選べるので、候補の中の最大値を取る
打牌後の状態: 引く牌は選べないので、確率で重み付き平均を取る

巡目 $t$ は自摸の回数で数えます。0 巡目は配牌直後の 13 枚の状態で、手牌が 14 枚になる自摸ごとに巡目が 1 つ進みます。打牌では巡目は進みません。そのため、打牌後の状態から次の自摸先を見るときは次巡 $t + 1$ の値を、自摸後の状態から打牌先を見るときは同じ巡 $t$ の値を使います。

No description has been provided for this image

聴牌確率、和了確率、点数期待値は、すべてこの考え方で計算します。

記号

以下の記号を使います。

  • $s$: 手牌と立直の有無を表す状態
  • $S$: 打牌後の状態で、自摸候補となる山の総枚数
  • $t$: 現在の巡目
  • $t_{max}$: 計算を終える巡目。入力された手牌の枚数に関わらず、通常は 18 とする
  • $s’$: 状態 $s$ から 1 回の自摸、または打牌で進んだ先の状態
  • $w_{s \to s’}$: 遷移 $s \to s’$ に対応する自摸牌の山にある枚数
  • $\text{score}_{s \to s’}$: 遷移 $s \to s’$ で和了できる場合の点数
  • $v_t^s$: 巡目 $t$ における状態 $s$ の評価値。聴牌確率、和了確率、点数期待値のいずれかを表す

山の各牌の枚数は、ドラ表示牌や現在の手牌、副露牌など、自分から見えている牌を除いて決まります。ただし、このモデルでは切った牌は山に戻るものとして扱います。打牌後の状態で山の総枚数を $S$ とすると、ある遷移 $s \to s’$ に対応する牌が山に $w_{s \to s’}$ 枚あるなら、その牌を引く確率は次のようになります。

$$ \frac{w_{s \to s’}}{S} $$

たとえば、山が 100 枚あり、ある牌が 4 枚あるなら、その牌を次に引く確率は $4 / 100$ です。

打牌後の状態

打牌後の状態では、次に何を引くかを選べません。そのため、引く牌ごとの確率で平均を取ります。

ここで $v_t^s$ は「巡目 $t$ の状態 $s$ の評価値」です。つまり、$v_{t + 1}^{s’}$ は「次巡 $t + 1$ に、遷移先の状態 $s’$ へ進んだ後の評価値」を表します。

もっとも単純に書くと、次のような考え方です。

$$ \sum_{s’} \frac{w_{s \to s’}}{S} v_{t + 1}^{s’} $$

ここで $v$ は、聴牌確率、和了確率、点数期待値のいずれかです。

ただし、実際には「探索対象の変化だけ」を遷移として数え、それ以外の自摸は自摸切りして同じ形のまま次巡に進んだものとして扱います。

No description has been provided for this image

例: 手牌が222567m34p3367s4z で探索対象を有効牌 25p58s のみとした場合

探索対象の自摸を引く確率は $\frac{w_{s \to s’}}{S}$ です。それ以外の自摸を引いた場合は、形が変わらないまま次巡へ進むので、値は $v_{t + 1}^{s}$ になります。したがって、まずは次の重み付き平均として書けます。

ここで $1 – \sum_{s’} \frac{w_{s \to s’}}{S}$ は、探索対象のどの牌も引かなかった場合の確率です。

$$ v_t^s = \left(1 – \sum_{s’} \frac{w_{s \to s’}}{S}\right) v_{t + 1}^{s} + \sum_{s’} \frac{w_{s \to s’}}{S} v_{t + 1}^{s’} $$

これを整理すると、次の差分の形になります。

$$ v_t^s = v_{t + 1}^{s} + \sum_{s’} \frac{w_{s \to s’}}{S} \left( v_{t + 1}^{s’} – v_{t + 1}^{s} \right) $$

意味はこうです。

何も改善しなかった場合の次巡の値を基準にする。
そこへ、有効牌を引いたときにどれだけ値が変わるかを、
その牌を引く確率で重み付けして足す。

自摸後の状態

自摸後の状態では、14枚の手牌から打牌を選べます。自分で選べるので、候補の中で最もよい値を採用します。

$$ v_t^s = \max_{s’} v_t^{s’} $$

ここで $s’$ は、何か1枚を切った後の状態です。

No description has been provided for this image

例: 手牌が222567m345p33667s で探索対象を向聴数が変わらない 67s のみとした場合

どの値を最大化するかは、目的によって変わります。

  • 聴牌確率を重視するなら、聴牌確率が最大になる打牌を選ぶ
  • 和了確率を重視するなら、和了確率が最大になる打牌を選ぶ
  • 点数期待値を重視するなら、点数期待値が最大になる打牌を選ぶ

同じ局面でも、目的が違えば選ばれる打牌が変わることがあります。

聴牌確率

聴牌確率は「最終巡までに聴牌できるか」を表します。

ここでは $p_t^s$ を、巡目 $t$ における状態 $s$ の聴牌確率とします。

打牌後

$$ p_t^s = \begin{cases} p_{t + 1}^{s} + \displaystyle\sum_{s’} \frac{w_{s \to s’}}{S} \left( p_{t + 1}^{s’} – p_{t + 1}^{s} \right) & \text{if } t < t_{max} \\ 1 & \text{if } t = t_{max} \text{ かつ } s \text{ が聴牌形} \\ 0 & \text{if } t = t_{max} \text{ かつ } s \text{ が聴牌形以外} \end{cases} $$

最終巡では、聴牌していれば値を 1、聴牌していなければ 0 とします。

自摸後

$$ p_t^s = \begin{cases} 1 & \text{if } s \text{ が聴牌形} \\ \max\limits_{s’} p_t^{s’} & \text{if } s \text{ が聴牌形以外} \end{cases} $$

自摸後の 14 枚がすでに聴牌形なら、いずれかの牌を切れば聴牌を維持できるため 1 とします。聴牌していない場合は、最も聴牌に近づく打牌を選びます。

和了確率

和了確率は「最終巡までに自摸和了できるか」を表します。

聴牌確率との違いは、最終巡で聴牌しているだけでは条件を満たさないことです。和了できなければ 0 です。

ここでは $p_t^s$ を、巡目 $t$ における状態 $s$ の和了確率とします。聴牌確率の節と同じ記号 $p$ を使いますが、表している値は和了確率です。

打牌後

$$ p_t^s = \begin{cases} p_{t + 1}^{s} + \displaystyle\sum_{s’} \frac{w_{s \to s’}}{S} \left( p_{t + 1}^{s’} – p_{t + 1}^{s} \right) & \text{if } t < t_{max} \\ 0 & \text{if } t = t_{max} \end{cases} $$

自摸後

$$ p_t^s = \begin{cases} 1 & \text{if } s \text{ が役ありで和了できる形} \\ \max\limits_{s’} p_t^{s’} & \text{それ以外} \end{cases} $$

役ありで和了できる形なら値を 1 とします。役がない場合はその時点では和了として扱わず、最も和了しやすい打牌を選びます。

点数期待値

点数期待値は、和了できる確率だけでなく、和了したときの点数も含めて評価します。

ここでは $e_t^s$ を、巡目 $t$ における状態 $s$ の点数期待値とします。

点数は和了牌によっても変わるため、和了形を表す状態 $s’$ だけの値ではなく、遷移 $s \to s’$ に付く値として $\text{score}_{s \to s’}$ と書きます。

和了形に到達した場合は、和了点と続行した場合の期待値を比べ、大きい方を採用します。

打牌後

$$ e_t^s = \begin{cases} e_{t + 1}^{s} + \displaystyle\sum_{s’} \frac{w_{s \to s’}}{S} \left( \max\bigl(\text{score}_{s \to s’},\ e_{t + 1}^{s’}\bigr) – e_{t + 1}^{s} \right) & \text{if } t < t_{max} \\ 0 & \text{if } t = t_{max} \end{cases} $$

$\text{score}_{s \to s’}$ は、その自摸で和了できる場合の点数です。和了できない場合、または役がない場合は 0 とします。

自摸後

$$ e_t^s = \max_{s’} e_t^{s’} $$

自摸後は、点数期待値が最も高くなる打牌を選びます。

和了するか続けるか

条件を満たしたら、その評価ではそこで値が決まります。聴牌確率なら聴牌した時点、和了確率なら役ありで和了できた時点で、それ以上先は読みません。

一方、点数期待値では、役ありで和了できる形に到達しても、必ずそこで終わるとは限りません。今和了して得る点数と、和了せず続けた場合の期待値を比べ、大きい方を採用します。

そのため、点数期待値を重視する場合だけ、安い和了を取らずに高い手変わりを待つ方が高く評価されることがあります。

探索する手変わり

すべての手牌変化を無制限に調べると、状態数が非常に多くなります。そのため、現実的な時間で計算できるように探索範囲を絞ります。

主に次の変化を候補にします。

  • 向聴数を進める自摸
  • 向聴数を変えない手変わりの自摸
  • 向聴数を維持する打牌
  • 一時的に向聴数を戻す打牌

ただし、手変わりや向聴戻しは常に無制限に許すわけではありません。元の手牌から遠くなりすぎない範囲で探索します。

立直後は、手変わりや向聴戻しのための探索はしません。待ち牌を引いた場合、聴牌確率と和了確率ではそこで値が決まります。点数期待値では、和了点と続行した場合の期待値を比べます。待ち牌以外を引いた場合は、ツモ切りして同じ状態のまま次巡へ進むものとして扱います。

計算手順

計算は、次の 2 段階に分けて行います。

  1. 現在の手牌から到達しうる状態と遷移を洗い出す
  2. 境界条件から後ろ向きに値を計算する

状態と遷移を洗い出す

まず、どの牌を引くとどの状態へ進むか、どの打牌を選ぶとどの状態へ進むかを一覧できる形にします。これは、打牌後の状態を作る関数と、自摸後の状態を作る関数を相互に呼び出す形で書けます。同じ状態を何度も展開しないように、作成済みの状態は記録します。

draw_node(s):
    if s が作成済み:
        return s に対応するノード

    打牌後のノードを作成する

    for each 自摸候補 tile:
        s_draw = s に tile を自摸した状態
        target = discard_node(s_draw)
        遷移 s -> target を追加する

    return s に対応するノード


discard_node(s):
    if s が作成済み:
        return s に対応するノード

    自摸後のノードを作成する

    for each 打牌候補 tile:
        s_discard = s から tile を打牌した状態
        target = draw_node(s_discard)
        打牌による遷移 s -> target を追加する

    return s に対応するノード

この段階では値を計算せず、状態同士がどの遷移でつながるかだけを記録します。

次に、最終巡のように値を直接決められる境界条件を決めます。たとえば、聴牌確率なら最終巡で聴牌していれば 1、していなければ 0 です。

境界条件の値が分かれば、そこから 1 つ前の状態、さらにもう 1 つ前の状態を順に計算できます。各巡目では、打牌後の状態を先に計算します。打牌後の状態は計算済みの次巡 $t + 1$ の値から求められ、自摸後の状態は同じ巡目 $t$ の打牌後の値を使って最大値を取るためです。

評価値ごとの計算は、境界条件と、目的を満たした状態の扱いが異なります。具体的には次のようになります。

聴牌確率の計算

聴牌確率では、「最終巡までに聴牌できるか」を評価します。

打牌後の状態では、最終巡に到達した時点で聴牌していれば 1、していなければ 0 とします。自摸後の状態では、すでに聴牌形ならそれ以上先を読まず、値を 1 とします。

for t = t_max down to 0:
    # 打牌後の状態を計算する
    for each 打牌後の状態 s:
        if t == t_max:
            v[t][s] = 1 if s が聴牌形 else 0
        else:
            v[t][s] = v[t + 1][s]
            for each 自摸による遷移 s -> s':
                value = v[t + 1][s']
                v[t][s] += w[s -> s'] / S * (value - v[t + 1][s])

    # 自摸後の状態を計算する
    for each 自摸後の状態 s:
        if s が聴牌形:
            v[t][s] = 1
        else:
            v[t][s] = max(v[t][s'] for each 打牌による遷移 s -> s')

和了確率の計算

和了確率では、「最終巡までに自摸和了できるか」を評価します。

打牌後の状態では、最終巡に到達した時点で値を 0 とします。自摸後の状態では、役ありで和了できる形ならそれ以上先を読まず、値を 1 とします。

for t = t_max down to 0:
    # 打牌後の状態を計算する
    for each 打牌後の状態 s:
        if t == t_max:
            v[t][s] = 0
        else:
            v[t][s] = v[t + 1][s]
            for each 自摸による遷移 s -> s':
                value = v[t + 1][s']
                v[t][s] += w[s -> s'] / S * (value - v[t + 1][s])

    # 自摸後の状態を計算する
    for each 自摸後の状態 s:
        if s が役ありで和了できる形:
            v[t][s] = 1
        else:
            v[t][s] = max(v[t][s'] for each 打牌による遷移 s -> s')

点数期待値の計算

点数期待値では、最終巡の値は 0 とします。自摸で和了できる場合は、そこで和了する点数と、和了せずに続けた場合の期待値を比べ、大きい方を採用します。

for t = t_max down to 0:
    # 打牌後の状態を計算する
    for each 打牌後の状態 s:
        if t == t_max:
            v[t][s] = 0
        else:
            v[t][s] = v[t + 1][s]
            for each 自摸による遷移 s -> s':
                value = max(和了点(s -> s'), v[t + 1][s'])
                v[t][s] += w[s -> s'] / S * (value - v[t + 1][s])

    # 自摸後の状態を計算する
    for each 自摸後の状態 s:
        v[t][s] = max(v[t][s'] for each 打牌による遷移 s -> s')

まとめ

この計算の中心は、自摸後は候補の最大値を取り、打牌後は自摸牌ごとの確率で平均を取ることです。

聴牌確率、和了確率、点数期待値は、どれもこの同じ骨格で計算できます。違うのは、聴牌を目標にするか、和了を目標にするか、和了点まで含めて評価するかです。

現在の打牌は、未来の自摸と未来の打牌選択によって価値が決まります。その未来を最終巡から逆向きにたどることで、各打牌候補を比較できます。

コメント

コメント一覧 (5件)

  • こんにちは。

    些細な質問なのですが、30符4ハンは7900点での計算でしょうか?

  • 初めまして。いつも非常に参考にさせていただいております。

    平面の何牌切る? ですが、メンゼンテンパイの場合。
    リーチとダマでの期待値(手変わりを考慮して)の差も出していただけると嬉しいです。
    リーチだと当然1翻増えますし、一発の可能性や裏ドラが乗るかもしれませんので打点期待値も変わってきます。
    (和了率は、リーチだと当然他家が警戒してロン和了の和了率が下がるので無くても構いませんし、追い掛けの場合は先制リーチが何人居るかで和了率の算出していただけるならそれは嬉しいですが、アルゴリズムが複雑化して改良が大変かと思われますので、そこまでは求めません)

    Xにて以下の問題が出題されました。
    東1局親0本場。4巡目。ドラ東

    手牌
    一・二・三・四・伍・六・七・七萬4・6ピン、4・5・6ソウ
    ダマにしてたら7ピンを引いた。どの牌切る? リーチ判断は?

    私はツモ切り7ピンリーチが良い(5ピン暗カンされたら最悪ですが、真ん中の牌は横に伸ばし易いので端より暗カンされにくいですし、もし手変わり待っている間に5ピン切られたら損)と判断しました。
    しかしリプ欄の意見は多様で、中には論理的説明が書いてあるものもあり、「ダマも一理あるのかな?」とも思いました。

    次に、局が東一局と南一局から動かせませんので、動かせるなら方法を知りたいですし、動かせないなら動かしたいです。
    例えば、オーラスでの点差状況判断を加味すると打ち形変える方が良いかもしれないけど、シミュレーターはこの様に回答しているので、差分をどの様に考えるか?の良い切欠になりそうです。

    如何でしょうか? よろしくどうぞ、お願いいたします。

    • コメントありがとうございます。
      週末に確認して改めて返信いたします。

コメントする

目次