python实现扫雷游戏的示例


Posted in Python onOctober 20, 2020

扫雷是一款益智类小游戏,最早于 1992 年由微软在 Windows 上发行,游戏适合于全年龄段,规则简单,即在最短的时间内找出所有非雷格子且在中间过程中不能踩到雷, 踩到雷则失败,需重新开始。

本文我们使用 Python 来实现扫雷游戏,主要用的 Python 库是 pygame。

实现

游戏组成比较简单,主要包括:小方格、计时器、地雷等。

首先,我们初始化一些常量,比如:横竖方块数、地雷数、鼠标点击情况等,如下所示:

BLOCK_WIDTH = 30
BLOCK_HEIGHT = 16
# 块大小
SIZE = 20
# 地雷数
MINE_COUNT = 66
# 未点击
normal = 1
# 已点击
opened = 2
# 地雷
mine = 3
# 标记为地雷
flag = 4
# 标记为问号
ask = 5
# 踩中地雷
bomb = 6
# 被双击的周围
hint = 7
# 正被鼠标左右键双击
double = 8
readied = 1,
started = 2,
over = 3,
win = 4

接着定义一个地雷类,类中定义一些基本属性(如:坐标、状态等)及 get、set 方法,代码实现如下:

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 = normal
  self.set_value(value)
 def __repr__(self):
  return str(self._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, 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 = 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 = property(fget=get_status, fset=set_status, doc='BlockStatus')

再接着定义一个 MineBlock 类,用来处理扫雷的基本逻辑,代码实现如下:

class MineBlock:
 def __init__(self):
  self._block = [[Mine(i, j) for i in range(BLOCK_WIDTH)] for j in range(BLOCK_HEIGHT)]
  # 埋雷
  for i in random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT):
   self._block[i // BLOCK_WIDTH][i % BLOCK_WIDTH].value = 1
 def get_block(self):
  return self._block
 block = property(fget=get_block)
 def getmine(self, x, y):
  return self._block[y][x]
 def open_mine(self, x, y):
  # 踩到雷了
  if self._block[y][x].value:
   self._block[y][x].status = bomb
   return False
  # 先把状态改为 opened
  self._block[y][x].status = opened
  around = _get_around(x, y)
  _sum = 0
  for i, j in around:
   if self._block[j][i].value:
    _sum += 1
  self._block[y][x].around_mine_count = _sum
  # 如果周围没有雷,那么将周围 8 个未中未点开的递归算一遍
  if _sum == 0:
   for i, j in around:
    if self._block[j][i].around_mine_count == -1:
     self.open_mine(i, j)
  return True
 def double_mouse_button_down(self, x, y):
  if self._block[y][x].around_mine_count == 0:
   return True
  self._block[y][x].status = double
  around = _get_around(x, y)
  # 周围被标记的雷数量
  sumflag = 0
  for i, j in _get_around(x, y):
   if self._block[j][i].status == flag:
    sumflag += 1
  # 周边的雷已经全部被标记
  result = True
  if sumflag == self._block[y][x].around_mine_count:
   for i, j in around:
    if self._block[j][i].status == normal:
     if not self.open_mine(i, j):
      result = False
  else:
   for i, j in around:
    if self._block[j][i].status == normal:
     self._block[j][i].status = hint
  return result
 def double_mouse_button_up(self, x, y):
  self._block[y][x].status = opened
  for i, j in _get_around(x, y):
   if self._block[j][i].status == hint:
    self._block[j][i].status = normal

我们接下来初始化界面,首先生成由小方格组成的面板,主要代码实现如下

for row in block.block:
	for mine in row:
		pos = (mine.x * SIZE, (mine.y + 2) * SIZE)
		if mine.status == opened:
			screen.blit(img_dict[mine.around_mine_count], pos)
			opened_count += 1
		elif mine.status == double:
			screen.blit(img_dict[mine.around_mine_count], pos)
		elif mine.status == bomb:
			screen.blit(img_blood, pos)
		elif mine.status == flag:
			screen.blit(img_flag, pos)
			flag_count += 1
		elif mine.status == ask:
			screen.blit(img_ask, pos)
		elif mine.status == hint:
			screen.blit(img0, pos)
		elif game_status == over and mine.value:
			screen.blit(img_mine, pos)
		elif mine.value == 0 and mine.status == flag:
			screen.blit(img_error, pos)
		elif mine.status == normal:
			screen.blit(img_blank, pos)

看一下效果:

python实现扫雷游戏的示例

再接着添加面板的 head 部分,包括:显示雷数、重新开始按钮(笑脸)、显示耗时,主要代码实现如下:

print_text(screen, font1, 30, (SIZE * 2 - fheight) // 2 - 2, '%02d' % (MINE_COUNT - flag_count), red)
if game_status == started:
	elapsed_time = int(time.time() - start_time)
print_text(screen, font1, SCREEN_WIDTH - fwidth - 30, (SIZE * 2 - fheight) // 2 - 2, '%03d' % elapsed_time, red)
if flag_count + opened_count == BLOCK_WIDTH * BLOCK_HEIGHT:
	game_status = win
if game_status == over:
	screen.blit(img_face_fail, (face_pos_x, face_pos_y))
elif game_status == win:
	screen.blit(img_face_success, (face_pos_x, face_pos_y))
else:
	screen.blit(img_face_normal, (face_pos_x, face_pos_y))

看一下效果:

python实现扫雷游戏的示例

再接着添加各种点击事件,代码实现如下:

for event in pygame.event.get():
	if event.type == QUIT:
		sys.exit()
	elif event.type == MOUSEBUTTONDOWN:
		mouse_x, mouse_y = event.pos
		x = mouse_x // SIZE
		y = mouse_y // SIZE - 2
		b1, b2, b3 = pygame.mouse.get_pressed()
		if game_status == started:
			# 鼠标左右键同时按下,如果已经标记了所有雷,则打开周围一圈;如果还未标记完所有雷,则有一个周围一圈被同时按下的效果
			if b1 and b3:
				mine = block.getmine(x, y)
				if mine.status == opened:
					if not block.double_mouse_button_down(x, y):
						game_status = over
	elif event.type == MOUSEBUTTONUP:
		if y < 0:
			if face_pos_x <= mouse_x <= face_pos_x + face_size \
					and face_pos_y <= mouse_y <= face_pos_y + face_size:
				game_status = readied
				block = MineBlock()
				start_time = time.time()
				elapsed_time = 0
				continue
		if game_status == readied:
			game_status = started
			start_time = time.time()
			elapsed_time = 0
		if game_status == started:
			mine = block.getmine(x, y)
			# 按鼠标左键
			if b1 and not b3:
				if mine.status == normal:
					if not block.open_mine(x, y):
						game_status = over
			# 按鼠标右键
			elif not b1 and b3:
				if mine.status == normal:
					mine.status = flag
				elif mine.status == flag:
					mine.status = ask
				elif mine.status == ask:
					mine.status = normal
			elif b1 and b3:
				if mine.status == double:
					block.double_mouse_button_up(x, y)

我们来看一下最终实现效果:

python实现扫雷游戏的示例

总结

本文我们通过 Python 简单的实现了扫雷游戏,大家有兴趣的话,可以实际操作一下,看看自己能否排除全部的雷。

完整代码

项目地址

以上就是python实现扫雷游戏的示例的详细内容,更多关于python 扫雷的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
如何将python中的List转化成dictionary
Aug 15 Python
Python正则表达式常用函数总结
Jun 24 Python
python+mongodb数据抓取详细介绍
Oct 25 Python
Python基于递归算法实现的汉诺塔与Fibonacci数列示例
Apr 18 Python
解决DataFrame排序sort的问题
Jun 07 Python
使用Python微信库itchat获得好友和群组已撤回的消息
Jun 24 Python
Python django框架应用中实现获取访问者ip地址示例
May 17 Python
python实现二级登陆菜单及安装过程
Jun 21 Python
对pytorch的函数中的group参数的作用介绍
Feb 18 Python
Python基于内置库pytesseract实现图片验证码识别功能
Feb 24 Python
sklearn+python:线性回归案例
Feb 24 Python
Python 生成VOC格式的标签实例
Mar 10 Python
python3排序的实例方法
Oct 20 #Python
关于python tushare Tkinter构建的简单股票可视化查询系统(Beta v0.13)
Oct 19 #Python
15款Python编辑器的优缺点,别再问我“选什么编辑器”啦
Oct 19 #Python
django使用channels实现通信的示例
Oct 19 #Python
python实现测试工具(二)——简单的ui测试工具
Oct 19 #Python
python实现测试工具(一)——命令行发送get请求
Oct 19 #Python
基于Python制作一副扑克牌过程详解
Oct 19 #Python
You might like
PHP实现的注册,登录及查询用户资料功能API接口示例
2017/06/06 PHP
from 表单提交返回值用post或者是get方法实现
2013/08/21 Javascript
jquery.form.js用法之清空form的方法
2014/03/07 Javascript
jQuery实现移动 和 渐变特效的点击事件
2015/02/26 Javascript
jQuery Ajax 全局调用封装实例代码详解
2016/06/02 Javascript
JS两个数组比较,删除重复值的巧妙方法(推荐)
2016/06/03 Javascript
基于JavaScript实现滑动门效果
2017/03/16 Javascript
JavaScript中使用Async实现异步控制
2017/08/15 Javascript
javascript将list转换成树状结构的实例
2017/09/08 Javascript
Vuejs 单文件组件实例详解
2018/02/09 Javascript
vuejs使用axios异步访问时用get和post的实例讲解
2018/08/09 Javascript
Vue中对拿到的数据进行A-Z排序的实例
2018/09/25 Javascript
nodejs中实现修改用户路由功能
2019/05/24 NodeJs
详解element-ui级联菜单(城市三级联动菜单)和回显问题
2019/10/02 Javascript
详解js location.href和window.open的几种用法和区别
2019/12/02 Javascript
ant-design-vue中tree增删改的操作方法
2020/11/03 Javascript
JavaScript实现打字游戏
2021/02/19 Javascript
python采用getopt解析命令行输入参数实例
2014/09/30 Python
Python内置函数Type()函数一个有趣的用法
2015/02/18 Python
python获取指定路径下所有指定后缀文件的方法
2015/05/26 Python
Python 中的Selenium异常处理实例代码
2018/05/03 Python
python中字符串的操作方法大全
2018/06/03 Python
Python3使用xml.dom.minidom和xml.etree模块儿解析xml文件封装函数的方法
2019/09/23 Python
Python发送邮件的实例代码讲解
2019/10/16 Python
Python 中使用 PyMySQL模块操作数据库的方法
2019/11/10 Python
Python函数参数定义及传递方式解析
2020/06/10 Python
python 多进程和协程配合使用写入数据
2020/10/30 Python
菲律宾领先的在线时尚商店:Zalora菲律宾
2018/02/08 全球购物
世界上最好的旅行夹克:BauBax
2018/12/23 全球购物
机械设计制造专业个人求职信
2013/09/25 职场文书
蛋糕店创业计划书
2014/05/06 职场文书
施工质量承诺书范文
2014/05/30 职场文书
教师批评与自我批评(群众路线)
2014/10/15 职场文书
幼儿学前班评语
2014/12/29 职场文书
2016新年年会主持词
2015/07/06 职场文书
k-means & DBSCAN 总结
2021/04/27 Python