20点游戏(也称为“21点”或“黑杰克”)是一种流行的卡牌游戏,玩家的目标是尽量接近21点而不超过。游戏通常在赌场中进行,但我们可以通过编程将其转化为一个命令行游戏。在本教程中,我们将使用Python编写一个简单的20点游戏,包括游戏规则、代码实现、测试和扩展功能等内容。

1. 游戏规则

在开始编写代码之前,我们需要了解20点游戏的基本规则:

  1. 游戏使用一副标准的52张扑克牌。
  2. 每张牌的点数如下:
  • 数字2到10按面值计算。
  • J、Q、K 均计为10点。
  • A 可以计为1点或11点,具体取决于哪种方式对玩家更有利。
  1. 玩家和庄家各自开始时可获得两张牌,玩家可以选择要牌(Hit)或停牌(Stand)。
  2. 玩家总点数超过21点则为爆牌(Bust),失去游戏。
  3. 玩家选择停牌后,庄家将亮出自己的牌并进行相应的操作,通常庄家的手牌必须达到17点以上。
  4. 最终比较玩家和庄家的点数,点数更接近21点的一方获胜。

2. 环境准备

2.1 安装Python

确保您的计算机上安装了Python。您可以从Python官方网站下载并安装最新版本。

2.2 创建项目文件

创建一个新的文件夹用于存放项目文件,命名为TwentyOne。在该文件夹内创建一个Python文件,命名为twenty_one.py

3. 游戏设计

在开始编写游戏之前,我们需要明确游戏的基本架构。我们将分成以下几个部分:

  • 牌的表示
  • 游戏逻辑
  • 玩家和庄家的操作
  • 显示结果

3.1 牌的表示

我们可以使用一个列表来表示牌组,每张牌可以用一个元组表示(点数、花色)。

3.2 游戏逻辑

我们需要实现游戏的基本逻辑,包括初始化游戏、处理玩家输入、庄家的操作以及判断胜负。

3.3 玩家和庄家的操作

玩家可以选择要牌或停牌,而庄家在特定条件下自动进行操作。

3.4 显示结果

在每局游戏结束后,显示玩家和庄家的点数以及游戏结果。

4. 代码实现

下面是实现上述设计的代码。

4.1 牌的表示

首先,我们实现牌组的表示和洗牌功能:

import random

def create_deck():
    suits = ['♥', '♦', '♣', '♠']
    ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
    deck = [(rank, suit) for suit in suits for rank in ranks]
    random.shuffle(deck)
    return deck

4.2 计算点数

接下来,我们实现计算手牌点数的功能:

def calculate_hand_value(hand):
    value = 0
    aces = 0
    for card in hand:
        rank = card[0]
        if rank in ['J', 'Q', 'K']:
            value += 10
        elif rank == 'A':
            aces += 1
            value += 11  # 默认将A计为11
        else:
            value += int(rank)

    # 处理A的情况,如果总点数超过21,A计为1
    while value > 21 and aces:
        value -= 10
        aces -= 1
    
    return value

4.3 玩家操作

接下来,我们实现玩家的操作:

def player_turn(deck):
    hand = [deck.pop(), deck.pop()]  # 玩家起始两张牌
    while True:
        print(f"您的手牌: {hand}, 当前点数: {calculate_hand_value(hand)}")
        action = input("请选择:1. 要牌 2. 停牌 ").strip()
        if action == '1':
            hand.append(deck.pop())
            if calculate_hand_value(hand) > 21:
                print(f"您的手牌: {hand}, 当前点数: {calculate_hand_value(hand)}")
                print("您爆牌了!")
                return hand
        elif action == '2':
            break
        else:
            print("无效输入,请选择 1 或 2。")
    return hand

4.4 庄家操作

庄家的操作逻辑如下:

def dealer_turn(deck):
    hand = [deck.pop(), deck.pop()]  # 庄家起始两张牌
    while calculate_hand_value(hand) < 17:  # 庄家点数小于17时要牌
        hand.append(deck.pop())
    return hand

4.5 显示结果

在每局游戏结束后,我们需要显示结果:

def show_results(player_hand, dealer_hand):
    player_value = calculate_hand_value(player_hand)
    dealer_value = calculate_hand_value(dealer_hand)
    
    print(f"您的最终手牌: {player_hand}, 点数: {player_value}")
    print(f"庄家的最终手牌: {dealer_hand}, 点数: {dealer_value}")

    if player_value > 21:
        print("您爆牌,庄家获胜!")
    elif dealer_value > 21 or player_value > dealer_value:
        print("恭喜您,您获胜了!")
    elif player_value < dealer_value:
        print("庄家获胜!")
    else:
        print("平局!")

4.6 主游戏循环

最后,我们实现主游戏循环:

def main():
    while True:
        deck = create_deck()  # 创建并洗牌
        print("欢迎来到20点游戏!")
        
        player_hand = player_turn(deck)
        if calculate_hand_value(player_hand) > 21:
            continue  # 玩家爆牌,重新开始
        
        dealer_hand = dealer_turn(deck)
        
        show_results(player_hand, dealer_hand)

        play_again = input("是否再来一局?(y/n)").strip().lower()
        if play_again != 'y':
            print("感谢您的游戏!")
            break

if __name__ == "__main__":
    main()

5. 完整代码

将上述所有代码整合,以下是完整的twenty_one.py文件代码:

import random

def create_deck():
    suits = ['♥', '♦', '♣', '♠']
    ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
    deck = [(rank, suit) for suit in suits for rank in ranks]
    random.shuffle(deck)
    return deck

def calculate_hand_value(hand):
    value = 0
    aces = 0
    for card in hand:
        rank = card[0]
        if rank in ['J', 'Q', 'K']:
            value += 10
        elif rank == 'A':
            aces += 1
            value += 11  # 默认将A计为11
        else:
            value += int(rank)

    while value > 21 and aces:
        value -= 10
        aces -= 1
    
    return value

def player_turn(deck):
    hand = [deck.pop(), deck.pop()]  # 玩家起始两张牌
    while True:
        print(f"您的手牌: {hand}, 当前点数: {calculate_hand_value(hand)}")
        action = input("请选择:1. 要牌 2. 停牌 ").strip()
        if action == '1':
            hand.append(deck.pop())
            if calculate_hand_value(hand) > 21:
                print(f"您的手牌: {hand}, 当前点数: {calculate_hand_value(hand)}")
                print("您爆牌了!")
                return hand
        elif action == '2':
            break
        else:
            print("无效输入,请选择 1 或 2。")
    return hand

def dealer_turn(deck):
    hand = [deck.pop(), deck.pop()]  # 庄家起始两张牌
    while calculate_hand_value(hand) < 17:  # 庄家点数小于17时要牌
        hand.append(deck.pop())
    return hand

def show_results(player_hand, dealer_hand):
    player_value = calculate_hand_value(player_hand)
    dealer_value = calculate_hand_value(dealer_hand)
    
    print(f"您的最终手牌: {player_hand}, 点数: {player_value}")
    print(f"庄家的最终手牌: {dealer_hand}, 点数: {dealer_value}")

    if player_value > 21:
        print("您爆牌,庄家获胜!")
    elif dealer_value > 21 or player_value > dealer_value
    elif player_value > dealer_value:
        print("恭喜您,您获胜了!")
    elif player_value < dealer_value:
        print("庄家获胜!")
    else:
        print("平局!")

def main():
    print("欢迎来到20点游戏!")
    while True:
        deck = create_deck()  # 创建并洗牌
        
        player_hand = player_turn(deck)
        if calculate_hand_value(player_hand) > 21:
            continue  # 玩家爆牌,重新开始
        
        dealer_hand = dealer_turn(deck)
        
        show_results(player_hand, dealer_hand)

        play_again = input("是否再来一局?(y/n)").strip().lower()
        if play_again != 'y':
            print("感谢您的游戏!")
            break

if __name__ == "__main__":
    main()

6. 测试游戏

完成代码后,您可以通过在命令行中运行以下命令来测试游戏:

python twenty_one.py

根据提示操作,体验游戏的乐趣。

7. 扩展功能

为了让游戏更加丰富和有趣,您可以考虑以下扩展功能:

7.1 增加下注功能

您可以为玩家增加一个下注功能,在每局游戏开始前让玩家决定下注数额。如果玩家获胜,下注数额将翻倍。

代码实现:

main函数中增加下注逻辑:

def main():
    print("欢迎来到20点游戏!")
    while True:
        deck = create_deck()  # 创建并洗牌
        
        bet = int(input("请下注:"))
        player_hand = player_turn(deck)
        if calculate_hand_value(player_hand) > 21:
            print(f"您损失了 {bet} 元。")
            continue  # 玩家爆牌,重新开始
        
        dealer_hand = dealer_turn(deck)
        
        player_value = calculate_hand_value(player_hand)
        dealer_value = calculate_hand_value(dealer_hand)

        show_results(player_hand, dealer_hand)

        if player_value > 21:
            print(f"您损失了 {bet} 元。")
        elif dealer_value > 21 or player_value > dealer_value:
            print(f"恭喜您,您获胜了 {bet * 2} 元!")
        elif player_value < dealer_value:
            print(f"庄家获胜,您损失了 {bet} 元。")
        else:
            print("平局!您的下注将返还。")

        play_again = input("是否再来一局?(y/n)").strip().lower()
        if play_again != 'y':
            print("感谢您的游戏!")
            break

7.2 实现多个玩家

您可以扩展游戏支持多个玩家竞争,增加游戏的趣味性。

代码实现:

main函数中增加多个玩家的处理逻辑:

def player_turn(deck, player_name):
    hand = [deck.pop(), deck.pop()]  # 玩家起始两张牌
    while True:
        print(f"{player_name} 的手牌: {hand}, 当前点数: {calculate_hand_value(hand)}")
        action = input(f"{player_name},请选择:1. 要牌 2. 停牌 ").strip()
        if action == '1':
            hand.append(deck.pop())
            if calculate_hand_value(hand) > 21:
                print(f"{player_name} 的手牌: {hand}, 当前点数: {calculate_hand_value(hand)}")
                print(f"{player_name} 爆牌了!")
                return hand
        elif action == '2':
            break
        else:
            print("无效输入,请选择 1 或 2。")
    return hand

def main():
    print("欢迎来到20点游戏!")
    num_players = int(input("请输入玩家人数:"))
    players = [f"玩家 {i + 1}" for i in range(num_players)]
    
    while True:
        deck = create_deck()  # 创建并洗牌
        
        for player in players:
            player_hand = player_turn(deck, player)
            if calculate_hand_value(player_hand) > 21:
                continue  # 玩家爆牌,进入下一轮
            
        dealer_hand = dealer_turn(deck)
        
        for player in players:
            show_results(player_hand, dealer_hand)

        play_again = input("是否再来一局?(y/n)").strip().lower()
        if play_again != 'y':
            print("感谢您的游戏!")
            break

7.3 增加图形用户界面

为了提高用户体验,您可以使用 tkinter 库创建一个简单的图形用户界面。

代码实现(概述):

使用 tkinter 创建一个窗口,添加按钮和标签来显示玩家和庄家的手牌。

import tkinter as tk
from tkinter import messagebox

class TwentyOneGame:
    def __init__(self, master):
        self.master = master
        self.master.title("20点游戏")
        self.deck = create_deck()
        self.player_hand = []
        self.dealer_hand = []
        
        self.create_widgets()

    def create_widgets(self):
        self.player_label = tk.Label(self.master, text="玩家手牌: ")
        self.player_label.pack()

        self.dealer_label = tk.Label(self.master, text="庄家手牌: ")
        self.dealer_label.pack()

        self.hit_button = tk.Button(self.master, text="要牌", command=self.hit)
        self.hit_button.pack()

        self.stand_button = tk.Button(self.master, text="停牌", command=self.stand)
        self.stand_button.pack()

    def hit(self):
        self.player_hand.append(self.deck.pop())
        self.update_display()
        if calculate_hand_value(self.player_hand) > 21:
            messagebox.showinfo("结果", "您爆牌了!")
            self.reset_game()

    def stand(self):
        self.dealer_hand = dealer_turn(self.deck)
        self.update_display()
        show_results(self.player_hand, self.dealer_hand)
        self.reset_game()

    def update_display(self):
        self.player_label.config(text=f"玩家手牌: {self.player_hand},点数: {calculate_hand_value(self.player_hand)}")
        self.dealer_label.config(text=f"庄家手牌: {self.dealer_hand},点数: {calculate_hand_value(self.dealer_hand)}")

    def reset_game(self):
        self.deck = create_deck()
        self.player_hand = []
        self.dealer_hand = []

if __name__ == "__main__":
    root = tk.Tk()
    game = TwentyOneGame(root)
    root.mainloop()

7.4 记录游戏历史

实现一个记录玩家每局比赛的胜负和下注金额的功能。可以使用文件存储记录。

代码实现:

在游戏结束时,记录结果到文件:

def log_results(player_value, dealer_value, bet):
    with open("game_history.txt", "a") as file:
        result = "平局" if player_value == dealer_value else ("玩家胜利" if player_value > dealer_value else "庄家胜利")
        file.write(f"玩家点数: {player_value}, 庄家点数: {dealer_value}, 下注: {bet}, 结果: {result}\n")

在主逻辑中记录结果:

show_results(player_hand, dealer_hand)
log_results(player_value, dealer_value, bet)

8. 总结

通过本教程,您已经学会了如何使用Python编写20点游戏。我们从基础知识入手,逐步实现了一个命令行版本的20点游戏,并扩展到了支持多个玩家、下注功能、图形界面和游戏记录等。

希望您能在这个项目中获得乐趣,并在学习Python的过程中获得更多的启发!如果您有任何问题或建议,欢迎随时提出。祝您编程愉快!