卡牌抽取游戏

我来为您创建一个使用Python Tkinter的卡牌抽取游戏UI。这个程序会实现您描述的所有功能。

这个程序提供了以下功能:

  1. 牌堆管理

    • 10种不同的牌,每种4张,总共40张牌

    • 实时显示牌堆中每种牌的剩余数量

    • 用进度条形式直观显示每种牌的数量

  2. 抽取功能

    • 每次显示3张随机抽取的牌

    • 可以单独抽取任意一张牌

    • 可以一次性抽取全部3张牌

    • 抽取后牌堆相应减少

  3. 刷新功能

    • 点击"刷新"按钮将当前未抽取的牌放回牌堆

    • 重新洗牌并抽取3张新牌

    • 已抽取的牌不会放回牌堆

  4. 显示区域

    • 当前抽取的3张牌(带抽取按钮)

    • 用户已抽取的牌(按类型统计)

    • 当前牌堆状态

    • 游戏统计信息

  5. 游戏控制

    • 重置游戏按钮,可重新开始游戏

    • 自动检测游戏结束条件(牌堆不足3张)

    • 彩色显示不同类型的牌

运行这个程序后,您会看到一个完整的GUI界面,可以按照您的描述进行卡牌抽取游戏。

python 复制代码
import tkinter as tk
from tkinter import ttk, messagebox
import random
from collections import Counter

class CardGame:
    def __init__(self, master, N=10):
        self.master = master
        self.N = N
        self.master.title("卡牌抽取游戏")
        self.master.geometry("1000x700")
        
        # 初始化牌堆,每种牌4张
        self.card_types = list(range(1, N + 1))
        self.initial_counts = {card_type: 4 for card_type in self.card_types}
        self.deck = []
        self.reset_deck()
        
        # 当前显示的3张牌
        self.current_cards = []
        # 用户已抽取的牌
        self.user_drawn_cards = []
        # 游戏状态
        self.game_active = True
        
        # 设置样式
        self.setup_styles()
        # 创建UI
        self.create_widgets()
        # 初始抽取3张牌
        self.draw_initial_cards()
    
    def setup_styles(self):
        """设置样式"""
        style = ttk.Style()
        style.theme_use('clam')
    
    def reset_deck(self):
        """重置牌堆到初始状态"""
        self.deck = []
        for card_type, count in self.initial_counts.items():
            self.deck.extend([card_type] * count)
    
    def shuffle_deck(self):
        """洗牌"""
        random.shuffle(self.deck)
    
    def draw_three_cards(self):
        """从牌堆中抽取3张牌(不放回)"""
        if len(self.deck) < 3:
            messagebox.showwarning("牌堆不足", "牌堆中剩余牌数不足3张,无法继续游戏!")
            self.game_active = False
            return []
        
        drawn_cards = []
        for _ in range(3):
            if self.deck:
                card = self.deck.pop(0)
                drawn_cards.append(card)
        return drawn_cards
    
    def create_widgets(self):
        """创建所有UI组件"""
        # 主框架
        main_frame = ttk.Frame(self.master, padding="20")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 标题
        title_label = ttk.Label(main_frame, text="卡牌抽取游戏", font=("Arial", 20, "bold"))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        # 牌堆状态区域
        deck_frame = ttk.LabelFrame(main_frame, text="当前牌堆状态", padding="10")
        deck_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 20))
        
        self.deck_status_label = ttk.Label(
            deck_frame, 
            text=self.get_deck_status_text(),
            font=("Consolas", 10),
            wraplength=200
        )
        self.deck_status_label.pack()
        
        # 抽取的牌显示区域
        current_cards_frame = ttk.LabelFrame(main_frame, text="当前抽取的3张牌", padding="20")
        current_cards_frame.grid(row=1, column=1, sticky=(tk.W, tk.E, tk.N, tk.S), padx=20)
        
        # 当前3张牌的框架
        self.card_frames = []
        self.card_labels = []
        self.draw_buttons = []
        
        for i in range(3):
            card_frame = ttk.Frame(current_cards_frame)
            card_frame.grid(row=0, column=i, padx=10)
            
            # 牌显示
            card_label = ttk.Label(
                card_frame, 
                text="", 
                font=("Arial", 24, "bold"),
                width=6,
                anchor="center",
                relief="solid",
                padding=10
            )
            card_label.pack(pady=(0, 10))
            self.card_labels.append(card_label)
            
            # 抽取按钮
            draw_button = ttk.Button(
                card_frame, 
                text=f"抽取牌{i+1}",
                command=lambda idx=i: self.draw_single_card(idx)
            )
            draw_button.pack()
            self.draw_buttons.append(draw_button)
            
            self.card_frames.append(card_frame)
        
        # 用户抽取的牌区域
        user_cards_frame = ttk.LabelFrame(main_frame, text="您已抽取的牌", padding="10")
        user_cards_frame.grid(row=1, column=2, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(20, 0))
        
        self.user_cards_text = tk.Text(
            user_cards_frame, 
            height=15, 
            width=20,
            font=("Consolas", 10)
        )
        self.user_cards_text.pack()
        self.user_cards_text.config(state=tk.DISABLED)
        
        # 控制按钮区域
        control_frame = ttk.Frame(main_frame)
        control_frame.grid(row=2, column=0, columnspan=3, pady=20)
        
        # 刷新按钮
        self.refresh_button = ttk.Button(
            control_frame, 
            text="刷新牌堆并重新抽取",
            command=self.refresh_and_redraw,
            width=30
        )
        self.refresh_button.pack(side=tk.LEFT, padx=5)
        
        # 抽取全部按钮
        self.draw_all_button = ttk.Button(
            control_frame, 
            text="抽取全部3张牌",
            command=self.draw_all_cards,
            width=20
        )
        self.draw_all_button.pack(side=tk.LEFT, padx=5)
        
        # 重置游戏按钮
        self.reset_button = ttk.Button(
            control_frame, 
            text="重置游戏",
            command=self.reset_game,
            width=15
        )
        self.reset_button.pack(side=tk.LEFT, padx=5)
        
        # 统计信息
        stats_frame = ttk.LabelFrame(main_frame, text="游戏统计", padding="10")
        stats_frame.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(10, 0))
        
        self.stats_label = ttk.Label(
            stats_frame,
            text=self.get_stats_text(),
            font=("Consolas", 10)
        )
        self.stats_label.pack()
        
        # 配置网格权重
        self.master.columnconfigure(0, weight=1)
        self.master.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        
    def get_deck_status_text(self):
        """获取牌堆状态文本"""
        if not self.deck:
            return "牌堆已空!"
        
        card_counter = Counter(self.deck)
        status_lines = []
        for card_type in sorted(card_counter.keys()):
            count = card_counter[card_type]
            bar = "■" * count
            status_lines.append(f"牌{card_type}: {count}张 {bar}")
        
        status_text = f"牌堆总牌数: {len(self.deck)}\n"
        status_text += "\n".join(status_lines)
        return status_text
    
    def get_stats_text(self):
        """获取统计信息文本"""
        card_counter = Counter(self.user_drawn_cards)
        stats_lines = []
        for card_type in sorted(card_counter.keys()):
            count = card_counter[card_type]
            stats_lines.append(f"牌{card_type}: 抽取了{count}次")
        
        stats_text = f"您总共抽取了 {len(self.user_drawn_cards)} 张牌\n"
        if stats_lines:
            stats_text += "\n".join(stats_lines)
        return stats_text
    
    def draw_initial_cards(self):
        """初始抽取3张牌"""
        self.current_cards = self.draw_three_cards()
        self.update_card_display()
        self.update_buttons_state()
    
    def update_card_display(self):
        """更新卡牌显示"""
        for i, label in enumerate(self.card_labels):
            if i < len(self.current_cards):
                label.config(text=f"牌{self.current_cards[i]}")
                # 为不同牌设置不同颜色
                colors = ["lightblue", "lightgreen", "lightcoral", "lightyellow", "lightpink",
                         "lightcyan", "lightgray", "lightgoldenrodyellow", "lightsalmon", "lightseagreen"]
                color_idx = (self.current_cards[i] - 1) % len(colors)
                label.config(background=colors[color_idx])
            else:
                label.config(text="", background="SystemButtonFace")
    
    def update_buttons_state(self):
        """更新按钮状态"""
        for i, button in enumerate(self.draw_buttons):
            if i < len(self.current_cards) and self.game_active:
                button.config(state=tk.NORMAL)
            else:
                button.config(state=tk.DISABLED)
    
    def draw_single_card(self, card_index):
        """抽取单张牌"""
        if not self.game_active or card_index >= len(self.current_cards):
            return
        
        # 抽取选中的牌
        drawn_card = self.current_cards.pop(card_index)
        self.user_drawn_cards.append(drawn_card)
        
        # 更新显示
        self.update_card_display()
        self.update_buttons_state()
        self.update_deck_status()
        self.update_user_cards_display()
        self.update_stats()
        
        # 检查是否还有牌可抽
        if not self.current_cards:
            self.check_game_status()
    
    def draw_all_cards(self):
        """抽取全部3张牌"""
        if not self.game_active or not self.current_cards:
            return
        
        # 抽取所有剩余牌
        while self.current_cards:
            drawn_card = self.current_cards.pop(0)
            self.user_drawn_cards.append(drawn_card)
        
        # 更新显示
        self.update_card_display()
        self.update_buttons_state()
        self.update_deck_status()
        self.update_user_cards_display()
        self.update_stats()
        
        # 检查游戏状态
        self.check_game_status()
    
    def refresh_and_redraw(self):
        """刷新牌堆并重新抽取"""
        if not self.game_active:
            messagebox.showinfo("游戏结束", "游戏已结束,请点击重置游戏重新开始!")
            return
        
        # 将当前剩余的牌放回牌堆
        for card in self.current_cards:
            self.deck.append(card)
        
        # 洗牌
        self.shuffle_deck()
        
        # 重新抽取3张牌
        self.current_cards = self.draw_three_cards()
        
        # 更新显示
        self.update_card_display()
        self.update_buttons_state()
        self.update_deck_status()
        self.update_stats()
        
        # 检查游戏状态
        self.check_game_status()
    
    def reset_game(self):
        """重置游戏"""
        # 重置所有状态
        self.reset_deck()
        self.shuffle_deck()
        self.current_cards = []
        self.user_drawn_cards = []
        self.game_active = True
        
        # 初始抽取
        self.draw_initial_cards()
        
        # 更新显示
        self.update_deck_status()
        self.update_user_cards_display()
        self.update_stats()
    
    def update_deck_status(self):
        """更新牌堆状态显示"""
        self.deck_status_label.config(text=self.get_deck_status_text())
    
    def update_user_cards_display(self):
        """更新用户抽取的牌显示"""
        self.user_cards_text.config(state=tk.NORMAL)
        self.user_cards_text.delete(1.0, tk.END)
        
        if not self.user_drawn_cards:
            self.user_cards_text.insert(tk.END, "尚未抽取任何牌")
        else:
            card_counter = Counter(self.user_drawn_cards)
            for card_type in sorted(card_counter.keys()):
                count = card_counter[card_type]
                self.user_cards_text.insert(tk.END, f"牌{card_type}: {count}张\n")
        
        self.user_cards_text.config(state=tk.DISABLED)
    
    def update_stats(self):
        """更新统计信息"""
        self.stats_label.config(text=self.get_stats_text())
    
    def check_game_status(self):
        """检查游戏状态"""
        if len(self.deck) < 3 and not self.current_cards:
            messagebox.showinfo("游戏结束", "牌堆中牌数不足3张,游戏结束!")
            self.game_active = False
            self.update_buttons_state()

def main():
    root = tk.Tk()
    app = CardGame(root, N=10)
    root.mainloop()

if __name__ == "__main__":
    main()
相关推荐
阿里嘎多学长10 小时前
2026-05-28 GitHub 热点项目精选
开发语言·程序员·github·代码托管
小白学大数据10 小时前
电商关键词挖掘:Java 爬虫抓取 1688 推荐搜索词
java·开发语言·爬虫·python
风兮雨露11 小时前
Python 3 从入门到精通教程 第一期
开发语言·python
A charmer11 小时前
零基础学OC:变量与基本数据类型(C++开发者速通版)[特殊字符]
开发语言·c++·objective-c
bjzhang7511 小时前
python开发环境安装及30个常用第三方库
开发语言·python
财经资讯数据_灵砚智能11 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年5月28日
大数据·人工智能·python·信息可视化·自然语言处理·ai编程·灵砚智能
索西引擎11 小时前
【LangChain 1.0】环境搭建指南:从 conda 到 uv 的现代化 Python 工程实践
python·langchain·conda
狼与自由11 小时前
jdk版本升级
java·开发语言