不間斷 Python 挑戰 Day 16 - 專題:21點 (Blackjack)

2021/12/26閱讀時間約 8 分鐘
這篇文章將利用之前所學過的一些東西,包括if敘述、串列、while迴圈、函數等等的觀念,來實作一個撲克牌的小遊戲-21點[1]。

遊戲規則

使用一副撲克牌,不含鬼牌,由電腦扮演莊家,使用者為玩家,牌局結束後由點數高的一方獲勝,但點數不可超過21點。A可記為1點或11點,2點到10點的點數以牌面的點數計算,J、Q、K都計為10點。

遊戲與程式邏輯

  1. 隨機發給玩家一張牌。
  2. 隨機發給莊家一張牌(暗牌)。
  3. 隨機發給玩家第二張牌。
  4. 隨機發給莊家第二張牌(明牌)。
  5. 顯示莊家的明牌,並詢問玩家是否加牌,直到玩家不加牌,或是點數超過21點。
  6. 莊家的點數若不足17點必須加牌,直到點數超過或等於17點。
  7. 依以下條件依序判斷獲勝者:
    - 若玩家超過21點,則莊家獲勝,無論莊家是否超過21點。
    - 若莊家超過21點,則玩家獲勝。
    - 若玩家和莊家的點數相同,則平手。
    - 若玩家的點數大於莊家的點數,則玩家獲勝。
    - 若玩家的點數小於莊家的點數,則莊家獲勝。

程式架構

建立牌組

A到K共13種點數的牌各4張,不區分花色,A先預設為11點,J、Q、K皆為10點。
cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10] * 4

建立發牌函數

當函數被呼叫時,從牌組中隨機選出一張牌,並將該點數的牌從牌組中移除。
def deal_card():
  card = random.choice(cards)
  cards.remove(card)
  return card

建立記點函數

先計算傳入牌組的點數總和,再根據傳入牌組的張數有不同的判斷邏輯:
  • 若傳入2張牌,不須修改點數,直接回傳。
  • 若傳入超過2張牌,且點數超過21點,檢查牌組中是否有A(11點),若有則將其改成1點。
  • 其它狀況則直接回傳點數。
def calculate_points(cards):
  total_points = sum(cards)
  # 2 cards
  if len(cards) == 2:
    return total_points
  # more than 2 cards
  if total_points > 21:
    if 11 in cards:
      cards.remove(11)
      cards.append(1)
      total_points = sum(cards)
  return total_points

建立遊戲流程函數

將遊戲流程建成一個函數play_blackjack(),依序執行:隨機發兩張牌給玩家和莊家、玩家加牌、莊家加牌、判斷贏家。
首先分別為玩家和莊家建立兩個空的牌組:
user_cards = []
dealer_cards = []
使用for迴圈為玩家和莊家隨機發兩張牌,並顯示玩家的牌和莊家的明牌:
for _ in range(2):
  user_cards.append(deal_card())
  dealer_cards.append(deal_card())
print(f"玩家的牌:{user_cards}")
print(f"莊家的明牌:{dealer_cards[1]}")
使用while迴圈持續詢問玩家是否加牌,直到玩家停止加牌,或點數超過21點:
ask_for_card = ""
while ask_for_card != "n":
  ask_for_card = input("輸入y加牌、輸入n看結果:")
  
  if ask_for_card == "y":
    user_cards.append(deal_card())
    user_points = calculate_points(user_cards)
    if user_points > 21:
      ask_for_card = "n"
    else:
      print(f"玩家的牌:{user_cards}")
    elif ask_for_card == "n":
      user_points = calculate_points(user_cards)
  else:
    print("請重新輸入!輸入y加牌、輸入n看結果:")
若莊家的牌點數小於17點,則使用while迴圈持續為莊家加牌:
dealer_points = calculate_points(dealer_cards)
while dealer_points < 17:
  dealer_cards.append(deal_card())
  dealer_points = calculate_points(dealer_cards)
顯示玩家和莊家最後的牌組:
print(f"玩家的牌:{user_cards},共{user_points}點")
print(f"莊家的牌:{dealer_cards},共{dealer_points}點")
根據「遊戲與程式邏輯」一節的規則判斷最後的贏家:
if user_points > 21:
  print("你輸了!")
elif dealer_points > 21:
  print("你贏了!")
elif user_points == dealer_points:
  print("平手!")
elif user_points > dealer_points:
  print("你贏了!")
else:
  print("你輸了!")

主程式

到目前為止,我們已經將相同功能的單位包裝成函數。主程式的部分,我們呼叫play_blackjack()函數執行遊戲流程,並使用while迴圈持續詢問玩家是否要重新開始,或是結束遊戲。
play_game = True
print("歡迎來到21點遊戲!")
play_blackjack()
while play_game == True:
  print("=======================================")
  user_input = input("重新進行遊戲?請輸入y開始、輸入n結束:")
  if user_input == "y":
    play_blackjack()
  elif user_input == "n":
    play_game = False
    print("Bye~")
  else:
    continue

遊戲畫面

歡迎來到21點遊戲!
玩家的牌:[10, 8]
莊家的明牌:3
輸入y加牌、輸入n看結果:n
玩家的牌:[10, 8],共18點
莊家的牌:[10, 3, 2, 8],共23點
你贏了!
=======================================
重新進行遊戲?請輸入y開始、輸入n結束:y
玩家的牌:[4, 11]
莊家的明牌:2
輸入y加牌、輸入n看結果:y
玩家的牌:[4, 8, 1]
輸入y加牌、輸入n看結果:y
玩家的牌:[4, 8, 1, 10],共23點
莊家的牌:[10, 2, 7],共19點
你輸了!
=======================================
重新進行遊戲?請輸入y開始、輸入n結束:n
Bye~

程式範例

為什麼會看到廣告
Wei-Jie Weng
Wei-Jie Weng
留言0
查看全部
發表第一個留言支持創作者!