今天给大家分享一个由Python3(当然python3.5 3.6 3.7 3.8 ...都行)与pygame模块结合制作的一个经典小游戏“扫雷”

代码是完全可运行的,请大家放心运行。当然了别忘了下载素材(下方代码位置处写明了下载地址)

一、运行效果

二、完整代码

下面的代码用到了一些素材(图片、字体等),下载地址为:https://www.itprojects.cn/detail.html?example_id=dd0fdfb421f61089547578d235b3fce7

  1. import random
  2. import sys
  3. import time
  4.  
  5. import pygame
  6.  
  7. # 地雷数量
  8. MINE_COUNT = 99
  9. # 每个方格的大小(宽、高都为20)
  10. SIZE = 20
  11. # 方格的行数
  12. BLOCK_ROW_NUM = 16
  13. # 方格的列数
  14. BLOCK_COL_NUM = 30
  15. # 游戏窗口的宽、高
  16. SCREEN_WIDTH, SCREEN_HEIGHT = BLOCK_COL_NUM * SIZE, (BLOCK_ROW_NUM + 2) * SIZE
  17.  
  18. def get_mine_flag_num(board_list):
  19. """
  20. 计算还剩多少颗雷
  21. """
  22. num = 0
  23. for line in board_list:
  24. for num_dict in line:
  25. if num_dict.get("closed_num") == "雷标记":
  26. num += 1
  27.  
  28. return num
  29.  
  30. def open_all_mine(board_list):
  31. """
  32. 显示所有的雷
  33. """
  34. for row, line in enumerate(board_list):
  35. for col, num_dict in enumerate(line):
  36. if num_dict.get("opened_num") == "雷":
  37. num_dict["opened"] = True
  38.  
  39. def get_mine_num(row, col, board_list):
  40. """
  41. 计算点击的空格周围的雷的数量
  42. """
  43. # 生成起始位置、终止位置
  44. row_start = row - 1 if row - 1 >= 0 else row
  45. row_stop = row + 2 if row + 1 <= BLOCK_ROW_NUM - 1 else row + 1
  46. col_start = col - 1 if col - 1 >= 0 else col
  47. col_stop = col + 2 if col + 1 <= BLOCK_COL_NUM - 1 else col + 1
  48.  
  49. # 循环遍历当前方格周围的雷的数量
  50. mine_num = 0
  51. for i in range(row_start, row_stop):
  52. for j in range(col_start, col_stop):
  53. if board_list[i][j].get("opened_num") == "雷":
  54. mine_num += 1
  55. return mine_num
  56.  
  57. def set_nums_blank(row, col, board_list):
  58. """
  59. 判断当前位置的周边位置是否为空,如果是则继续判断,
  60. 最终能够实现点击一个空位置后连续的空位置都能够显示出来
  61. """
  62. mine_num = get_mine_num(row, col, board_list)
  63. print("row=%d, col=%d, mine_num=%d" % (row, col, mine_num))
  64. if mine_num == 0:
  65. board_list[row][col]['opened'] = True
  66. board_list[row][col]["opened_num"] = 0
  67. board_list[row][col]["closed_num"] = "空"
  68. # 判断对角是否是数字
  69. for i, j in [(-1, -1), (1, 1), (1, -1), (-1, 1)]:
  70. if 0 <= row + i <= 15 and 0 <= col + j <= 29:
  71. mine_num = get_mine_num(row + i, col + j, board_list)
  72. if mine_num:
  73. board_list[row + i][col + j]['opened'] = True
  74. board_list[row + i][col + j]["opened_num"] = mine_num
  75. board_list[row + i][col + j]["closed_num"] = "空"
  76.  
  77. # 判断剩下4个位置是否是也是0,即空
  78. for i, j in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
  79. if 0 <= row + i <= 15 and 0 <= col + j <= 29:
  80. if not board_list[row + i][col + j].get("opened"):
  81. set_nums_blank(row + i, col + j, board_list)
  82. else:
  83. board_list[row][col]['opened'] = True
  84. board_list[row][col]["opened_num"] = mine_num
  85. board_list[row][col]["closed_num"] = "空"
  86.  
  87. def left_click_block(row, col, board_list):
  88. """
  89. 左击空格后的处理
  90. """
  91. if board_list[row][col].get("opened") is False and board_list[row][col].get("opened_num") != "雷":
  92. # 如果不是雷,那么就计算当前位置数字
  93. mine_num = get_mine_num(row, col, board_list)
  94. print("地雷数:", mine_num)
  95. board_list[row][col]["opened_num"] = mine_num
  96. board_list[row][col]["opened"] = True # 标记为"打开"状态
  97. board_list[row][col]["closed_num"] = "空" # 标记为"未打开时的状态为空格",防止显示剩余雷数错误
  98. if mine_num == 0:
  99. # 如果方格周边没有雷此时,判断是否有连续空位置
  100. set_nums_blank(row, col, board_list)
  101. elif board_list[row][col].get("opened") is False and board_list[row][col].get("opened_num") == "雷":
  102. board_list[row][col]["opened_num"] = "踩雷" # 标记为"踩雷"图片
  103. board_list[row][col]["opened"] = True # 标记为"打开"状态
  104. board_list[row][col]["closed_num"] = "空" # 标记为"未打开时的状态为空格",防止显示剩余雷数错误
  105. return True
  106.  
  107. def create_random_board(row, col, mine_num):
  108. """
  109. 得到一个随机的棋盘
  110. """
  111. # 随机布雷
  112. nums = [{"opened": False, "opened_num": 0, 'closed_num': "空"} for _ in range(row * col - mine_num)] # 16x30-99 表示的是生成381个0
  113. nums += [{"opened": False, "opened_num": "雷", 'closed_num': "空"} for _ in range(mine_num)] # 99颗地雷
  114. random.shuffle(nums) # 乱序,此时nums是乱的
  115. return [list(x) for x in zip(*[iter(nums)] * col)]
  116.  
  117. def right_click_block(row, col, board_list):
  118. """
  119. 右击方格后更新其状态(标记为雷、问号?、取消标记)
  120. """
  121. if board_list[row][col].get("opened") is False:
  122. if board_list[row][col]["closed_num"] == "空":
  123. board_list[row][col]["closed_num"] = "雷标记"
  124. elif board_list[row][col]["closed_num"] == "雷标记":
  125. board_list[row][col]["closed_num"] = "疑问标记"
  126. elif board_list[row][col]["closed_num"] == "疑问标记":
  127. board_list[row][col]["closed_num"] = "空"
  128.  
  129. def click_block(x, y, board_list):
  130. """
  131. 检测点击的是哪个方格(即第x行,第y列)
  132. """
  133. # 计算出点击的空格的行、列
  134. for row, line in enumerate(board_list):
  135. for col, _ in enumerate(line):
  136. if col * SIZE <= x <= (col + 1) * SIZE and (row + 2) * SIZE <= y <= (row + 2 + 1) * SIZE:
  137. print("点击的空格的位置是:", row, col)
  138. return row, col
  139.  
  140. def run(screen):
  141. bgcolor = (225, 225, 225) # 背景色
  142.  
  143. # 要显示的棋盘
  144. # board_list = [[0] * BLOCK_COL_NUM for _ in range(BLOCK_ROW_NUM)]
  145. board_list = create_random_board(BLOCK_ROW_NUM, BLOCK_COL_NUM, MINE_COUNT) # 16行、30列,有99颗地雷
  146.  
  147. # 默认的方格图片
  148. img_blank = pygame.image.load('resource/blank.bmp').convert()
  149. img_blank = pygame.transform.smoothscale(img_blank, (SIZE, SIZE))
  150. # "雷标记"图片
  151. img_mine_flag = pygame.image.load('resource/flag.bmp').convert()
  152. img_mine_flag = pygame.transform.smoothscale(img_mine_flag, (SIZE, SIZE))
  153. # "雷"图片
  154. img_mine = pygame.image.load('resource/mine.bmp').convert()
  155. img_mine = pygame.transform.smoothscale(img_mine, (SIZE, SIZE))
  156. # "疑问标记"图片
  157. img_ask = pygame.image.load('resource/ask.bmp').convert()
  158. img_ask = pygame.transform.smoothscale(img_ask, (SIZE, SIZE))
  159. # "踩雷"图片
  160. img_blood = pygame.image.load('resource/blood.bmp').convert()
  161. img_blood = pygame.transform.smoothscale(img_blood, (SIZE, SIZE))
  162. # "表情"图片
  163. face_size = int(SIZE * 1.25)
  164. img_face_fail = pygame.image.load('resource/face_fail.bmp').convert()
  165. img_face_fail = pygame.transform.smoothscale(img_face_fail, (face_size, face_size))
  166. img_face_normal = pygame.image.load('resource/face_normal.bmp').convert()
  167. img_face_normal = pygame.transform.smoothscale(img_face_normal, (face_size, face_size))
  168. img_face_success = pygame.image.load('resource/face_success.bmp').convert()
  169. img_face_success = pygame.transform.smoothscale(img_face_success, (face_size, face_size))
  170. # "表情"位置
  171. face_pos_x = (SCREEN_WIDTH - face_size) // 2
  172. face_pos_y = (SIZE * 2 - face_size) // 2
  173. # 类的数量图片
  174. img0 = pygame.image.load('resource/0.bmp').convert()
  175. img0 = pygame.transform.smoothscale(img0, (SIZE, SIZE))
  176. img1 = pygame.image.load('resource/1.bmp').convert()
  177. img1 = pygame.transform.smoothscale(img1, (SIZE, SIZE))
  178. img2 = pygame.image.load('resource/2.bmp').convert()
  179. img2 = pygame.transform.smoothscale(img2, (SIZE, SIZE))
  180. img3 = pygame.image.load('resource/3.bmp').convert()
  181. img3 = pygame.transform.smoothscale(img3, (SIZE, SIZE))
  182. img4 = pygame.image.load('resource/4.bmp').convert()
  183. img4 = pygame.transform.smoothscale(img4, (SIZE, SIZE))
  184. img5 = pygame.image.load('resource/5.bmp').convert()
  185. img5 = pygame.transform.smoothscale(img5, (SIZE, SIZE))
  186. img6 = pygame.image.load('resource/6.bmp').convert()
  187. img6 = pygame.transform.smoothscale(img6, (SIZE, SIZE))
  188. img7 = pygame.image.load('resource/7.bmp').convert()
  189. img7 = pygame.transform.smoothscale(img7, (SIZE, SIZE))
  190. img8 = pygame.image.load('resource/8.bmp').convert()
  191. img8 = pygame.transform.smoothscale(img8, (SIZE, SIZE))
  192. img_dict = {
  193. 0: img0,
  194. 1: img1,
  195. 2: img2,
  196. 3: img3,
  197. 4: img4,
  198. 5: img5,
  199. 6: img6,
  200. 7: img7,
  201. 8: img8,
  202. '雷标记': img_mine_flag,
  203. '雷': img_mine,
  204. '空': img_blank,
  205. '疑问标记': img_ask,
  206. '踩雷': img_blood,
  207. }
  208. # 标记是否踩到雷
  209. game_over = False
  210. # 游戏状态
  211. game_status = "normal"
  212. # 显示雷的数量、耗时用到的资源
  213. font = pygame.font.Font('resource/a.TTF', SIZE * 2) # 字体
  214. f_width, f_height = font.size('999')
  215. red = (200, 40, 40)
  216. # 标记出雷的个数
  217. flag_count = 0
  218. # 记录耗时
  219. elapsed_time = 0
  220. last_time = time.time()
  221. start_record_time = False
  222.  
  223. # 创建计时器(防止while循环过快,占用太多CPU的问题)
  224. clock = pygame.time.Clock()
  225. while True:
  226. # 事件检测(鼠标点击、键盘按下等)
  227. for event in pygame.event.get():
  228. if event.type == pygame.QUIT:
  229. pygame.quit()
  230. sys.exit()
  231. elif event.type == pygame.MOUSEBUTTONDOWN and event.button:
  232. b1, b2, b3 = pygame.mouse.get_pressed()
  233. mouse_click_type = None
  234. if b1 and not b2 and not b3: # 左击
  235. mouse_click_type = "left"
  236. elif not b1 and not b2 and b3: # 右击
  237. mouse_click_type = "right"
  238. print("点击了鼠标的[%s]键" % mouse_click_type)
  239. x, y = pygame.mouse.get_pos()
  240. if game_status == "normal" and 2 * SIZE <= y <= SCREEN_HEIGHT:
  241. # 计算点击的是哪个空
  242. position = click_block(x, y, board_list)
  243. if position:
  244. if mouse_click_type == "right":
  245. # 如果右击方格,那么就更新其状态
  246. right_click_block(*position, board_list)
  247. # 更新标记的雷的数量
  248. flag_count = get_mine_flag_num(board_list)
  249. start_record_time = True # 开始记录耗时
  250. elif mouse_click_type == "left":
  251. # 点击空格的处理
  252. game_over = left_click_block(*position, board_list)
  253. print("是否踩到雷", game_over)
  254. start_record_time = True # 开始记录耗时
  255. # 更新标记的雷的数量
  256. flag_count = get_mine_flag_num(board_list)
  257. if game_over:
  258. # 将所有雷的位置,标记出来
  259. open_all_mine(board_list)
  260. # 更改游戏状态
  261. game_status = "fail"
  262. # 停止记录耗时
  263. start_record_time = False
  264. elif face_pos_x <= x <= face_pos_x + face_size and face_pos_y <= y <= face_pos_y + face_size:
  265. # 重来一局
  266. print("点击了再来一局...")
  267. return
  268.  
  269. # 填充背景色
  270. screen.fill(bgcolor)
  271.  
  272. # 显示方格
  273. for i, line in enumerate(board_list):
  274. for j, num_dict in enumerate(line):
  275. if num_dict.get("opened"):
  276. screen.blit(img_dict[num_dict.get("opened_num")], (j * SIZE, (i + 2) * SIZE))
  277. else:
  278. screen.blit(img_dict[num_dict.get("closed_num")], (j * SIZE, (i + 2) * SIZE))
  279.  
  280. # 显示表情
  281. if game_status == "win":
  282. screen.blit(img_face_success, (face_pos_x, face_pos_y))
  283. elif game_status == "fail":
  284. screen.blit(img_face_fail, (face_pos_x, face_pos_y))
  285. else:
  286. screen.blit(img_face_normal, (face_pos_x, face_pos_y))
  287.  
  288. # 显示剩余雷的数量
  289. mine_text = font.render('%02d' % (MINE_COUNT - flag_count), True, red)
  290. screen.blit(mine_text, (30, (SIZE * 2 - f_height) // 2 - 2))
  291.  
  292. # 显示耗时
  293. if start_record_time and time.time() - last_time >= 1:
  294. elapsed_time += 1
  295. last_time = time.time()
  296. mine_text = font.render('%03d' % elapsed_time, True, red)
  297. screen.blit(mine_text, (SCREEN_WIDTH - f_width - 30, (SIZE * 2 - f_height) // 2 - 2))
  298.  
  299. # 刷新显示(此时窗口才会真正的显示)
  300. pygame.display.update()
  301. # FPS(每秒钟显示画面的次数)
  302. clock.tick(60) # 通过一定的延时,实现1秒钟能够循环60次
  303.  
  304. def main():
  305. """
  306. 循环调用run函数,每调用一次就重新来一局游戏
  307. """
  308. pygame.init()
  309. pygame.display.set_caption('扫雷')
  310. screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
  311. while True:
  312. run(screen)
  313.  
  314. if __name__ == '__main__':
  315. main()

Python3+pygame实现Windows经典扫雷的更多相关文章

  1. 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 ...

  2. 基于jQuery经典扫雷游戏源码

    分享一款基于jQuery经典扫雷游戏源码.这是一款网页版扫雷小游戏特效代码下载.效果图如下: 在线预览   源码下载 实现的代码. html代码: <center> <h1>j ...

  3. Python3.x(windows系统)安装matplotlib库

    Python3.x(windows系统)安装matplotlib库 cmd命令: pip install matplotlib 执行结果:

  4. Python3.x(windows系统)安装requests库

    Python3.x(windows系统)安装requests库 cmd命令: pip install requests 执行结果:

  5. Python3.x(windows系统)安装libxml2库

    Python3.x(windows系统)安装libxml2库 cmd安装命令: pip install lxml 执行结果: 再执行命令: pip install virtualenv 执行结果:

  6. Python3.6(windows系统)安装pip.whl

    Python3.6(windows系统)安装pip.whl 1,下载whl文件:https://pypi.python.org/pypi/pip#downloads 2,将下载的文件放入Python的 ...

  7. Python3.6(windows系统)通过pip安装bs4

    Python3.6(windows系统)通过pip安装bs4 cmd安装命令: pip install beautifulsoup4 执行结果:

  8. Python3.6(windows系统)解决编码问题

    Python3.6(windows系统)解决编码问题 1,py文件代码: import urllib.request url = "http://www.douban.com/" ...

  9. Python3+pygame实现的90坦克大战 代码完整 有演示效果

    我是一个典型的80后,年轻时玩过了特别多的游戏,所以这几天用Python3+pygame实现了一个另外小游戏"坦克大战"(其他的游戏,请翻阅我的博客) 本实例代码量有些多,完整的版 ...

随机推荐

  1. hdu5432Rikka with Array (数位dp+十进制转化为二进制)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  2. CodeForces 893C (并查集板子题)

    刷题刷到自闭,写个博客放松一下 题意:n个人,m对朋友,每寻找一个人传播消息需要花费相应的价钱,朋友之间传播消息不需要花钱,问最小的花费 把是朋友的归到一起,求朋友中花钱最少的,将所有最少的加起来. ...

  3. 2017, X Samara Regional Intercollegiate Programming Contest B.Pursuing the Happiness (string函数)

    题意:给你一个字符串,可以交换两个字符的位置,问操作后能否在字符串中找到子串\("happiness"\),如果不能,输出交换的两个位置. 题解:这题其实用string中的find ...

  4. Codeforces Round #663 (Div. 2) C. Cyclic Permutations (构造,图?)  

    题意:对于某个序列,若\(1\le i\le n\),\(1\le j\le i\)且\(p_j>p_i\),或者\(1\le i\le n\),\(i<j \le n\)且\(p_j&g ...

  5. Git管理远程仓库

    一:使用远程仓库的目的 作用:备份,实现代码共享集中化管理: 二:将git本地仓库同步到远程仓库流程图 三:Git克隆操作 目的: 将远程仓库(github远程仓库项目代码)克隆到本地 如何克隆 1. ...

  6. Go中的Socket编程

    在很多底层网络应用开发者的眼里一切编程都是Socket,话虽然有点夸张,但却也几乎如此了,现在的网络编程几乎都是用Socket来编程.你想过这些情景么?我们每天打开浏览器浏览网页时,浏览器进程怎么和W ...

  7. 在kubernetes集群里集成Apollo配置中心(6)之实战使用apollo分环境管理dubbo服务

    生产实践 1.迭代新需求/修复BUG(编码--->提git) 2.测试环境发版,测试(应用通过编译打包发布至test命名空间) 3.测试通过,上线(应用镜像直接发布至prod命名空间) 系统架构 ...

  8. Kubernets二进制安装(16)之安装部署traefik(ingress)

    K8S的DNS实现了服务在集群"内"被自动发现,如何使得服务在Kuberneters集群"外"被使用和访问呢,有二种方法 1)使用NodePort型的Servi ...

  9. woj1002-Genesis woj1003-birthofnoah woj1004-noah's ark

    title: woj1002-Genesis date: 2020-03-05 categories: acm tags: [acm,woj] 输入输出考虑一下.easy #include <i ...

  10. 深入理解gradle中的task

    目录 简介 定义task tasks 集合类 Task 之间的依赖 定义task之间的顺序 给task一些描述 task的条件执行 task rule Finalizer tasks 总结 深入理解g ...