前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >ChatGPT与我们玩游戏_排雷

ChatGPT与我们玩游戏_排雷

作者头像
顾翔
发布2025-02-05 17:22:53
发布2025-02-05 17:22:53
6200
代码可运行
举报
文章被收录于专栏:啄木鸟软件测试
运行总次数:0
代码可运行

询问

以图形方式给出早期Windows挖地雷的python代码

回答

以下是一个简单的使用 Python 和 Tkinter 库实现的经典早期 Windows 挖地雷游戏(Minesweeper)的图形化版本。这个程序允许玩家点击格子来探索地雷,标记可能的地雷位置,并判断游戏胜负。

Windows 风格的挖地雷游戏(Python实现)

代码语言:javascript
代码运行次数:0
复制
import tkinter as tk
import random
import time
           
class Minesweeper:
    def __init__(self, master, width=10, height=10, num_mines=20):
        self.master = master
        self.master.title("挖地雷")
        self.width = width  # 网格宽度
        self.height = height  # 网格高度
        self.num_mines = num_mines  # 地雷数量
        self.buttons = []
        self.mines = set()  # 存储地雷的坐标
        self.revealed = set()  # 存储已打开的格子
        self.flags = set()  # 存储标记的格子    
        self.game_over = False
           
        # 创建画布和按钮
        self.canvas = tk.Canvas(self.master, width=width*30, height=height*30)
        self.canvas.pack()
        self.create_grid()
        self.place_mines()
           
    def create_grid(self):
        """创建按钮网格"""
        for row in range(self.height):
            button_row = []
            for col in range(self.width):
                button = tk.Button(self.master, text='', width=3, height=1, command=lambda r=row, c=col: self.reveal(r, c))
                button.grid(row=row, column=col)
                button_row.append(button)
            self.buttons.append(button_row)
           
    def place_mines(self):
        """随机放置地雷"""    
        while len(self.mines) < self.num_mines:
            mine = (random.randint(0, self.height-1), random.randint(0, self.width-1))
            self.mines.add(mine)
           
    def reveal(self, row, col):
        """揭示格子内容"""
        if self.game_over or (row, col) in self.revealed or (row, col) in self.flags:
            return
           
        self.revealed.add((row, col))
        if (row, col) in self.mines:
            self.buttons[row][col].config(text="💣", bg="red")
            self.game_over = True
            self.show_game_over("游戏失败!")
            return
        else:
            # 计算相邻地雷的数量
            adjacent_mines = self.count_adjacent_mines(row, col)
            if adjacent_mines > 0:
                self.buttons[row][col].config(text=str(adjacent_mines), relief=tk.SUNKEN)    
            else:
                self.buttons[row][col].config(relief=tk.SUNKEN)
                # 如果没有地雷,递归揭示相邻格子
                for r in range(max(0, row-1), min(self.height, row+2)):
                    for c in range(max(0, col-1), min(self.width, col+2)):
                        if (r, c) != (row, col) and (r, c) not in self.revealed:
                            self.reveal(r, c)
           
        # 检查游戏胜利条件
        if len(self.revealed) == self.width * self.height - self.num_mines:
            self.game_over = True
            self.show_game_over("游戏胜利!")
           
    def count_adjacent_mines(self, row, col):
        """计算相邻格子的地雷数量"""
        adjacent_mines = 0
        for r in range(max(0, row-1), min(self.height, row+2)):
            for c in range(max(0, col-1), min(self.width, col+2)):
                if (r, c) in self.mines:
                    adjacent_mines += 1
        return adjacent_mines
               
    def show_game_over(self, message):
        """显示游戏结束的消息"""
        for r in range(self.height):
            for c in range(self.width):
                if (r, c) in self.mines:
                    self.buttons[r][c].config(text="💣", bg="red")
                else:
                    self.buttons[r][c].config(state=tk.DISABLED)
        self.canvas.create_text(self.width*15, self.height*15, text=message, font=("Arial", 20), fill="black")
           
if __name__ == "__main__":
    root = tk.Tk()
    game = Minesweeper(root, width=10, height=10, num_mines=20)
    root.mainloop()

代码功能和说明:

游戏初始化:

游戏包含一个 10x10 的网格,默认情况下有 20 个地雷。

使用 Tkinter 创建图形界面,每个格子用一个按钮表示。

创建按钮网格并随机放置地雷。

按钮点击和地雷揭示: 玩家点击按钮后会触发 reveal 函数,如果点击的是地雷,游戏结束;否则,按钮显示周围地雷的数量。如果周围没有地雷,会递归揭示周围的按钮。

如果玩家揭示了所有非地雷格子,游戏胜利。

计算周围的地雷数量:

使用 count_adjacent_mines 函数来计算某个格子周围的地雷数量。如果该格子周围没有地雷,则继续递归揭示相邻的格子。

游戏胜负判断:

如果玩家点击到地雷,显示“游戏失败”。

如果玩家揭示了所有非地雷格子,显示“游戏胜利”。

地雷显示:游戏结束时,所有地雷会显示在对应的按钮上,玩家无法再点击其他格子。

运行游戏:

将代码复制到 Python 环境中并运行,确保已安装 tkinter 库。

游戏会弹出窗口,玩家可以点击格子来探索,避免点击到地雷。

游戏会根据玩家的表现显示“游戏胜利”或“游戏失败”。

扩展功能:

标记功能:玩家可以右键点击格子标记疑似地雷的位置。

难度设置:根据玩家选择的难度改变网格的大小和地雷的数量。

计时功能:为游戏添加一个计时器,记录玩家完成游戏的时间。

如果您有其他问题或想进一步扩展这个游戏,随时告诉我!

运行代码,失败

代码语言:javascript
代码运行次数:0
复制
Traceback (most recent call last):
File "C:\Users\xiang\Desktop\Minesweeper.py", line 90, in
game = Minesweeper(root, width=10, height=10, num_mines=20)
File "C:\Users\xiang\Desktop\Minesweeper.py", line 21, in init
self.create_grid()
File "C:\Users\xiang\Desktop\Minesweeper.py", line 30, in create_grid
button.grid(row=row, column=col)
File "C:\Users\xiang\AppData\Local\Programs\Python\Python312\Lib\tkinter_init_.py", line 2569, in grid_configure
self.tk.call(
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack这个错误发生是因为在Tkinter中,你不能同时使用pack和grid布局管理器。你要么使用pack()来管理控件的位置,要么使用grid()来管理。

在你的代码中,self.canvas.pack()使用了pack(),而self.buttons[row][col].grid()则使用了grid()。这就导致了冲突,因为一个窗口不能同时使用两种布局管理器。

代码语言:javascript
代码运行次数:0
复制
import tkinter as tk
from tkinter import messagebox
import random
               
class Minesweeper:
    def __init__(self, master, size=10, mines=10):
        self.master = master
        self.size = size
        self.mines = mines
        self.board = [[0] * size for _ in range(size)]
        self.buttons = [[None] * size for _ in range(size)]
        self.revealed = [[False] * size for _ in range(size)]
        self.flags = [[False] * size for _ in range(size)]
        self.game_over = False
           
        self.create_widgets()
        self.place_mines()
        self.calculate_numbers()
           
    def create_widgets(self):
        for row in range(self.size):
            for col in range(self.size):
                button = tk.Button(self.master, width=2, height=1,
                                   command=lambda r=row, c=col: self.reveal(r, c))
                button.bind('', lambda e, r=row, c=col: self.toggle_flag(r, c))    
                button.grid(row=row, column=col)
                self.buttons[row][col] = button
           
    def place_mines(self):
        count = 0
        while count < self.mines:
            row = random.randint(0, self.size - 1)
            col = random.randint(0, self.size - 1)
            if self.board[row][col] != 'M':
                self.board[row][col] = 'M'
                count += 1
           
    def calculate_numbers(self):
        for row in range(self.size):
            for col in range(self.size):
                if self.board[row][col] == 'M':
                    continue
                mines_count = 0
                for dr in [-1, 0, 1]:
                    for dc in [-1, 0, 1]:
                        if 0 <= row + dr < self.size and 0 <= col + dc < self.size:    
                            if self.board[row + dr][col + dc] == 'M':
                                mines_count += 1
                self.board[row][col] = mines_count
           
    def reveal(self, row, col):
        if self.game_over or self.flags[row][col] or self.revealed[row][col]:
            return
           
        self.revealed[row][col] = True
        if self.board[row][col] == 'M':
            self.buttons[row][col].config(text='M', bg='red')
            self.game_over = True
            messagebox.showinfo("游戏结束", "你踩到地雷了!")
            return
           
        self.buttons[row][col].config(text=str(self.board[row][col]), relief=tk.SUNKEN)
        if self.board[row][col] == 0:
            for dr in [-1, 0, 1]:
                for dc in [-1, 0, 1]:
                    if 0 <= row + dr < self.size and 0 <= col + dc < self.size:
                        if not self.revealed[row + dr][col + dc]:    
                            self.reveal(row + dr, col + dc)
           
        if self.check_win():
            self.game_over = True
            messagebox.showinfo("胜利", "恭喜,你赢了!")
           
    def toggle_flag(self, row, col):
        if self.game_over or self.revealed[row][col]:
            return
           
        if self.flags[row][col]:
            self.buttons[row][col].config(text='', bg='SystemButtonFace')
            self.flags[row][col] = False
        else:
            self.buttons[row][col].config(text='F', bg='yellow')
            self.flags[row][col] = True
           
    def check_win(self):
        for row in range(self.size):
            for col in range(self.size):
                if self.board[row][col] != 'M' and not self.revealed[row][col]:
                    return False    
        return True
           
if __name__ == "__main__":
    root = tk.Tk()
    root.title("扫雷游戏")
    game = Minesweeper(root, size=10, mines=10)
    root.mainloop()  

解决方案:

你有两种方法可以解决这个问题:

统一使用 grid() 布局管理器:将所有组件的布局都改为grid()。

统一使用 pack() 布局管理器:将所有组件的布局都改为pack()。

在这种情况下,由于你的按钮是按网格排列的,推荐使用 grid() 来管理按钮的布局。对于canvas,你也可以使用grid(),而不是pack(),这样就可以避免布局冲突。

主要修改:

canvas.grid():将 canvas 使用 grid() 布局,而不是 pack()。

按钮 grid():所有按钮都使用 grid() 来管理,而不是 pack()。

这样就避免了布局冲突,确保所有组件都通过相同的布局管理器(grid())进行管理。您可以尝试运行这段代码,看看是否解决了问题。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档