扫雷Minesweeper,1992年4月6日,扫雷和纸牌、空当接龙等小游戏搭载在Windows 3.1系统中与用户见面,主要目的是让用户训练使用鼠标。这个游戏的玩法很简单,有初级(9*9,10颗雷)、中级(16*16,40颗雷)、高级(16*30,99颗雷)和自定义等模式,雷区中随机布置一定数量的地雷,玩家需要尽快找出所有不是地雷的方块,但不许踩到地雷。
本文试图用python+pygame来实现扫雷,其目的为了进一步学习python的面向对象编程及python的一些基本开发技巧。
一、
程序基本文件结构
以下逐步来看看
二、
游戏局的操作主要是通过鼠标的左键数字,右键地雷,两键提示,所以共有8种局状态:blockstatus.py文件内容如下:大家平时做的时候,不可能一下子那么细能枚举完所有的状态,可以一步步来。不要太为难自己。
python
# -*- 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代码就是:
python
# -*- 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,如此类推,并且会使用面向对象的封装概念将数据暴露出来。先上代码看看:
python
# -*- 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等等)编程经验的一看就懂了。
待续。。。