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 条件判断的缩写方法
Sep 06 Python
Python pickle模块用法实例
Apr 14 Python
浅谈python中的变量默认是什么类型
Sep 11 Python
Python tkinter模块中类继承的三种方式分析
Aug 08 Python
python+numpy+matplotalib实现梯度下降法
Aug 31 Python
Python3.5模块的定义、导入、优化操作图文详解
Apr 27 Python
python的pytest框架之命令行参数详解(上)
Jun 27 Python
基于Django统计博客文章阅读量
Oct 29 Python
python不相等的两个字符串的 if 条件判断为True详解
Mar 12 Python
详解Windows下PyCharm安装Numpy包及无法安装问题解决方案
Jun 18 Python
keras 两种训练模型方式详解fit和fit_generator(节省内存)
Jul 03 Python
python unichr函数知识点总结
Dec 16 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
【COS正片】蕾姆睡衣cos,纯洁可爱被治愈了 cn名濑弥七
2020/03/02 日漫
php jquery 多文件上传简单实例
2013/12/23 PHP
php中执行系统命令的方法
2015/03/21 PHP
php根据年月获取当月天数及日期数组的方法
2016/11/30 PHP
Laravel框架执行原生SQL语句及使用paginate分页的方法
2018/08/17 PHP
js计算字符串长度包含的中文是utf8格式
2013/10/15 Javascript
javascript scrollTop正解使用方法
2013/11/14 Javascript
javascript操作table(insertRow,deleteRow,insertCell,deleteCell方法详解)
2013/12/16 Javascript
JS动态添加与删除select中的Option对象(示例代码)
2013/12/20 Javascript
分享两款带遮罩的jQuery弹出框
2015/12/30 Javascript
js简单判断移动端系统的方法
2016/02/25 Javascript
jQuery实现鼠标跟随提示层效果代码(可显示文本,Div,Table,Html等)
2016/04/18 Javascript
JS脚本实现动态给标签控件添加事件的方法
2016/06/02 Javascript
BootStrap.css 在手机端滑动时右侧出现空白的原因及解决办法
2016/06/07 Javascript
js表单元素checked、radio被选中的几种方法(详解)
2016/08/22 Javascript
用jQuery.ajaxSetup实现对请求和响应数据的过滤
2016/12/20 Javascript
vuex 项目结构目录及一些简单配置介绍
2018/04/08 Javascript
js核心基础之构造函数constructor用法实例分析
2019/05/11 Javascript
小程序实现搜索框
2020/06/19 Javascript
[45:18]完美世界DOTA2联赛循环赛 PXG vs IO 第二场 11.06
2020/11/09 DOTA
在centos7中分布式部署pyspider
2017/05/03 Python
python解决js文件utf-8编码乱码问题(推荐)
2018/05/02 Python
解决DataFrame排序sort的问题
2018/06/07 Python
pandas 读取各种格式文件的方法
2018/06/22 Python
Python3中列表list合并的四种方法
2019/04/19 Python
用python给自己做一款小说阅读器过程详解
2019/07/11 Python
Python基于network模块制作电影人物关系图
2020/06/19 Python
夏尔巴人登珠峰品牌:Sherpa Adventure Gear
2018/02/08 全球购物
专业幼师实习生自我鉴定范文
2013/12/08 职场文书
酒店副总经理岗位职责范本
2014/02/04 职场文书
适用于所有创业者的创业计划书
2014/02/05 职场文书
生日礼品店创业计划书范文
2014/03/21 职场文书
幼儿园个人总结
2015/02/28 职场文书
会议简讯范文
2015/07/20 职场文书
Python+OpenCV实现图片中的圆形检测
2022/04/07 Python
CSS中理解层叠性及权重如何分配
2022/12/24 HTML / CSS