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实用代码片段收集贴
Jun 03 Python
Python的净值数据接口调用示例分享
Mar 15 Python
python通过getopt模块如何获取执行的命令参数详解
Dec 29 Python
对python中类的继承与方法重写介绍
Jan 20 Python
python实现静态服务器
Sep 05 Python
python实现复制文件到指定目录
Oct 16 Python
python元组和字典的内建函数实例详解
Oct 22 Python
python3.8与pyinstaller冲突问题的快速解决方法
Jan 16 Python
keras 实现轻量级网络ShuffleNet教程
Jun 19 Python
Python3实现英文字母转换哥特式字体实例代码
Sep 01 Python
python和C++共享内存传输图像的示例
Oct 27 Python
Python字节单位转换(将字节转换为K M G T)
Mar 02 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中输出转义JavaScript代码的实现代码
2011/04/22 PHP
PHP实现抓取Google IP并自动修改hosts文件
2015/02/12 PHP
php单例模式实现方法分析
2015/03/14 PHP
Laravel 5框架学习之日期,Mutator 和 Scope
2015/04/08 PHP
PHP实现链式操作的核心思想
2015/06/23 PHP
反射调用private方法实践(php、java)
2015/12/21 PHP
PHP在线打包下载功能示例
2016/10/15 PHP
PHP自定义函数获取汉字首字母的方法
2016/12/01 PHP
解决在laravel中leftjoin带条件查询没有返回右表为NULL的问题
2019/10/15 PHP
根据出生日期自动取得星座的js代码
2010/07/20 Javascript
Get中文乱码IE浏览器Get中文乱码解决方案
2013/12/26 Javascript
jQuery源码解读之removeAttr()方法分析
2015/02/20 Javascript
JS获取及设置TextArea或input文本框选择文本位置的方法
2015/03/24 Javascript
Javascript中的prototype与继承
2017/02/06 Javascript
JavaScript 过滤关键字
2017/03/20 Javascript
angular1配合gulp和bower的使用教程
2018/01/19 Javascript
在react中使用vuex的示例代码
2018/07/30 Javascript
jQuery实现的淡入淡出图片轮播效果示例
2018/08/29 jQuery
Vue resource三种请求格式和万能测试地址
2018/09/26 Javascript
详解如何搭建mpvue框架搭配vant组件库的小程序项目
2019/05/16 Javascript
vue 集成 vis-network 实现网络拓扑图的方法
2019/08/07 Javascript
Python 正则表达式操作指南
2009/05/04 Python
浅谈pycharm出现卡顿的解决方法
2018/12/03 Python
Python 解码Base64 得到码流格式文本实例
2020/01/09 Python
python打开文件的方式有哪些
2020/06/29 Python
selenium判断元素是否存在的两种方法小结
2020/12/07 Python
Charlotte Tilbury澳大利亚官网:英国美妆品牌
2018/10/05 全球购物
专业销售业务员求职信
2013/11/18 职场文书
护士演讲稿优秀范文
2014/04/30 职场文书
档案工作汇报材料
2014/08/21 职场文书
优秀小学生事迹材料
2014/12/26 职场文书
党风廉政建设心得体会
2019/05/21 职场文书
利用Nginx代理如何解决前端跨域问题详析
2021/04/02 Servers
pytorch损失反向传播后梯度为none的问题
2021/05/12 Python
springboot 多数据源配置不生效遇到的坑及解决
2021/11/17 Java/Android
你需要掌握的20个Python常用技巧
2022/02/28 Python