用 list、dict、def 打造完整的 21 點遊戲!
結合第四章函式 + 第五章資料結構
用 list comprehension 建出 52 張牌,再用 shuffle 洗牌:
import random
def create_deck():
"""建立一副 52 張撲克牌"""
suits = ["♠", "♥", "♦", "♣"]
ranks = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"]
deck = [r + s for s in suits for r in ranks]
random.shuffle(deck)
return deck
deck = create_deck()
print(f"牌堆:{len(deck)} 張")
print(f"前 5 張:{deck[:5]}")
把「建牌」包成函式,以後想重新開局只要呼叫一次 create_deck() 就好。
從牌堆頂抽牌,用 pop() 同時移除和回傳:
def deal(deck, hand, n=1):
"""從牌堆抽 n 張牌加到手牌中"""
for i in range(n):
card = deck.pop() # 抽出最上面那張
hand.append(card) # 加入手牌
# 使用
deck = create_deck()
player_hand = [] # 玩家手牌(空 list)
dealer_hand = [] # 莊家手牌(空 list)
deal(deck, player_hand, 2) # 玩家發 2 張
deal(deck, dealer_hand, 2) # 莊家發 2 張
print(f"你的手牌:{player_hand}")
print(f"莊家的手牌:[{dealer_hand[0]}, ?]") # 莊家第 2 張蓋住
這是最關鍵的函式 — A 要能自動判斷算 11 還是 1:
def hand_value(hand):
"""計算手牌總點數,A 自動判斷 11 或 1"""
values = {"A":11, "K":10, "Q":10, "J":10,
"10":10,"9":9,"8":8,"7":7,
"6":6,"5":5,"4":4,"3":3,"2":2}
total = 0
ace_count = 0 # 記錄有幾張 A
for card in hand:
rank = card[:-1] # 去掉花色,例如 "A♠" → "A"
total += values[rank]
if rank == "A":
ace_count += 1
# 如果爆了,且手上有 A,就把 A 從 11 改成 1(減 10)
while total > 21 and ace_count > 0:
total -= 10
ace_count -= 1
return total
先全部算 11,如果超過 21 就逐張改成 1(減 10)。
例如 A + A + 9 = 11+11+9 = 31 → 改一張 A → 21!
把手牌和點數漂亮地印出來:
def show_hand(name, hand, hide_second=False):
"""顯示某位玩家的手牌和點數"""
if hide_second:
# 莊家的第二張牌蓋住
display = f"{hand[0]}, ?"
print(f"{name}:{display}")
else:
display = ", ".join(hand)
total = hand_value(hand)
print(f"{name}:{display}({total} 點)")
# 使用
show_hand("你", ["A♠", "K♥"]) # 你:A♠, K♥(21 點)
show_hand("莊家", ["7♦", "J♣"], True) # 莊家:7♦, ?
預設 False,只有莊家在玩家回合時才需要蓋牌,傳入 True。
這就是預設參數的實用場景!
def player_turn(deck, hand):
"""玩家回合:選擇抽牌或停牌"""
while True:
show_hand("你", hand)
total = hand_value(hand)
if total == 21:
print("Blackjack!🎉")
break
if total > 21:
print("爆牌了!💥")
break
choice = input("要抽牌(h)還是停牌(s)?")
if choice == "h":
deal(deck, hand)
print(f"抽到:{hand[-1]}") # 最後一張就是剛抽的
else:
print("你選擇停牌。")
break
def dealer_turn(deck, hand):
"""莊家回合:未滿 17 點必須繼續抽牌"""
print("\n--- 莊家翻牌 ---")
show_hand("莊家", hand)
while hand_value(hand) < 17:
deal(deck, hand)
print(f"莊家抽了一張:{hand[-1]}")
show_hand("莊家", hand)
total = hand_value(hand)
if total > 21:
print("莊家爆牌了!💥")
莊家沒有選擇權 — 未滿 17 點一定要抽,17 點以上就停。
這個規則用 while hand_value(hand) < 17 一行就搞定!
def judge(player_hand, dealer_hand):
"""判斷勝負"""
p = hand_value(player_hand)
d = hand_value(dealer_hand)
print(f"\n--- 結算 ---")
print(f"你:{p} 點 vs 莊家:{d} 點\n")
if p > 21:
print("你爆牌了,莊家贏!😢")
elif d > 21:
print("莊家爆牌,你贏了!🎉")
elif p > d:
print("你贏了!🎉")
elif d > p:
print("莊家贏!😢")
else:
print("平手!🤝")
# --- 遊戲主程式 ---
print("🃏 歡迎來到 21 點!\n")
# 1. 建立牌組
deck = create_deck()
# 2. 發牌
player_hand = []
dealer_hand = []
deal(deck, player_hand, 2)
deal(deck, dealer_hand, 2)
# 3. 顯示初始手牌(莊家蓋一張)
show_hand("莊家", dealer_hand, hide_second=True)
print()
# 4. 玩家回合
player_turn(deck, player_hand)
# 5. 如果玩家沒爆,換莊家
if hand_value(player_hand) <= 21:
dealer_turn(deck, dealer_hand)
# 6. 判斷勝負
judge(player_hand, dealer_hand)
主程式只有十幾行!所有複雜的邏輯都藏在函式裡面。
讀主程式就像在讀遊戲規則,一目瞭然。
| 技巧 | 用在哪裡 |
|---|---|
list | 牌堆 deck、手牌 hand |
list comprehension | 一行建出 52 張牌 |
.pop() / .append() | 抽牌 / 加入手牌 |
dict | 牌面 → 點數對照 values |
def + return | 6 個函式各司其職 |
| 預設參數 | deal(n=1)、show_hand(hide_second=False) |
while 迴圈 | 玩家回合、莊家回合、A 的處理 |
random.shuffle() | 洗牌 |
你已經用 Python 寫出一個完整的 21 點遊戲!
試試看加入更多功能吧。