Python3.8.10每日一练(斗地主)

import tkinter as tk
from tkinter import messagebox, font
import random
import os


class Card:
    def __init__(self, suit, rank, value):
        self.suit = suit
        self.rank = rank
        self.value = value
        self.image_path = f"{suit}_{rank}.png"  # 实际使用时需要准备对应的图片

    def __str__(self):
        return f"{self.suit}{self.rank}"


class Player:
    def __init__(self, name):
        self.name = name
        self.cards = []
        self.is_landlord = False

    def sort_cards(self):
        self.cards.sort(key=lambda card: card.value)

    def play_cards(self, selected_indices):
        selected_cards = [self.cards[i] for i in sorted(selected_indices, reverse=True)]
        for i in sorted(selected_indices, reverse=True):
            del self.cards[i]
        return selected_cards


class LandlordsGame:
    def __init__(self):
        self.players = [Player("玩家"), Player("电脑1"), Player("电脑2")]
        self.deck = []
        self.bottom_cards = []
        self.current_player_index = 0
        self.last_played_cards = []
        self.last_player_index = -1
        self.landlord_index = -1
        self.setup_deck()

    def setup_deck(self):
        suits = ["♠", "♥", "♣", "♦"]
        ranks = ["3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"]
        values = list(range(3, 16))  # 3-15

        # 普通牌
        for suit in suits:
            for i, rank in enumerate(ranks):
                self.deck.append(Card(suit, rank, values[i]))

        # 大小王
        self.deck.append(Card("", "小王", 16))
        self.deck.append(Card("", "大王", 17))

    def shuffle_deck(self):
        random.shuffle(self.deck)

    def deal_cards(self):
        self.shuffle_deck()
        self.bottom_cards = self.deck[-3:]
        for i in range(17):
            for player in self.players:
                player.cards.append(self.deck.pop(0))
        for player in self.players:
            player.sort_cards()

    def select_landlord(self, player_index):
        self.landlord_index = player_index
        self.players[player_index].is_landlord = True
        self.players[player_index].cards.extend(self.bottom_cards)
        self.players[player_index].sort_cards()
        self.current_player_index = player_index
        self.last_player_index = player_index

    def is_valid_play(self, played_cards):
        # 简化的牌型判断,实际需要完整实现各种牌型规则
        if not played_cards:
            return self.last_played_cards or self.current_player_index == self.last_player_index
        if not self.last_played_cards:
            return True  # 第一个出牌,只要有牌就行
        # 这里应该实现完整的牌型比较逻辑
        return True

    def play_round(self, player_index, played_cards):
        if not self.is_valid_play(played_cards):
            return False

        self.last_played_cards = played_cards
        self.last_player_index = player_index

        if not self.players[player_index].cards:
            return True  # 游戏结束

        # 轮到下一个玩家
        self.current_player_index = (self.current_player_index + 1) % 3
        # 如果当前玩家选择不出
        if not played_cards and self.current_player_index == self.last_player_index:
            self.last_played_cards = []  # 重新开始一轮

        return False


class LandlordsGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("斗地主")
        self.root.geometry("1200x700")
        self.root.configure(bg="#008000")  # 绿色背景模拟牌桌

        self.game = LandlordsGame()
        self.selected_indices = set()
        self.buttons_frame = None
        self.player_hand_frame = None
        self.computer1_frame = None
        self.computer2_frame = None
        self.table_frame = None
        self.bottom_cards_frame = None
        self.card_font = font.Font(family="SimHei", size=14)
        self.title_font = font.Font(family="SimHei", size=24, weight="bold")

        self.setup_ui()

    def setup_ui(self):
        # 标题
        title_label = tk.Label(self.root, text="斗地主", bg="#008000", fg="white", font=self.title_font)
        title_label.pack(pady=20)

        # 主游戏区域
        main_frame = tk.Frame(self.root, bg="#008000")
        main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        # 电脑2区域(顶部)
        self.computer2_frame = tk.Frame(main_frame, bg="#008000")
        self.computer2_frame.pack(fill=tk.X, pady=10)
        self.computer2_label = tk.Label(self.computer2_frame, text="电脑2", bg="#008000", fg="white",
                                        font=self.card_font)
        self.computer2_label.pack()
        self.computer2_cards_frame = tk.Frame(self.computer2_frame, bg="#008000")
        self.computer2_cards_frame.pack(pady=5)

        # 桌面区域(中间)
        self.table_frame = tk.Frame(main_frame, bg="#008000")
        self.table_frame.pack(fill=tk.BOTH, expand=True, pady=20)

        # 底牌区域
        self.bottom_cards_frame = tk.Frame(self.table_frame, bg="#008000")
        self.bottom_cards_frame.pack(side=tk.TOP, pady=10)
        self.bottom_cards_label = tk.Label(self.bottom_cards_frame, text="底牌", bg="#008000", fg="white",
                                           font=self.card_font)
        self.bottom_cards_label.pack()
        self.bottom_cards_display = tk.Frame(self.bottom_cards_frame, bg="#008000")
        self.bottom_cards_display.pack(pady=5)

        # 已出牌区域
        self.played_cards_frame = tk.Frame(self.table_frame, bg="#008000")
        self.played_cards_frame.pack(side=tk.TOP, pady=20)
        self.played_cards_label = tk.Label(self.played_cards_frame, text="已出牌", bg="#008000", fg="white",
                                           font=self.card_font)
        self.played_cards_label.pack()
        self.played_cards_display = tk.Frame(self.played_cards_frame, bg="#008000")
        self.played_cards_display.pack(pady=5)

        # 玩家区域(底部)
        self.player_hand_frame = tk.Frame(main_frame, bg="#008000")
        self.player_hand_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=10)
        self.player_label = tk.Label(self.player_hand_frame, text="玩家", bg="#008000", fg="white", font=self.card_font)
        self.player_label.pack()
        self.player_cards_frame = tk.Frame(self.player_hand_frame, bg="#008000")
        self.player_cards_frame.pack(pady=5)

        # 电脑1区域(右侧)
        self.computer1_frame = tk.Frame(main_frame, bg="#008000")
        self.computer1_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=10)
        self.computer1_label = tk.Label(self.computer1_frame, text="电脑1", bg="#008000", fg="white",
                                        font=self.card_font)
        self.computer1_label.pack()
        self.computer1_cards_frame = tk.Frame(self.computer1_frame, bg="#008000")
        self.computer1_cards_frame.pack(pady=5)

        # 按钮区域
        self.buttons_frame = tk.Frame(self.root, bg="#008000")
        self.buttons_frame.pack(pady=20)

        # 开始游戏按钮
        self.start_button = tk.Button(self.buttons_frame, text="开始游戏", command=self.start_game, font=self.card_font)
        self.start_button.pack(side=tk.LEFT, padx=10)

        # 出牌按钮
        self.play_button = tk.Button(self.buttons_frame, text="出牌", command=self.play_selected_cards,
                                     font=self.card_font, state=tk.DISABLED)
        self.play_button.pack(side=tk.LEFT, padx=10)

        # 不出按钮
        self.pass_button = tk.Button(self.buttons_frame, text="不出", command=self.pass_turn, font=self.card_font,
                                     state=tk.DISABLED)
        self.pass_button.pack(side=tk.LEFT, padx=10)

        # 叫地主按钮
        self.landlord_button = tk.Button(self.buttons_frame, text="叫地主", command=lambda: self.select_landlord(True),
                                         font=self.card_font, state=tk.DISABLED)
        self.landlord_button.pack(side=tk.LEFT, padx=10)

        # 不叫按钮
        self.not_landlord_button = tk.Button(self.buttons_frame, text="不叫",
                                             command=lambda: self.select_landlord(False), font=self.card_font,
                                             state=tk.DISABLED)
        self.not_landlord_button.pack(side=tk.LEFT, padx=10)

    def start_game(self):
        self.game = LandlordsGame()
        self.game.deal_cards()
        self.selected_indices = set()
        self.update_display()

        # 显示叫地主按钮
        self.start_button.config(state=tk.DISABLED)
        self.landlord_button.config(state=tk.NORMAL)
        self.not_landlord_button.config(state=tk.NORMAL)
        self.play_button.config(state=tk.DISABLED)
        self.pass_button.config(state=tk.DISABLED)

        # 显示底牌背面
        self.update_bottom_cards_display(hidden=True)

        # 提示玩家叫地主
        messagebox.showinfo("游戏开始", "游戏已开始,请选择是否叫地主")

    def update_display(self):
        # 清空所有显示区域
        for widget in self.player_cards_frame.winfo_children():
            widget.destroy()
        for widget in self.computer1_cards_frame.winfo_children():
            widget.destroy()
        for widget in self.computer2_cards_frame.winfo_children():
            widget.destroy()
        for widget in self.played_cards_display.winfo_children():
            widget.destroy()

        # 显示玩家手牌
        for i, card in enumerate(self.game.players[0].cards):
            card_label = tk.Label(self.player_cards_frame, text=f"{card.suit}{card.rank}",
                                  bg="white", fg="black", relief=tk.RAISED,
                                  bd=2, padx=10, pady=15, font=self.card_font)
            card_label.grid(row=0, column=i, padx=2)
            card_label.bind("<Button-1>", lambda event, idx=i: self.toggle_card_selection(idx))

        # 显示电脑1手牌(背面)
        for i in range(len(self.game.players[1].cards)):
            card_back = tk.Label(self.computer1_cards_frame, text="背面",
                                 bg="red", fg="white", relief=tk.RAISED,
                                 bd=2, padx=5, pady=10, font=self.card_font)
            card_back.pack(pady=1)

        # 显示电脑2手牌(背面)
        for i in range(len(self.game.players[2].cards)):
            card_back = tk.Label(self.computer2_cards_frame, text="背面",
                                 bg="red", fg="white", relief=tk.RAISED,
                                 bd=2, padx=10, pady=5, font=self.card_font)
            card_back.grid(row=0, column=i, padx=1)

        # 显示已出牌
        for i, card in enumerate(self.game.last_played_cards):
            card_label = tk.Label(self.played_cards_display, text=f"{card.suit}{card.rank}",
                                  bg="white", fg="black", relief=tk.RAISED,
                                  bd=2, padx=10, pady=15, font=self.card_font)
            card_label.grid(row=0, column=i, padx=2)

        # 更新玩家标签显示当前回合
        if self.game.landlord_index != -1:
            player_labels = [self.player_label, self.computer1_label, self.computer2_label]
            for i, label in enumerate(player_labels):
                text = self.game.players[i].name
                if self.game.players[i].is_landlord:
                    text += "(地主)"
                if i == self.game.current_player_index:
                    text += " [当前回合]"
                label.config(text=text)

    def update_bottom_cards_display(self, hidden=False):
        for widget in self.bottom_cards_display.winfo_children():
            widget.destroy()

        if hidden:
            for i in range(3):
                card_back = tk.Label(self.bottom_cards_display, text="背面",
                                     bg="red", fg="white", relief=tk.RAISED,
                                     bd=2, padx=10, pady=15, font=self.card_font)
                card_back.grid(row=0, column=i, padx=2)
        else:
            for i, card in enumerate(self.game.bottom_cards):
                card_label = tk.Label(self.bottom_cards_display, text=f"{card.suit}{card.rank}",
                                      bg="white", fg="black", relief=tk.RAISED,
                                      bd=2, padx=10, pady=15, font=self.card_font)
                card_label.grid(row=0, column=i, padx=2)

    def toggle_card_selection(self, index):
        if self.game.current_player_index != 0:
            return  # 不是玩家回合

        if index in self.selected_indices:
            self.selected_indices.remove(index)
            # 更新卡片外观
            for i, widget in enumerate(self.player_cards_frame.winfo_children()):
                if i == index:
                    widget.config(bg="white", fg="black")
        else:
            self.selected_indices.add(index)
            # 更新卡片外观
            for i, widget in enumerate(self.player_cards_frame.winfo_children()):
                if i == index:
                    widget.config(bg="yellow", fg="black")

    def select_landlord(self, is_landlord):
        if is_landlord:
            self.game.select_landlord(0)
            self.update_bottom_cards_display(hidden=False)
            messagebox.showinfo("地主确定", "你成为了地主!")
        else:
            # 简化处理,电脑随机选择一个当地主
            landlord_index = random.choice([1, 2])
            self.game.select_landlord(landlord_index)
            self.update_bottom_cards_display(hidden=False)
            messagebox.showinfo("地主确定", f"{self.game.players[landlord_index].name}成为了地主!")

        # 更新显示
        self.update_display()

        # 隐藏叫地主按钮,显示游戏按钮
        self.landlord_button.config(state=tk.DISABLED)
        self.not_landlord_button.config(state=tk.DISABLED)

        # 如果轮到玩家
        if self.game.current_player_index == 0:
            self.play_button.config(state=tk.NORMAL)
            self.pass_button.config(state=tk.NORMAL)
        else:
            self.play_button.config(state=tk.DISABLED)
            self.pass_button.config(state=tk.DISABLED)
            # 电脑出牌
            self.root.after(1000, self.computer_play)

    def play_selected_cards(self):
        if not self.selected_indices:
            messagebox.showwarning("提示", "请选择要出的牌!")
            return

        selected_cards = [self.game.players[0].cards[i] for i in self.selected_indices]
        if not self.game.is_valid_play(selected_cards):
            messagebox.showwarning("提示", "出牌不符合规则!")
            return

        # 出牌
        game_over = self.game.play_round(0, selected_cards)
        self.selected_indices = set()
        self.update_display()

        if game_over:
            messagebox.showinfo("游戏结束", "恭喜,你赢了!")
            self.start_button.config(state=tk.NORMAL)
            self.play_button.config(state=tk.DISABLED)
            self.pass_button.config(state=tk.DISABLED)
            return

        # 轮到电脑
        self.play_button.config(state=tk.DISABLED)
        self.pass_button.config(state=tk.DISABLED)
        self.root.after(1000, self.computer_play)

    def pass_turn(self):
        game_over = self.game.play_round(0, [])  # 不出牌
        self.selected_indices = set()
        self.update_display()

        if game_over:
            messagebox.showinfo("游戏结束", f"{self.game.players[self.game.last_player_index].name}赢了!")
            self.start_button.config(state=tk.NORMAL)
            self.play_button.config(state=tk.DISABLED)
            self.pass_button.config(state=tk.DISABLED)
            return

        # 轮到电脑
        self.play_button.config(state=tk.DISABLED)
        self.pass_button.config(state=tk.DISABLED)
        self.root.after(1000, self.computer_play)

    def computer_play(self):
        current_player = self.game.players[self.game.current_player_index]

        # 简单AI:随机出牌或不出
        if self.game.last_player_index == self.game.current_player_index or random.random() > 0.3:
            # 出牌
            if self.game.last_played_cards:
                # 跟牌逻辑,简化处理
                played_cards = [current_player.cards[0]]  # 只出一张最小的牌
            else:
                # 先手出牌,随机出1-5张牌
                num_cards = random.randint(1, min(5, len(current_player.cards)))
                played_cards = current_player.cards[:num_cards]

            # 从手牌中移除已出的牌
            for card in played_cards:
                current_player.cards.remove(card)

            self.game.last_played_cards = played_cards
            self.game.last_player_index = self.game.current_player_index

            messagebox.showinfo("出牌", f"{current_player.name}出了{len(played_cards)}张牌")
        else:
            # 不出
            self.game.last_played_cards = []
            messagebox.showinfo("出牌", f"{current_player.name}选择不出")

        # 检查游戏是否结束
        if not current_player.cards:
            self.update_display()
            messagebox.showinfo("游戏结束", f"{current_player.name}赢了!")
            self.start_button.config(state=tk.NORMAL)
            return

        # 轮到下一个玩家
        self.game.current_player_index = (self.game.current_player_index + 1) % 3
        self.update_display()

        # 如果轮到玩家
        if self.game.current_player_index == 0:
            self.play_button.config(state=tk.NORMAL)
            self.pass_button.config(state=tk.NORMAL)
        else:
            # 继续电脑出牌
            self.root.after(1000, self.computer_play)


if __name__ == "__main__":
    root = tk.Tk()
    # 确保中文显示正常
    font.families()  # 加载字体
    app = LandlordsGUI(root)
    root.mainloop()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值