2021年8月16日 星期一

Python 學習筆記 : 用 random 模組洗牌與發牌

我對於博弈相關的東西大都很陌生, 撲克有數字與花色, 高達 52 支牌有點複雜; 更不要說麻將這麼多牌讓人昏頭轉向, 只有骰子簡單易懂. 上週學姊除了骰子問題外, 還問我撲克發牌問題, 此題希望用 Python 寫一個發牌程式給四個玩者, 此題我想了兩天才想好作法, 我在 random 模組裡找到 shuffle() 函數可用來洗牌, 另外在下面這篇文章看到內建模組 itertools 有 product() 函數可用來組合花色與數字, 參考 : 


程式碼如下 :

import itertools
import random

c=['♥', '♠', '♣', '♦']                          # 花色
n=['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']    # 數字
cards=[]                                         # 用來記錄 52 張牌
for i in itertools.product(c, n):    # 用花色與數字組合出 4x13=52 張牌 
    cards.append(i)
random.shuffle(cards)  #洗牌   
print("洗牌結果 :\n", cards)
print("A 玩家的牌 :\n", cards[0::4]) 
print("B 玩家的牌 :\n", cards[1::4])
print("C 玩家的牌 :\n", cards[2::4])
print("D 玩家的牌 :\n", cards[3::4])

此程式先建立 4 個花色串列 c 與 13 個數字串列 n, 然後將兩者做為參數傳入 itertools.product() 函數, 它會傳回兩個串列元素的 52 種組合方式, 每一張牌 i 以一個元組表示, 然後再呼叫串列的 append() 方法將每張牌放進串列 cards 中. 呼叫 random.shuffle() 可將串列 cards 的元素重新隨機排列達到洗牌的效果, 最後用切片每跳 4 格取一張牌給一個玩者, 相當於是依序發牌, 結果如下 :

洗牌結果 :
 [('♥', '7'), ('♠', 'Q'), ('♣', '6'), ('♦', '7'), ('♠', '9'), ('♦', 'J'), ('♠', '6'), ('♥', '10'), ('♦', '5'), ('♦', '6'), ('♣', '2'), ('♠', 'A'), ('♠', '10'), ('♦', 'A'), ('♦', '4'), ('♣', 'J'), ('♥', '2'), ('♠', '7'), ('♣', '8'), ('♥', '5'), ('♥', 'A'), ('♣', 'A'), ('♦', '8'), ('♥', '3'), ('♦', 'K'), ('♣', 'K'), ('♠', '5'), ('♠', '4'), ('♥', '4'), ('♥', '6'), ('♣', '10'), ('♣', '7'), ('♦', '9'), ('♠', 'K'), ('♥', '8'), ('♣', '4'), ('♦', '10'), ('♦', '2'), ('♦', 'Q'), ('♠', '3'), ('♥', 'J'), ('♣', '5'), ('♠', 'J'), ('♣', '9'), ('♠', '2'), ('♥', 'K'), ('♥', 'Q'), ('♠', '8'), ('♣', 'Q'), ('♥', '9'), ('♣', '3'), ('♦', '3')]
A 玩家的牌 :
 [('♥', '7'), ('♠', '9'), ('♦', '5'), ('♠', '10'), ('♥', '2'), ('♥', 'A'), ('♦', 'K'), ('♥', '4'), ('♦', '9'), ('♦', '10'), ('♥', 'J'), ('♠', '2'), ('♣', 'Q')]
B 玩家的牌 :
 [('♠', 'Q'), ('♦', 'J'), ('♦', '6'), ('♦', 'A'), ('♠', '7'), ('♣', 'A'), ('♣', 'K'), ('♥', '6'), ('♠', 'K'), ('♦', '2'), ('♣', '5'), ('♥', 'K'), ('♥', '9')]
C 玩家的牌 :
 [('♣', '6'), ('♠', '6'), ('♣', '2'), ('♦', '4'), ('♣', '8'), ('♦', '8'), ('♠', '5'), ('♣', '10'), ('♥', '8'), ('♦', 'Q'), ('♠', 'J'), ('♥', 'Q'), ('♣', '3')]
D 玩家的牌 :
 [('♦', '7'), ('♥', '10'), ('♠', 'A'), ('♣', 'J'), ('♥', '5'), ('♥', '3'), ('♠', '4'), ('♣', '7'), ('♣', '4'), ('♠', '3'), ('♣', '9'), ('♠', '8'), ('♦', '3')]

當然不一定要用 itertools.product(), 硬將 52 張牌敲進串列 cards 中也是可以的. 做完這幾題我才發現自己對 Python 資料型態的用法還是不夠, 基礎功還是需要不斷加強複習. 

在尋找解決方案途中看到下面這篇文章, 其中談排列組合的差別讓我這個機率統計弱弱的人來說可謂醍醐灌頂 :


另外一篇關於發牌程式的文章則有點複雜, 參考 :


沒有留言 :