python+pygame实现扫雷游戏之一

扫雷Minesweeper,1992年4月6日,扫雷和纸牌、空当接龙等小游戏搭载在Windows 3.1系统中与用户见面,主要目的是让用户训练使用鼠标。这个游戏的玩法很简单,有初级(9*9,10颗雷)、中级(16*16,40颗雷)、高级(16*30,99颗雷)和自定义等模式,雷区中随机布置一定数量的地雷,玩家需要尽快找出所有不是地雷的方块,但不许踩到地雷。

本文试图用python+pygame来实现扫雷,其目的为了进一步学习python的面向对象编程及python的一些基本开发技巧。

一、

程序基本文件结构

以下逐步来看看

二、

游戏局的操作主要是通过鼠标的左键数字,右键地雷,两键提示,所以共有8种局状态:blockstatus.py文件内容如下:大家平时做的时候,不可能一下子那么细能枚举完所有的状态,可以一步步来。不要太为难自己。

# -*- coding: utf-8 -*-
from enum import Enum

class BlockStatus(Enum):
    normal = 1  # 未点击
    opened = 2  # 已点击
    mine = 3    # 地雷
    flag = 4    # 标记为地雷
    ask = 5     # 标记为问号
    bomb = 6    # 踩中地雷
    hint = 7    # 被双击的周围
    double = 8  # 正被鼠标左右键双击

三、

游戏状态,一般就是准备好了还未开始,开始了,胜了,败了

所以gamestatus.py代码就是:

# -*- coding: utf-8 -*-
from enum import Enum

class GameStatus(Enum):
    readied = 1,      #准备好了还未开始
    started = 2,      #开始了
    over = 3,         #败了
    win = 4           #胜了

四、

下面可以开始构造游戏的基本构成单元:单元格   mine.py类

对于任意一格,它可能是雷,可能不是雷,以value=1表示是雷,0表示不是雷

每一个格子还会有一个行号+列号表示它的位置,很自然会想到使用二维数组来表示,那么就构成了一个完整的数据结构,例如:第二行第三列是地雷,那么blocks[2][1].value=1,如此类推,并且会使用面向对象的封装概念将数据暴露出来。先上代码看看:

# -*- coding: utf-8 -*-
from  blockstatus import *

class Mine:
    def __init__(self, x, y, value=0):
        self._x = x
        self._y = y
        self._value = 0
        self._around_mine_count = -1
        self._status = BlockStatus.normal
        self.set_value(value)

     # __repr__是Python中一个重要的特殊方法,它允许开发者控制对象在特定情况下的字符串表现形式,从而增强代码的可读性和可维护性。
    # 与__str__的区别:虽然__str__和__repr__都用于提供对象的字符串表示,但它们的主要用途不同。\
    # 通常,__str__用于提供用户友好的输出,而__repr__则用于提供详细的、可能包含足够信息以重新创建对象的字符串表示。

    def __repr__(self):             #用于自定义对象的字符串表示形式
        return str(self._value)     #用value来表示该地雷,通常该对象是用默认的内存地址表示。
                                    
    def get_x(self):
        return self._x

    def set_x(self, x):
        self._x = x

    #定义了属性x 
    #在Python中,property 是一种内置的装饰器,它可以将类的方法转换为属性,让你在不改变类接口的情况下添加额外的逻辑,如输入值的验证、取值的计算等。\
    # property 可以作为一种方式让你的类接口保持清晰且易于使用。
    # property 装饰器最常见的应用场景是将类的属性封装起来,提供getter 和 setter 方法。这种方式的原因是,你可以对属性赋值或者取值的代码进行控制,而不是直接暴露属性。
    #这体现了面向对象的三大特征:封装、继承、多态中的封装
    # 设想一下,假如后续改变了get_x的方法名为get_XX,那只需要改变property的参数即可(改成(fget=get_XX, fset=set_x),整体就清晰一些)。
    x = property(fget=get_x, fset=set_x)

    def get_y(self):
        return self._y

    def set_y(self, y):
        self._y = y

    #定义了属性y 
    y = property(fget=get_y, fset=set_y)

    def get_value(self):
        return self._value

    def set_value(self, value):
        if value:
            self._value = 1
        else:
            self._value = 0
    #定义了属性value
    value = property(fget=get_value, fset=set_value, doc='0:非地雷 1:雷')

    def get_around_mine_count(self):
        return self._around_mine_count

    def set_around_mine_count(self, around_mine_count):
        self._around_mine_count = around_mine_count
    #定义了属性around_mine_count 
    around_mine_count = property(fget=get_around_mine_count, fset=set_around_mine_count, doc='四周地雷数量')

    def get_status(self):
        return self._status

    def set_status(self, value):
        self._status = value
    #定义了属性status
    status = property(fget=get_status, fset=set_status, doc='BlockStatus')

这段代码到底要怎么去实现,个人的写法不一样,可以很简单。在这里主要是希望通过这个类的实现来看看python的实现风格。别看代码量有点长,其实绝大部分是封装时的标准代码,有其他面向对象语言(c#,java等等)编程经验的一看就懂了。

待续。。。

python+pygame实现扫雷游戏之二

好的,下面是一个简单的扫雷游戏实现,使用Pythonpygame库: ```python import pygame import random # 初始化游戏 pygame.init() # 设置游戏窗口尺寸 WIDTH = 500 HEIGHT = 600 WINDOW_SIZE = (WIDTH, HEIGHT) # 设置游戏窗口标题 pygame.display.set_caption("扫雷游戏") # 定义常用颜色 BLACK = (0, 0, 0) WHITE = (255, 255, 255) GRAY = (128, 128, 128) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) YELLOW = (255, 255, 0) # 定义游戏区域尺寸和格子数量 GRID_SIZE = 20 GRID_NUM = int(WIDTH / GRID_SIZE) # 定义雷区和雷数量 mines = [] mine_num = 50 # 创建游戏窗口 screen = pygame.display.set_mode(WINDOW_SIZE) # 创建字体对象 font = pygame.font.SysFont(None, 40) # 创建游戏结束标志 game_over = False # 生成随机雷区 def generate_mines(): global mines # 随机生成雷的位置 for i in range(mine_num): mine = (random.randint(0, GRID_NUM - 1), random.randint(0, GRID_NUM - 1)) while mine in mines: mine = (random.randint(0, GRID_NUM - 1), random.randint(0, GRID_NUM - 1)) mines.append(mine) # 计算每个格子周围的雷数 def count_mines(x, y): count = 0 for i in range(-1, 2): for j in range(-1, 2): if (x + i, y + j) in mines: count += 1 return count # 绘制游戏界面 def draw_game(): global game_over # 绘制游戏区域 screen.fill(WHITE) for i in range(GRID_NUM): for j in range(GRID_NUM): pygame.draw.rect(screen, GRAY, (i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE), 1) if (i, j) in mines and not game_over: pygame.draw.circle(screen, BLACK, (i * GRID_SIZE + GRID_SIZE // 2, j * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4) elif (i, j) not in mines and not game_over: count = count_mines(i, j) if count > 0: text = font.render(str(count), True, BLUE) screen.blit(text, (i * GRID_SIZE + GRID_SIZE // 2 - text.get_width() // 2, j * GRID_SIZE + GRID_SIZE // 2 - text.get_height() // 2)) # 绘制游戏结束信息 if game_over: text = font.render("Game Over", True, RED) screen.blit(text, (WIDTH // 2 - text.get_width() // 2, HEIGHT // 2 - text.get_height() // 2)) # 刷新屏幕 pygame.display.flip() # 主循环 generate_mines() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() elif event.type == pygame.MOUSEBUTTONDOWN: if not game_over: x, y = pygame.mouse.get_pos() i, j = x // GRID_SIZE, y // GRID_SIZE if (i, j) in mines: game_over = True else: count = count_mines(i, j) if count == 0: # 连续翻开空白格子 visited = set() queue = [(i, j)] while queue: x, y = queue.pop(0) visited.add((x, y)) for m in range(-1, 2): for n in range(-1, 2): if 0 <= x + m < GRID_NUM and 0 <= y + n < GRID_NUM and (x + m, y + n) not in visited: count = count_mines(x + m, y + n) if count == 0: queue.append((x + m, y + n)) elif count > 0: visited.add((x + m, y + n)) for x, y in visited: if (x, y) not in mines: count = count_mines(x, y) if count > 0: text = font.render(str(count), True, BLUE) screen.blit(text, (x * GRID_SIZE + GRID_SIZE // 2 - text.get_width() // 2, y * GRID_SIZE + GRID_SIZE // 2 - text.get_height() // 2)) pygame.draw.rect(screen, WHITE, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE)) else: # 翻开数字格子 text = font.render(str(count), True, BLUE) screen.blit(text, (i * GRID_SIZE + GRID_SIZE // 2 - text.get_width() // 2, j * GRID_SIZE + GRID_SIZE // 2 - text.get_height() // 2)) pygame.draw.rect(screen, WHITE, (i * GRID_SIZE, j * GRID_SIZE, GRID_SIZE, GRID_SIZE)) else: game_over = False mines.clear() generate_mines() draw_game() ``` 这个程序使用了Pygame库来实现,可以直接运行,生成一个简单的扫雷游戏界面。其中,generate_mines()函数用于随机生成雷区,count_mines(x, y)函数用于计算每个格子周围的雷数,draw_game()函数用于绘制游戏界面,主循环监听鼠标事件,根据用户的操作来更新游戏状态和界面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值