python实现扫雷小游戏
扫雷
新人博主,学习python一个多月,请大家多多关照,不足之处,敬请雅正。
准备工作
下载制作扫雷游戏所需要的一些图片,如数字0-8,雷等。
链接: link.
设计原理
定义一个类block_condition用来判断方块的状态。再用个类Mine返回方块的性质:坐标,是否为雷,周边雷的数量。类mine_block用来埋地雷和点击的效果,点到雷,返回False,没点到雷就点开这个方块,如果点击的方块周边无雷,则向周围递归打开,可以实现一点就是一片的效果。判断游戏胜利的标志为:点开的方块加地雷数等于总数,失败的标志为:踩到地雷。
实施步骤
1.定义一个类用来表示方块的状态
我们都知道扫雷是个鼠标操作的游戏,每个小方块都有不同的状态,仅对鼠标而言,就有被点击、未被点击,右键一次、两次,被点击的方块也有踩中地雷和没有踩中。这么多状态,一个个声明有些麻烦,索性将其封装到一个类里,方便调用。
class Block_Condition():
unclicked = 1 # 未点击
clicked = 2 # 已点击
mine = 3 # 地雷
flag = 4 # 标记为地雷
ask = 5 # 标记为问号
bomb = 6 # 踩中地雷
2.再定义一个类用来获取坐标,周边地雷的数量,方块的状态
鼠标点击,如何知道点击的是哪个方块,这就需要知道每个方块的坐标。点击下去,究竟是不是雷呢,那就还需要一个变量来确定是否是雷,此处,用x,y来表示坐标,value的值表示是否是地雷,0表示不是,1表示是,正好对应了布尔代数式的取值,方便程序编译理解。此处把周边地雷的数量设置成-1而非0,是因为如果设置成0,那根据游戏的原理,就直接向旁边递归打开了,那点一下,所有方块都要被点击了,游戏就不用玩了。在这个类中,condition对应了上一个类,用来存储方块的状态,我们依据方块的状态才能进行游戏,加载图片,判断胜利与否。
from block_condition import *
class Mine:
def __init__(self, x, y, value=0):
self._x = x
self._y = y
self._value = 0
self._surround_count = -1 #周边雷的数量
self._condition = Block_Condition.unclicked #初始设置为未点击
self.set_value(value)
def get_x(self):
return self._x #直接传入
def set_x(self, x):
self._x = 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 = 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 = property(fget=get_value, fset=set_value)
def get_surround_count(self): #获取周边雷的数量
return self._surround_count
def set_surround_count(self, surround_count):
self._surround_count = surround_count
surround_count = property(fget=get_surround_count, fset=set_surround_count)
def get_condition(self): #方块的状态
return self._condition
def set_condition(self, value):
self._condition = value
condition = property(fget=get_condition, fset=set_condition)
3.随机生成地雷,递归打开周边无雷的方块
要想实现扫雷,每个方块都得是一个类,包含其坐标,自身的状态(是否是雷或是周边有多少地雷),所以需要定义一个二维数组list_mine,每个元素都是Mine类。而要想实现一点开就是一片的效果,则需要函数返回某个方块周边的方块,我们用函数get_around来返回某一方块周边的方块。如果方块旁边的地雷数量为0,那就向周边打开(只打开周边没有地雷的方块),形成一点就是一片的效果。游戏可以从代码里调整方块和地雷的数量来改变难度。
初始化只要将每个方块都变成Mine类就行,将二维数组list_mine赋值给block即可。埋下地雷用random.sample,从指定序列中随机获取指定长度的片段,在此呢,就是把被系统随机选中的block的value变成1,即将其变成地雷。
import random
import time
from Mine import *
from block_condition import *
BLOCK_WIDTH=30
BLOCK_HEIGHT=20
MINE_COUNT=99 #地雷数量
list_mine=[[]]
list_mine=[[Mine(i,j) for i in range(BLOCK_WIDTH)] for j in range(BLOCK_HEIGHT)]
def get_around(x, y):
#返回(x, y)周围一圈的点
return [(i, j) for i in range(max(0, x - 1), min(BLOCK_WIDTH - 1, x + 1) + 1) #range是左闭右开
for j in range(max(0, y - 1), min(BLOCK_HEIGHT - 1, y + 1) + 1) ]
class Mine_Block:
def __init__(self):
self._block = list_mine
# 埋下地雷的种子
for i in random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT):
self._block[i // BLOCK_WIDTH][i % BLOCK_WIDTH].value = 1
def getblock(self, x, y):
return self._block[y][x]
def open_block(self, x, y):
# 真不幸,这是颗地雷
if self._block[y][x].value:
self._block[y][x].condition = Block_Condition.bomb
return False
self._block[y][x].condition = Block_Condition.clicked #没踩雷
around = get_around(x, y)
sum1 = 0
for i, j in around:
if self._block[j][i].value:
sum1 += 1
self._block[y][x].surround_count = sum1
if sum1