python实现扫雷小游戏


Posted in Python onApril 24, 2020

前面我们用python实现了贪吃蛇、坦克大战、飞船大战、五子棋等游戏

今天我们用python来实现一下扫雷游戏

本游戏代码量和源文件较多

可以从我的GitHub地址中获取

构建地雷区

import random
from enum import Enum

BLOCK_WIDTH = 30
BLOCK_HEIGHT = 16
SIZE = 20   # 块大小
MINE_COUNT = 99  # 地雷数


class BlockStatus(Enum):
 normal = 1 # 未点击
 opened = 2 # 已点击
 mine = 3 # 地雷
 flag = 4 # 标记为地雷
 ask = 5  # 标记为问号
 bomb = 6 # 踩中地雷
 hint = 7 # 被双击的周围
 double = 8 # 正被鼠标左右键双击


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 = BlockStatus.normal
  self.set_value(value)

 def __repr__(self):
  return str(self._value)
  # return f'({self._x},{self._y})={self._value}, status={self.status}'

 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')


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 = BlockStatus.bomb
   return False

  # 先把状态改为 opened
  self._block[y][x].status = BlockStatus.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 = BlockStatus.double

  around = _get_around(x, y)

  sumflag = 0  # 周围被标记的雷数量
  for i, j in _get_around(x, y):
   if self._block[j][i].status == BlockStatus.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 == BlockStatus.normal:
     if not self.open_mine(i, j):
      result = False
  else:
   for i, j in around:
    if self._block[j][i].status == BlockStatus.normal:
     self._block[j][i].status = BlockStatus.hint
  return result

 def double_mouse_button_up(self, x, y):
  self._block[y][x].status = BlockStatus.opened
  for i, j in _get_around(x, y):
   if self._block[j][i].status == BlockStatus.hint:
    self._block[j][i].status = BlockStatus.normal


def _get_around(x, y):
 """返回(x, y)周围的点的坐标"""
 # 这里注意,range 末尾是开区间,所以要加 1
 return [(i, j) for i in range(max(0, x - 1), min(BLOCK_WIDTH - 1, x + 1) + 1)
   for j in range(max(0, y - 1), min(BLOCK_HEIGHT - 1, y + 1) + 1) if i != x or j != y]

主函数

import sys
import time
from enum import Enum
import pygame
from pygame.locals import *
from mineblock import *


# 游戏屏幕的宽
SCREEN_WIDTH = BLOCK_WIDTH * SIZE
# 游戏屏幕的高
SCREEN_HEIGHT = (BLOCK_HEIGHT + 2) * SIZE


class GameStatus(Enum):
 readied = 1,
 started = 2,
 over = 3,
 win = 4


def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):
 imgText = font.render(text, True, fcolor)
 screen.blit(imgText, (x, y))


def main():
 pygame.init()
 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
 pygame.display.set_caption('扫雷')

 font1 = pygame.font.Font('resources/a.TTF', SIZE * 2) # 得分的字体
 fwidth, fheight = font1.size('999')
 red = (200, 40, 40)

 # 加载资源图片,因为资源文件大小不一,所以做了统一的缩放处理
 img0 = pygame.image.load('resources/0.bmp').convert()
 img0 = pygame.transform.smoothscale(img0, (SIZE, SIZE))
 img1 = pygame.image.load('resources/1.bmp').convert()
 img1 = pygame.transform.smoothscale(img1, (SIZE, SIZE))
 img2 = pygame.image.load('resources/2.bmp').convert()
 img2 = pygame.transform.smoothscale(img2, (SIZE, SIZE))
 img3 = pygame.image.load('resources/3.bmp').convert()
 img3 = pygame.transform.smoothscale(img3, (SIZE, SIZE))
 img4 = pygame.image.load('resources/4.bmp').convert()
 img4 = pygame.transform.smoothscale(img4, (SIZE, SIZE))
 img5 = pygame.image.load('resources/5.bmp').convert()
 img5 = pygame.transform.smoothscale(img5, (SIZE, SIZE))
 img6 = pygame.image.load('resources/6.bmp').convert()
 img6 = pygame.transform.smoothscale(img6, (SIZE, SIZE))
 img7 = pygame.image.load('resources/7.bmp').convert()
 img7 = pygame.transform.smoothscale(img7, (SIZE, SIZE))
 img8 = pygame.image.load('resources/8.bmp').convert()
 img8 = pygame.transform.smoothscale(img8, (SIZE, SIZE))
 img_blank = pygame.image.load('resources/blank.bmp').convert()
 img_blank = pygame.transform.smoothscale(img_blank, (SIZE, SIZE))
 img_flag = pygame.image.load('resources/flag.bmp').convert()
 img_flag = pygame.transform.smoothscale(img_flag, (SIZE, SIZE))
 img_ask = pygame.image.load('resources/ask.bmp').convert()
 img_ask = pygame.transform.smoothscale(img_ask, (SIZE, SIZE))
 img_mine = pygame.image.load('resources/mine.bmp').convert()
 img_mine = pygame.transform.smoothscale(img_mine, (SIZE, SIZE))
 img_blood = pygame.image.load('resources/blood.bmp').convert()
 img_blood = pygame.transform.smoothscale(img_blood, (SIZE, SIZE))
 img_error = pygame.image.load('resources/error.bmp').convert()
 img_error = pygame.transform.smoothscale(img_error, (SIZE, SIZE))
 face_size = int(SIZE * 1.25)
 img_face_fail = pygame.image.load('resources/face_fail.bmp').convert()
 img_face_fail = pygame.transform.smoothscale(img_face_fail, (face_size, face_size))
 img_face_normal = pygame.image.load('resources/face_normal.bmp').convert()
 img_face_normal = pygame.transform.smoothscale(img_face_normal, (face_size, face_size))
 img_face_success = pygame.image.load('resources/face_success.bmp').convert()
 img_face_success = pygame.transform.smoothscale(img_face_success, (face_size, face_size))
 face_pos_x = (SCREEN_WIDTH - face_size) // 2
 face_pos_y = (SIZE * 2 - face_size) // 2

 img_dict = {
  0: img0,
  1: img1,
  2: img2,
  3: img3,
  4: img4,
  5: img5,
  6: img6,
  7: img7,
  8: img8
 }

 bgcolor = (225, 225, 225) # 背景色

 block = MineBlock()
 game_status = GameStatus.readied
 start_time = None # 开始时间
 elapsed_time = 0 # 耗时

 while True:
  # 填充背景色
  screen.fill(bgcolor)

  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 == GameStatus.started:
     # 鼠标左右键同时按下,如果已经标记了所有雷,则打开周围一圈
     # 如果还未标记完所有雷,则有一个周围一圈被同时按下的效果
     if b1 and b3:
      mine = block.getmine(x, y)
      if mine.status == BlockStatus.opened:
       if not block.double_mouse_button_down(x, y):
        game_status = GameStatus.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 = GameStatus.readied
      block = MineBlock()
      start_time = time.time()
      elapsed_time = 0
      continue

    if game_status == GameStatus.readied:
     game_status = GameStatus.started
     start_time = time.time()
     elapsed_time = 0

    if game_status == GameStatus.started:
     mine = block.getmine(x, y)
     if b1 and not b3:  # 按鼠标左键
      if mine.status == BlockStatus.normal:
       if not block.open_mine(x, y):
        game_status = GameStatus.over
     elif not b1 and b3:  # 按鼠标右键
      if mine.status == BlockStatus.normal:
       mine.status = BlockStatus.flag
      elif mine.status == BlockStatus.flag:
       mine.status = BlockStatus.ask
      elif mine.status == BlockStatus.ask:
       mine.status = BlockStatus.normal
     elif b1 and b3:
      if mine.status == BlockStatus.double:
       block.double_mouse_button_up(x, y)

  flag_count = 0
  opened_count = 0

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

  print_text(screen, font1, 30, (SIZE * 2 - fheight) // 2 - 2, '%02d' % (MINE_COUNT - flag_count), red)
  if game_status == GameStatus.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 = GameStatus.win

  if game_status == GameStatus.over:
   screen.blit(img_face_fail, (face_pos_x, face_pos_y))
  elif game_status == GameStatus.win:
   screen.blit(img_face_success, (face_pos_x, face_pos_y))
  else:
   screen.blit(img_face_normal, (face_pos_x, face_pos_y))

  pygame.display.update()


if __name__ == '__main__':
 main()

运行效果

python实现扫雷小游戏

更多有趣的经典小游戏实现专题,分享给大家:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python列表append和+的区别浅析
Feb 02 Python
深入Python解释器理解Python中的字节码
Apr 01 Python
python 3.6.2 安装配置方法图文教程
Sep 18 Python
对Python闭包与延迟绑定的方法详解
Jan 07 Python
详解用Python实现自动化监控远程服务器
May 18 Python
Python绘制组合图的示例
Sep 18 Python
python从Oracle读取数据生成图表
Oct 14 Python
pymysql模块使用简介与示例
Nov 17 Python
pandas使用函数批量处理数据(map、apply、applymap)
Nov 27 Python
Prometheus开发中间件Exporter过程详解
Nov 30 Python
Python中Pyspider爬虫框架的基本使用详解
Jan 27 Python
python数字图像处理:图像的绘制
Jun 28 Python
jupyter 使用Pillow包显示图像时inline显示方式
Apr 24 #Python
pyspark 随机森林的实现
Apr 24 #Python
Jupyter打开图形界面并画出正弦函数图像实例
Apr 24 #Python
pyspark给dataframe增加新的一列的实现示例
Apr 24 #Python
Pandas将列表(List)转换为数据框(Dataframe)
Apr 24 #Python
python实现飞船大战
Apr 24 #Python
解决安装新版PyQt5、PyQT5-tool后打不开并Designer.exe提示no Qt platform plugin的问题
Apr 24 #Python
You might like
php cookie 作用范围?不要在当前页面使用你的cookie
2009/03/24 PHP
用mysql_fetch_array()获取当前行数据的方法详解
2013/06/05 PHP
解决PHP curl或file_get_contents下载图片损坏或无法打开的问题
2019/10/11 PHP
javascript 简单高效判断数据类型 系列函数 By shawl.qiu
2007/03/06 Javascript
Javascript Object.extend
2010/05/18 Javascript
妙用Jquery的val()方法
2012/06/27 Javascript
优化javascript的执行效率一些方法总结
2013/12/25 Javascript
node.js中的fs.mkdir方法使用说明
2014/12/17 Javascript
jQuery插件Tmpl的简单使用方法
2015/04/27 Javascript
JS封装cookie操作函数实例(设置、读取、删除)
2015/11/17 Javascript
基于JavaScript实现前端文件的断点续传
2016/10/17 Javascript
Node.js中process模块常用的属性和方法
2016/12/13 Javascript
在vue中添加Echarts图表的基本使用教程
2017/11/22 Javascript
一个简单的node.js界面实现方法
2018/06/01 Javascript
解决vue中post方式提交数据后台无法接收的问题
2018/08/11 Javascript
jQuery实现数字自动增加或者减少的动画效果示例
2018/12/11 jQuery
微信小程序基础教程之worker线程的使用方法
2019/07/15 Javascript
python实现图书馆研习室自动预约功能
2018/04/27 Python
Python开发的十个小贴士和技巧及长常犯错误
2018/09/27 Python
pandas.dataframe按行索引表达式选取方法
2018/10/30 Python
Python之lambda匿名函数及map和filter的用法
2019/03/05 Python
pip install python 快速安装模块的教程图解
2019/10/08 Python
基于python3监控服务器状态进行邮件报警
2019/10/19 Python
用Python进行websocket接口测试
2020/10/16 Python
html5 外链式实现加减乘除的代码
2019/09/04 HTML / CSS
女孩每月服装订阅盒:kidpik
2019/04/17 全球购物
公司总经理工作职责管理办法
2014/02/28 职场文书
警校毕业生自我评价
2014/04/06 职场文书
司法建议书范文
2014/05/13 职场文书
投资意向书
2014/07/30 职场文书
爱祖国爱家乡演讲稿
2014/09/02 职场文书
元旦标语大全
2014/10/09 职场文书
2014年化验员工作总结
2014/11/18 职场文书
2014年手术室工作总结
2014/11/26 职场文书
python中mongodb包操作数据库
2022/04/19 Python
Spring Boot项目如何优雅实现Excel导入与导出功能
2022/06/10 Java/Android