這篇文章將利用之前所學過的一些東西,包括if敘述、串列、while迴圈、函數等等的觀念,來實作一個撲克牌的小遊戲-21點[1]。
遊戲規則
使用一副撲克牌,不含鬼牌,由電腦扮演莊家,使用者為玩家,牌局結束後由點數高的一方獲勝,但點數不可超過21點。A可記為1點或11點,2點到10點的點數以牌面的點數計算,J、Q、K都計為10點。
遊戲與程式邏輯
- 隨機發給玩家一張牌。
- 隨機發給莊家一張牌(暗牌)。
- 隨機發給玩家第二張牌。
- 隨機發給莊家第二張牌(明牌)。
- 顯示莊家的明牌,並詢問玩家是否加牌,直到玩家不加牌,或是點數超過21點。
- 莊家的點數若不足17點必須加牌,直到點數超過或等於17點。
- 依以下條件依序判斷獲勝者:
- 若玩家超過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~
程式範例