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笔记(2)
Oct 24 Python
Python实现类继承实例
Jul 04 Python
Python 不同对象比较大小示例探讨
Aug 21 Python
Python数据分析之如何利用pandas查询数据示例代码
Sep 01 Python
Python实现图片转字符画的代码实例
Feb 22 Python
2019 Python最新面试题及答案16道题
Apr 11 Python
pandas计数 value_counts()的使用
Jun 24 Python
python manage.py runserver流程解析
Nov 08 Python
python实现126邮箱发送邮件
May 20 Python
Python生成pdf目录书签的实例方法
Oct 29 Python
Django搭建项目实战与避坑细节详解
Dec 06 Python
Python OpenCV中的numpy与图像类型转换操作
Dec 11 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学习的路线图
2013/07/10 PHP
PHP实现简单数字分页效果
2015/07/26 PHP
Yii2.0高级框架数据库增删改查的一些操作
2015/11/16 PHP
PHP设计模式之注册树模式分析
2018/01/26 PHP
php常用字符串查找函数strstr()与strpos()实例分析
2019/06/21 PHP
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
2013/05/17 Javascript
在JavaScript中操作时间之getMonth()方法的使用
2015/06/10 Javascript
JavaScript+CSS实现仿天猫侧边网页菜单效果
2015/08/25 Javascript
Google 地图叠加层实例讲解
2016/08/06 Javascript
全选复选框JavaScript编写小结(附代码)
2017/08/16 Javascript
详解Angular4 路由设置相关
2017/08/26 Javascript
JS中的Replace()传入函数时的用法详解
2017/09/11 Javascript
基于es6三点运算符的使用方法(实例讲解)
2017/10/12 Javascript
微信小程序button组件使用详解
2018/01/31 Javascript
jQuery操作事件完整实例分析
2020/01/10 jQuery
原生js实现拖拽移动与缩放效果
2020/08/24 Javascript
js基于canvas实现时钟组件
2021/02/07 Javascript
[39:32]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS DT 第二场
2014/05/23 DOTA
[01:01:18]VP vs NIP 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
python操作CouchDB的方法
2014/10/08 Python
解决PyCharm中光标变粗的问题
2017/08/05 Python
Python 私有函数的实例详解
2017/09/11 Python
一个Python最简单的接口自动化框架
2018/01/02 Python
Python 实现12306登录功能实例代码
2018/02/09 Python
解决python父线程关闭后子线程不关闭问题
2020/04/25 Python
基于tf.shape(tensor)和tensor.shape()的区别说明
2020/06/30 Python
python获得命令行输入的参数的两种方式
2020/11/02 Python
企业演讲稿范文
2013/12/28 职场文书
本科毕业生应聘求职信
2014/07/06 职场文书
四风对照检查剖析材料
2014/10/07 职场文书
鲁迅故里导游词
2015/02/05 职场文书
上市公司董事长岗位职责
2015/04/16 职场文书
html5调用摄像头截图功能
2022/01/18 Javascript
Spring Security使用单点登录的权限功能
2022/04/03 Java/Android
利用uni-app生成微信小程序的踩坑记录
2022/04/05 Javascript
Java Spring Boot 正确读取配置文件中的属性的值
2022/04/20 Java/Android