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下载FTP上的文件夹的实现代码
Feb 10 Python
Python操作CouchDB数据库简单示例
Mar 10 Python
在Python中操作时间之strptime()方法的使用
Dec 30 Python
Python安装第三方库的3种方法
Jun 21 Python
基于Python实现对PDF文件的OCR识别
Aug 05 Python
python实现在pandas.DataFrame添加一行
Apr 04 Python
Python 3.6 读取并操作文件内容的实例
Apr 23 Python
Python使用修饰器进行异常日志记录操作示例
Mar 19 Python
Python函数基础实例详解【函数嵌套,命名空间,函数对象,闭包函数等】
Mar 30 Python
flask框架配置mysql数据库操作详解
Nov 29 Python
tensorflow如何继续训练之前保存的模型实例
Jan 21 Python
Pytorch中.new()的作用详解
Feb 18 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
ThinkPHP模板判断输出Empty标签用法详解
2014/06/30 PHP
PHP文件上传操作实例详解
2016/09/27 PHP
用JavaScript编写COM组件的步骤
2009/03/17 Javascript
JavaScript的类型转换(字符转数字 数字转字符)
2010/08/30 Javascript
jquery select多选框的左右移动 具体实现代码
2013/07/03 Javascript
如何在JavaScript中实现私有属性的写类方式(二)
2013/12/04 Javascript
jquery实现input输入框实时输入触发事件代码
2014/01/28 Javascript
分享JS代码实现鼠标放在输入框上输入框和图片同时更换样式
2016/09/01 Javascript
chrome下判断点击input上标签还是其余标签的实现方法
2016/09/18 Javascript
浅谈Angular2 模块懒加载的方法
2017/10/04 Javascript
vue中当图片地址无效的时候,显示默认图片的方法
2018/09/18 Javascript
Python实现多线程下载文件的代码实例
2014/06/01 Python
Python里隐藏的“禅”
2014/06/16 Python
Python中的字典与成员运算符初步探究
2015/10/13 Python
Python+OpenCV感兴趣区域ROI提取方法
2019/01/10 Python
使用python list 查找所有匹配元素的位置实例
2019/06/11 Python
python虚拟环境的安装和配置(virtualenv,virtualenvwrapper)
2019/08/09 Python
Python集合基本概念与相关操作实例分析
2019/10/30 Python
python读取文件指定行内容实例讲解
2020/03/02 Python
Python实现数字的格式化输出
2020/08/01 Python
如何用Python绘制3D柱形图
2020/09/16 Python
Python 使用office365邮箱的示例
2020/10/29 Python
amazeui页面分析之登录页面的示例代码
2020/08/25 HTML / CSS
澳大利亚领先的折扣药房:Chemist Direct(有中文站)
2018/11/24 全球购物
行政专员岗位职责
2014/01/02 职场文书
入党转预备思想汇报
2014/01/07 职场文书
物流专业大学生职业生涯规划书范文
2014/01/15 职场文书
关于期中考试的反思
2014/02/02 职场文书
培训班主持词
2014/03/28 职场文书
青年教师师德演讲稿
2014/08/26 职场文书
学习党章的体会
2014/11/07 职场文书
2015年化验室工作总结
2015/04/23 职场文书
新郎婚礼致辞
2015/07/27 职场文书
MySQL创建高性能索引的全步骤
2021/05/02 MySQL
Pytorch DataLoader shuffle验证方式
2021/06/02 Python
MySQL创建管理子分区
2022/04/13 MySQL