Python3+pygame实现Windows经典扫雷
今天给大家分享一个由Python3(当然python3.5 3.6 3.7 3.8 ...都行)与pygame模块结合制作的一个经典小游戏“扫雷”
代码是完全可运行的,请大家放心运行。当然了别忘了下载素材(下方代码位置处写明了下载地址)
一、运行效果
二、完整代码
下面的代码用到了一些素材(图片、字体等),下载地址为:https://www.itprojects.cn/detail.html?example_id=dd0fdfb421f61089547578d235b3fce7
import random
import sys
import time import pygame # 地雷数量
MINE_COUNT = 99
# 每个方格的大小(宽、高都为20)
SIZE = 20
# 方格的行数
BLOCK_ROW_NUM = 16
# 方格的列数
BLOCK_COL_NUM = 30
# 游戏窗口的宽、高
SCREEN_WIDTH, SCREEN_HEIGHT = BLOCK_COL_NUM * SIZE, (BLOCK_ROW_NUM + 2) * SIZE def get_mine_flag_num(board_list):
"""
计算还剩多少颗雷
"""
num = 0
for line in board_list:
for num_dict in line:
if num_dict.get("closed_num") == "雷标记":
num += 1 return num def open_all_mine(board_list):
"""
显示所有的雷
"""
for row, line in enumerate(board_list):
for col, num_dict in enumerate(line):
if num_dict.get("opened_num") == "雷":
num_dict["opened"] = True def get_mine_num(row, col, board_list):
"""
计算点击的空格周围的雷的数量
"""
# 生成起始位置、终止位置
row_start = row - 1 if row - 1 >= 0 else row
row_stop = row + 2 if row + 1 <= BLOCK_ROW_NUM - 1 else row + 1
col_start = col - 1 if col - 1 >= 0 else col
col_stop = col + 2 if col + 1 <= BLOCK_COL_NUM - 1 else col + 1 # 循环遍历当前方格周围的雷的数量
mine_num = 0
for i in range(row_start, row_stop):
for j in range(col_start, col_stop):
if board_list[i][j].get("opened_num") == "雷":
mine_num += 1
return mine_num def set_nums_blank(row, col, board_list):
"""
判断当前位置的周边位置是否为空,如果是则继续判断,
最终能够实现点击一个空位置后连续的空位置都能够显示出来
"""
mine_num = get_mine_num(row, col, board_list)
print("row=%d, col=%d, mine_num=%d" % (row, col, mine_num))
if mine_num == 0:
board_list[row][col]['opened'] = True
board_list[row][col]["opened_num"] = 0
board_list[row][col]["closed_num"] = "空"
# 判断对角是否是数字
for i, j in [(-1, -1), (1, 1), (1, -1), (-1, 1)]:
if 0 <= row + i <= 15 and 0 <= col + j <= 29:
mine_num = get_mine_num(row + i, col + j, board_list)
if mine_num:
board_list[row + i][col + j]['opened'] = True
board_list[row + i][col + j]["opened_num"] = mine_num
board_list[row + i][col + j]["closed_num"] = "空" # 判断剩下4个位置是否是也是0,即空
for i, j in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
if 0 <= row + i <= 15 and 0 <= col + j <= 29:
if not board_list[row + i][col + j].get("opened"):
set_nums_blank(row + i, col + j, board_list)
else:
board_list[row][col]['opened'] = True
board_list[row][col]["opened_num"] = mine_num
board_list[row][col]["closed_num"] = "空" def left_click_block(row, col, board_list):
"""
左击空格后的处理
"""
if board_list[row][col].get("opened") is False and board_list[row][col].get("opened_num") != "雷":
# 如果不是雷,那么就计算当前位置数字
mine_num = get_mine_num(row, col, board_list)
print("地雷数:", mine_num)
board_list[row][col]["opened_num"] = mine_num
board_list[row][col]["opened"] = True # 标记为"打开"状态
board_list[row][col]["closed_num"] = "空" # 标记为"未打开时的状态为空格",防止显示剩余雷数错误
if mine_num == 0:
# 如果方格周边没有雷此时,判断是否有连续空位置
set_nums_blank(row, col, board_list)
elif board_list[row][col].get("opened") is False and board_list[row][col].get("opened_num") == "雷":
board_list[row][col]["opened_num"] = "踩雷" # 标记为"踩雷"图片
board_list[row][col]["opened"] = True # 标记为"打开"状态
board_list[row][col]["closed_num"] = "空" # 标记为"未打开时的状态为空格",防止显示剩余雷数错误
return True def create_random_board(row, col, mine_num):
"""
得到一个随机的棋盘
"""
# 随机布雷
nums = [{"opened": False, "opened_num": 0, 'closed_num': "空"} for _ in range(row * col - mine_num)] # 16x30-99 表示的是生成381个0
nums += [{"opened": False, "opened_num": "雷", 'closed_num': "空"} for _ in range(mine_num)] # 99颗地雷
random.shuffle(nums) # 乱序,此时nums是乱的
return [list(x) for x in zip(*[iter(nums)] * col)] def right_click_block(row, col, board_list):
"""
右击方格后更新其状态(标记为雷、问号?、取消标记)
"""
if board_list[row][col].get("opened") is False:
if board_list[row][col]["closed_num"] == "空":
board_list[row][col]["closed_num"] = "雷标记"
elif board_list[row][col]["closed_num"] == "雷标记":
board_list[row][col]["closed_num"] = "疑问标记"
elif board_list[row][col]["closed_num"] == "疑问标记":
board_list[row][col]["closed_num"] = "空" def click_block(x, y, board_list):
"""
检测点击的是哪个方格(即第x行,第y列)
"""
# 计算出点击的空格的行、列
for row, line in enumerate(board_list):
for col, _ in enumerate(line):
if col * SIZE <= x <= (col + 1) * SIZE and (row + 2) * SIZE <= y <= (row + 2 + 1) * SIZE:
print("点击的空格的位置是:", row, col)
return row, col def run(screen):
bgcolor = (225, 225, 225) # 背景色 # 要显示的棋盘
# board_list = [[0] * BLOCK_COL_NUM for _ in range(BLOCK_ROW_NUM)]
board_list = create_random_board(BLOCK_ROW_NUM, BLOCK_COL_NUM, MINE_COUNT) # 16行、30列,有99颗地雷 # 默认的方格图片
img_blank = pygame.image.load('resource/blank.bmp').convert()
img_blank = pygame.transform.smoothscale(img_blank, (SIZE, SIZE))
# "雷标记"图片
img_mine_flag = pygame.image.load('resource/flag.bmp').convert()
img_mine_flag = pygame.transform.smoothscale(img_mine_flag, (SIZE, SIZE))
# "雷"图片
img_mine = pygame.image.load('resource/mine.bmp').convert()
img_mine = pygame.transform.smoothscale(img_mine, (SIZE, SIZE))
# "疑问标记"图片
img_ask = pygame.image.load('resource/ask.bmp').convert()
img_ask = pygame.transform.smoothscale(img_ask, (SIZE, SIZE))
# "踩雷"图片
img_blood = pygame.image.load('resource/blood.bmp').convert()
img_blood = pygame.transform.smoothscale(img_blood, (SIZE, SIZE))
# "表情"图片
face_size = int(SIZE * 1.25)
img_face_fail = pygame.image.load('resource/face_fail.bmp').convert()
img_face_fail = pygame.transform.smoothscale(img_face_fail, (face_size, face_size))
img_face_normal = pygame.image.load('resource/face_normal.bmp').convert()
img_face_normal = pygame.transform.smoothscale(img_face_normal, (face_size, face_size))
img_face_success = pygame.image.load('resource/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
# 类的数量图片
img0 = pygame.image.load('resource/0.bmp').convert()
img0 = pygame.transform.smoothscale(img0, (SIZE, SIZE))
img1 = pygame.image.load('resource/1.bmp').convert()
img1 = pygame.transform.smoothscale(img1, (SIZE, SIZE))
img2 = pygame.image.load('resource/2.bmp').convert()
img2 = pygame.transform.smoothscale(img2, (SIZE, SIZE))
img3 = pygame.image.load('resource/3.bmp').convert()
img3 = pygame.transform.smoothscale(img3, (SIZE, SIZE))
img4 = pygame.image.load('resource/4.bmp').convert()
img4 = pygame.transform.smoothscale(img4, (SIZE, SIZE))
img5 = pygame.image.load('resource/5.bmp').convert()
img5 = pygame.transform.smoothscale(img5, (SIZE, SIZE))
img6 = pygame.image.load('resource/6.bmp').convert()
img6 = pygame.transform.smoothscale(img6, (SIZE, SIZE))
img7 = pygame.image.load('resource/7.bmp').convert()
img7 = pygame.transform.smoothscale(img7, (SIZE, SIZE))
img8 = pygame.image.load('resource/8.bmp').convert()
img8 = pygame.transform.smoothscale(img8, (SIZE, SIZE))
img_dict = {
0: img0,
1: img1,
2: img2,
3: img3,
4: img4,
5: img5,
6: img6,
7: img7,
8: img8,
'雷标记': img_mine_flag,
'雷': img_mine,
'空': img_blank,
'疑问标记': img_ask,
'踩雷': img_blood,
}
# 标记是否踩到雷
game_over = False
# 游戏状态
game_status = "normal"
# 显示雷的数量、耗时用到的资源
font = pygame.font.Font('resource/a.TTF', SIZE * 2) # 字体
f_width, f_height = font.size('999')
red = (200, 40, 40)
# 标记出雷的个数
flag_count = 0
# 记录耗时
elapsed_time = 0
last_time = time.time()
start_record_time = False # 创建计时器(防止while循环过快,占用太多CPU的问题)
clock = pygame.time.Clock()
while True:
# 事件检测(鼠标点击、键盘按下等)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN and event.button:
b1, b2, b3 = pygame.mouse.get_pressed()
mouse_click_type = None
if b1 and not b2 and not b3: # 左击
mouse_click_type = "left"
elif not b1 and not b2 and b3: # 右击
mouse_click_type = "right"
print("点击了鼠标的[%s]键" % mouse_click_type)
x, y = pygame.mouse.get_pos()
if game_status == "normal" and 2 * SIZE <= y <= SCREEN_HEIGHT:
# 计算点击的是哪个空
position = click_block(x, y, board_list)
if position:
if mouse_click_type == "right":
# 如果右击方格,那么就更新其状态
right_click_block(*position, board_list)
# 更新标记的雷的数量
flag_count = get_mine_flag_num(board_list)
start_record_time = True # 开始记录耗时
elif mouse_click_type == "left":
# 点击空格的处理
game_over = left_click_block(*position, board_list)
print("是否踩到雷", game_over)
start_record_time = True # 开始记录耗时
# 更新标记的雷的数量
flag_count = get_mine_flag_num(board_list)
if game_over:
# 将所有雷的位置,标记出来
open_all_mine(board_list)
# 更改游戏状态
game_status = "fail"
# 停止记录耗时
start_record_time = False
elif face_pos_x <= x <= face_pos_x + face_size and face_pos_y <= y <= face_pos_y + face_size:
# 重来一局
print("点击了再来一局...")
return # 填充背景色
screen.fill(bgcolor) # 显示方格
for i, line in enumerate(board_list):
for j, num_dict in enumerate(line):
if num_dict.get("opened"):
screen.blit(img_dict[num_dict.get("opened_num")], (j * SIZE, (i + 2) * SIZE))
else:
screen.blit(img_dict[num_dict.get("closed_num")], (j * SIZE, (i + 2) * SIZE)) # 显示表情
if game_status == "win":
screen.blit(img_face_success, (face_pos_x, face_pos_y))
elif game_status == "fail":
screen.blit(img_face_fail, (face_pos_x, face_pos_y))
else:
screen.blit(img_face_normal, (face_pos_x, face_pos_y)) # 显示剩余雷的数量
mine_text = font.render('%02d' % (MINE_COUNT - flag_count), True, red)
screen.blit(mine_text, (30, (SIZE * 2 - f_height) // 2 - 2)) # 显示耗时
if start_record_time and time.time() - last_time >= 1:
elapsed_time += 1
last_time = time.time()
mine_text = font.render('%03d' % elapsed_time, True, red)
screen.blit(mine_text, (SCREEN_WIDTH - f_width - 30, (SIZE * 2 - f_height) // 2 - 2)) # 刷新显示(此时窗口才会真正的显示)
pygame.display.update()
# FPS(每秒钟显示画面的次数)
clock.tick(60) # 通过一定的延时,实现1秒钟能够循环60次 def main():
"""
循环调用run函数,每调用一次就重新来一局游戏
"""
pygame.init()
pygame.display.set_caption('扫雷')
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
while True:
run(screen) if __name__ == '__main__':
main()
Python3+pygame实现Windows经典扫雷的更多相关文章
- TensorFlow 1.2.0新版本完美支持Python3.6,windows在cmd中输入pip install tensorflow就能下载应用最新tensorflow
TensorFlow 1.2.0新版本完美支持Python3.6,windows在cmd中输入pip install tensorflow就能下载应用最新tensorflow 只需在cmd中输入pip ...
- 基于jQuery经典扫雷游戏源码
分享一款基于jQuery经典扫雷游戏源码.这是一款网页版扫雷小游戏特效代码下载.效果图如下: 在线预览 源码下载 实现的代码. html代码: <center> <h1>j ...
- Python3.x(windows系统)安装matplotlib库
Python3.x(windows系统)安装matplotlib库 cmd命令: pip install matplotlib 执行结果:
- Python3.x(windows系统)安装requests库
Python3.x(windows系统)安装requests库 cmd命令: pip install requests 执行结果:
- Python3.x(windows系统)安装libxml2库
Python3.x(windows系统)安装libxml2库 cmd安装命令: pip install lxml 执行结果: 再执行命令: pip install virtualenv 执行结果:
- Python3.6(windows系统)安装pip.whl
Python3.6(windows系统)安装pip.whl 1,下载whl文件:https://pypi.python.org/pypi/pip#downloads 2,将下载的文件放入Python的 ...
- Python3.6(windows系统)通过pip安装bs4
Python3.6(windows系统)通过pip安装bs4 cmd安装命令: pip install beautifulsoup4 执行结果:
- Python3.6(windows系统)解决编码问题
Python3.6(windows系统)解决编码问题 1,py文件代码: import urllib.request url = "http://www.douban.com/" ...
- Python3+pygame实现的90坦克大战 代码完整 有演示效果
我是一个典型的80后,年轻时玩过了特别多的游戏,所以这几天用Python3+pygame实现了一个另外小游戏"坦克大战"(其他的游戏,请翻阅我的博客) 本实例代码量有些多,完整的版 ...
随机推荐
- 【poj 1284】Primitive Roots(数论--欧拉函数 求原根个数){费马小定理、欧拉定理}
题意:求奇质数 P 的原根个数.若 x 是 P 的原根,那么 x^k (k=1~p-1) 模 P 为1~p-1,且互不相同. (3≤ P<65536) 解法:有费马小定理:若 p 是质数,x^( ...
- Codeforces Round #654 (Div. 2) D. Grid-00100 (构造)
题意:构造一个\(n\)x\(n\)只含\(0\)和\(k\)个\(1\)的矩阵,统计每一行每一列\(1\)的sum,然后构造一个权值最大行和最小行的差的平方加权值最大列和最小列的差的平方的最小和(\ ...
- 支撑性服务 & 自动化
连载传送门: 什么是云原生? 云原生设计理念 .NET 微服务 谈到云原生,绕不开"容器化" Backing services 云原生系统依赖于许多不同的辅助资源,例如数据存储.消 ...
- python之字符串split和rsplit的方法
1.描述 split()方法通过指定分隔符对字符串进行切片,如果参数num有指定值,则分隔num+1个子字符串,默认分隔符为所有空字符,包括空格.换行(\n).制表符(\t)等 rstrip()方法通 ...
- python to exe
使用pyinstaller 打包 文件结构如下 命令行cd 进入 project文件夹 ,然后 命令 pyinstaller -F main.py 即可打包文件为一个完整的exe.(不含DLL等)
- HDU 6623 Minimal Power of Prime(思维)题解
题意: 已知任意大于\(1\)的整数\(a = p_1^{q_1}p_2^{q_2} \cdots p_k^{q_k}\),现给出\(a \in [2,1e18]\),求\(min\{q_i\},q ...
- ZOJ 3430 Detect the Virus(AC自动机 + 模拟)题解
题意:问你主串有几种模式串.但是所有串都是加密的,先解码.解码过程为:先把串按照他给的映射表变成6位数二进制数,然后首尾衔接变成二进制长串,再8位8位取变成新的数,不够的补0.因为最多可能到255,所 ...
- TypeScript Generics All In one
TypeScript Generics All In one TypeScript 泛型 代码逻辑复用 扩展性 设计模式 方法覆写, 直接覆盖 方法重载,参数个数或参数类型不同 test " ...
- shit api & shit antd
shit api & shit antd 代码演示 ??? https://ant.design/components/skeleton-cn/ https://github.com/ant- ...
- Apple iPhone 12 Pro 数据迁移方式 All In One
Apple iPhone 12 Pro 数据迁移方式 All In One iPhone 12 Pro https://mp.weixin.qq.com/s/US1Z_69zVQIhV-cNW1E6A ...