目錄

廣告 AD

揭開臺灣麻將的神秘面紗!臺灣麻將天聽機率到底有多高?

- 麻將天聽

在台灣,麻將應該很多人都打過,但有誰天胡過呢?

可能有大大有遇過,但至少本貓我是沒遇過啦 ┐(´д`)┌

為了證明我不是非洲人,所以我就來算算看天胡的機率。

廣告 AD

排列組合

在遊戲剛開始,大家會拿到 16 張牌,莊家開門後手上會有 17 張牌。

這時如果莊家胡了,那就稱作天胡。

所以我們要算的就是直接從麻將牌堆裡面隨機拿 17 張可以直接胡牌的機率

這時候是不是有人說:“這簡單,我只要將從牌堆裡面拿 17 張的所有可能找出來,並檢查看看是否胡牌,統計一下就能知道機率了”。

想法很好,但計算太久了,你算看看,麻將包含 4 種花色,萬筒條共有 $9\times4\times3$ 個,字牌有 $7\times4$ 個,一共有 136 張。

算上排列組合之後共有 $\dbinom{136}{17} = 1,845,382,436,487,682,488,000$ 種拿取的方法 (同樣的牌都當做不同)。

這簡直是天文數字,不知道要算多久,因此,我們既然沒辦法列出所有可能,但我們換個方向,是不是可以找出所有胡牌手牌?


大家都知道,台灣麻將胡牌的時候要有 5 組面子 (刻子或順子) 加上 1 個對子 (眼睛),像下圖這樣:

面子、順子、刻子和對子

面子:順子或是刻子

  • 順子:數字連續三張同花色的牌
  • 刻子:三張相同的牌
  • 對子:兩張相同的牌

我們可以注意到 5 組面子和 1 個對子可能落在萬筒條字中任何一個。

單看一種花色的話,其實有 12 種狀態:

  • 0 個對子
    • 0 個面子
    • 1 個面子
    • 2 個面子
    • 3 個面子
    • 4 個面子
    • 5 個面子
  • 1 個對子
    • 0 個面子
    • 1 個面子
    • 2 個面子
    • 3 個面子
    • 4 個面子
    • 5 個面子

大致上來說就是 0 ~ 5 個面子再算上有沒有對子。

萬筒條字每一種花色都有這 12 種狀態,透過組合,就能形成一組胡牌手牌了。

例如:我們萬拿 1 組面子,筒也拿 1 組面子,條拿 3 組面子,字拿 1 個對子,這樣共有 5 組面子和 1 個對子,可以胡牌。

也可以萬拿 3 組面子和 1 組對子,筒也拿 1 組面子,條拿 1 組面子,這樣也有 5 組面子和 1 個對子。

列出其中幾種組合:

1 面1 面3 面1 對
3 面 + 1 對1 面1 面-
2 面1 面 + 1 對1 面1 面
4 面-1 面 + 1 對-
---5 面 + 1 對

到這裡,你是不是發現到,如果我們能知道這每一種組合類型的胡牌手牌有多少種,那全部加起來就是我們所要找的胡牌手牌個數!!!


如果說,用上面的例子,萬拿 1 組面子,筒也拿 1 組面子,條拿 3 組面子,字拿 1 個對子。

我分別告訴你萬筒條字在各自的條件下,有多少個可能,相信大家都能知道那個例子的條件下共有多少胡牌手牌,沒錯,全部相乘起來。

假設萬 1 組面子的可能共有 a 個,筒 1 組面子的可能有 b 個,條拿 3 組面子的可能有 c 個,字拿 1 個對子的可能有 d 個,那該例子的胡牌手牌就是 $a\times b\times c \times d$。


至於計算萬拿 1 組面子的可能的方式,我們就直接列舉所有可能,並計算目標個數。

不同張牌

⚠️ 注意:由於我們將所有牌當作不同張牌,因此我們在計算的時候要考慮到選擇的問題。

例如:345 萬,3 萬可以從 4 張裡面選擇 1 張,4 萬和 5 萬也是,這樣共有 $4^3$ 種不同的組合,雖然都是 345 萬,但是因為用了不同的 3 萬、4 萬和 5 萬,因此被當作不同的組合。

如果用 Python 寫起來的話,大概長下方這樣。

python

# 萬有 1 萬到 9 萬,每個共有 0 張到 4 張
numEachTile = [list(range(5)) for i in range(9)]
allPossibleHands = list(itertools.product(*numEachTile))

# 對於每種萬的手牌
for hand in allPossibleHands:
  # 由於我們只拿一組,因此就拿 3 張
  if sum(comb) != 3: continue
  # 雖然是 3 張,但也要確認是不是面子
  if checkSets(list(hand)):
    # 找到符合條件的手牌
    found += permutation(list(hand)) # 紀錄次數

其中 permutation 的部分只要用 $\dbinom{4}{k}$ 計算即可,k 為同樣張牌的個數。

python

# 計算 n 個裡面取 r 個的種類
def ncr(n, r):
  r = min(r, n-r)
  numer = reduce(op.mul, range(n, n-r, -1), 1)
  denom = reduce(op.mul, range(1, r+1), 1)
  return numer // denom
# 有多少種不同的選擇
NCR = [ncr(4, i) for i in range(5)]
def prob(hand):
  p = 1
  for i in range(len(hand)):
    p *= NCR[hand[i]]
  return p

以下列出其中幾個找出來符合條件的結果:

如果說要找 1 組以上,那就調整一下參數即可。

使用上方的方法,我們可以計算出特定一種花色下,符合面子條件的個數,並分別計算 a, b, c。

至於計算字牌 1 組對子的方式只要調整一下就可以了:

python

# 字牌有 7 種,每個共有 0 張到 4 張
numEachTile = [list(range(5)) for i in range(7)]
allPossibleHands = list(itertools.product(*numEachTile))

# 對於每種字牌的手牌
for hand in allPossibleHands:
  # 由於我們要 1 組對子,因此拿 2 張
  if sum(comb) != 2: continue
  # 確認是不是對子
  if checkPair(list(hand)):
    # 找到符合條件的手牌
    found += permutation(list(hand)) # 紀錄次數

那在計算出 a, b, c, d 之後,我們就可以全部相乘起來,找到在 “萬拿 1 組面子,筒也拿 1 組面子,條拿 3 組面子,字拿 1 個對子” 的狀況下的胡牌手牌個數


上面提到的方法,看起來沒問題,寫起來不難。

但如果我今天要找萬有 2 組面子,怎麼樣才能有效率地判斷呢?

更甚至,如果今天萬有 5 組面子和 1 組對子,那到底要怎麼判斷才快呢?

在打麻將的時候,其實就常常遇到這個問題吧?

這篇 paper1 裡有提到快速判斷胡牌的方法,我們可以拿來判斷問題。

我們先考慮沒有對子的時候。

我們從數字 1 開始檢查。

  • 如果這個數字數量 $\geq 3$ 個,那我們直接拿走一組刻子 (三張一樣的)。
  • 如果數量 $\geq 0$ 個,但是不滿 3 個,那我們判斷順子,也就是向後看兩個,判斷是否有順子,有就拿走,沒有就代表不符合條件。
  • 如果數量 $= 0$ 個,我們就換下個數字檢查。

因為我們只有剛好足夠組成條件的牌,例如萬要 1 組面子,我們手上就只有 3 張,要有多的牌,那一定就組不成了。


舉例如果現在要判斷是否為 2 組面子,手牌呈現如下:

從數字 1 開始,由於有 4 張,我們首先拿走 3 張,剩下這些:

由於數字 1 只剩下 1 張,因此檢查順子,剛好有 1 組順子,於是就拿走,剛好沒了。

由於後面都沒有了,就一直跳下一個數字,直到數字 9 結束後都沒有錯誤,該手牌即為我們要找的。


我們再看一組錯誤的,現在要判斷是否為 3 組面子,手牌如下:

從數字 1 開始,因為沒有,換看數字 2。

由於數字 2 不到 3 張,因此看順子,由於數字 2 可以湊成一組順子,剩下:

可以看到數字 2 和數字 3 湊不成順子,因此這手牌不含有 3 組面子。


萬筒條結束了,那字怎麼辦?

字由於沒有順子,因此簡單的多,就直接看各數字張數。

  • 數量為 0 或是 3:符合條件。
  • 數量為 1 或是 2:不符合條件。

由於字牌只能組成刻子,因此不是 0 張就是 3 張。


像是下列手牌就不是我們要找的字含有 1 組面子:

因為東和西分別為 2 張和 1 張,不是 0 或是 3。

那如果我們考慮更複雜的情況,今天要判斷 5 組面子和 1 組對子。

其實換個想法,既然對子只有一組,那我們假設所有對子的情況,然後將對子剔除,剩下的跑只有面子的判斷方法不就好了嗎!!!

用這個方式,假設對子的情況只要有一個判斷成功,那就是成功了。


舉例,今天要找 2 組面子和 1 組對子。

由於對子為兩張,因此只要假設數字有超過 2 張的就好了。

  • 假設 1:
    •   為對子,剩下  
    • 明顯剩下的沒有 2 組面子。
  • 假設 2:
    •   為對子,剩下  
    • 剩下剛好     一組,     為一組。

雖然假設 1 錯誤,但假設 2 通過,所以手牌符合條件。

好啦,說了那麼多方法,那到底本貓我到底是不是非洲人?

台灣麻將一共有 1,554,490,175,889,888 組胡牌手牌。

如果算上機率的話 (除以 $\dbinom{136}{17}$) 大約為 0.0000008424 ($\frac{1}{1,187,130}$)。

換句話說就是 119 萬次才會出現一次,我想我沒有打過那麼多次的麻將… 所以我不是非洲人!!!

順帶一提,大樂透的頭獎機率要 1400 萬次才會中一次。

恩…….我已經兩年沒有中發票了,我還是先不要嘗試好了。


  • 本篇麻將牌都由 FluffyStuff 製作的麻將牌圖片 Link

廣告 AD