python 扫雷游戏

前言

又不知道该干啥了。。。。。。

开始

献上代码

from tkinter.messagebox import showinfo
from pygame.locals import *
import tkinter as tk
import random
import pygame
base = tk.Tk()
base.withdraw()
pygame.init()
WIDTH = 10
HEIGHT = 10
def generate(w,h):
	res = []
	for i in range(h):
		ls = []
		for j in range(w):
			ls.append(False)
		res.append(ls)
	bomb_total = random.randint(1,w * h // 4)
	for i in range(bomb_total):
		x = random.randint(0,w - 1)
		y = random.randint(0,h - 1)
		res[x][y] = True
	return res
def show(surf,vals):
	font = pygame.font.Font('songti SC.TTF',100)
	for i in range(len(vals)):
		for j in range(len(vals[i])):
			x1,y1,x2,y2 = i * 50,j * 50,i * 50 + 50,j * 50 + 50
			rect = pygame.Rect((x1,y1,x2,y2))
			if(vals[i][j] == None):
				t = font.render(' ',True,(0,0,0),(255,255,255))
			else:
				t = font.render(str(vals[i][j]),True,(0,0,0),(255,255,255))
				t = pygame.transform.scale(t,(50,50))
				surf.blit(t,(50 * i,50 * j))
			pygame.draw.rect(surf,(0,0,0),rect,2)
def judge(vals,puzzle):
	for i in range(len(vals)):
		for j in range(len(vals[i])):
			if(vals[i][j] == None or (vals[i][j] == '!' and (not puzzle[j][i]))):
				return False
	return True
def sweep(display,puzzle,x,y,w,h):
	dir = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]
	def _sweep(display,puzzle,x,y,w,h):
		dir = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]
		display[x][y] = 0
		for dx,dy in dir:
			tx,ty = x + dx,y + dy
			if(tx in range(h) and ty in range(w) and \
			   puzzle[ty][tx]):
				display[x][y] += 1
		return display
	if(display[x][y] not in (None,'!') or puzzle[y][x]):
		return display
	display = _sweep(display,puzzle,x,y,w,h)
	if(display[x][y] == 0):
		for dx,dy in dir:
			tx,ty = x + dx,y + dy
			if(tx in range(h) and ty in range(w)):
				display = sweep(display,puzzle,tx,ty,w,h)
	return display
def main():
	src = pygame.display.set_mode((50 * WIDTH,50 * HEIGHT))
	puzzle = generate(WIDTH,HEIGHT)
	display = []
	for i in range(HEIGHT):
		ls = []
		for j in range(WIDTH):
			ls.append(None)
		display.append(ls)
	while(1):
		pygame.display.update()
		src.fill((255,255,255))
		show(src,display)
		if(judge(display,puzzle)):
			pygame.display.update()
			showinfo('Congratulations!','Congratulations!You\'ve done it!')
			exit()
		for ev in pygame.event.get():
			if(ev.type == QUIT):
				exit()
			elif(ev.type == MOUSEBUTTONDOWN):
				x = ev.pos[0] // 50
				y = ev.pos[1] // 50
				if(ev.button == 3):
					if(display[x][y] == '!'):
						display[x][y] = None
					else:
						display[x][y] = '!'
				else:
					if(puzzle[y][x]):
						showinfo('Failed','You click a BOMB!')
						exit()
					else:
						display = sweep(display,puzzle,x,y,WIDTH,HEIGHT)
if(__name__ == '__main__'):
	main()

代码剖析

from tkinter.messagebox import showinfo
from pygame.locals import *
import tkinter as tk
import random
import pygame
base = tk.Tk()
base.withdraw()
pygame.init()
WIDTH = 10
HEIGHT = 10

导入库及初始化,其中变量WIDTHHEIGHT为方格的长和宽。

def generate(w,h):
	res = []
	for i in range(h):
		ls = []
		for j in range(w):
			ls.append(False)
		res.append(ls)
	bomb_total = random.randint(1,w * h // 4)
	for i in range(bomb_total):
		x = random.randint(0,w - 1)
		y = random.randint(0,h - 1)
		res[x][y] = True
	return res

随机生成地雷,其中

bomb_total = random.randint(1,w * h // 4)

中的

  • 1可以更改成任意小于等于方格数的数字,表示地雷的最小个数
  • w * h // 4可以更改为任意小于等于方格数的数字,表示地雷的最大个数
def show(surf,vals):
	font = pygame.font.Font('songti SC.TTF',100)
	for i in range(len(vals)):
		for j in range(len(vals[i])):
			x1,y1,x2,y2 = i * 50,j * 50,i * 50 + 50,j * 50 + 50
			rect = pygame.Rect((x1,y1,x2,y2))
			if(vals[i][j] == None):
				t = font.render(' ',True,(0,0,0),(255,255,255))
			else:
				t = font.render(str(vals[i][j]),True,(0,0,0),(255,255,255))
				t = pygame.transform.scale(t,(50,50))
				surf.blit(t,(50 * i,50 * j))
			pygame.draw.rect(surf,(0,0,0),rect,2)

这里与2048游戏中我使用的代码类似,其中增加的三行代码以及更改的几个数字的解释如下:

增加的几行为

			x1,y1,x2,y2 = i * 50,j * 50,i * 50 + 50,j * 50 + 50
			rect = pygame.Rect((x1,y1,x2,y2))
			// ......
			pygame.draw.rect(surf,(0,0,0),rect,2)

解释如下:

  • 第一行,定义画矩形的位置。(x1,y1)为第一组坐标,左上角。(x2,y2)为第二组坐标,右下角。示意图如下:在这里插入图片描述
  • 第二行,根据两组坐标确定一个 pygame.Rect位置描述对象
  • 第三行,根据第二行产生的位置描述对象画一个矩形

这样重复,就可以产生一个网格

更改的整数表示字符大小,尽量不要随意改变。

def judge(vals,puzzle):
	for i in range(len(vals)):
		for j in range(len(vals[i])):
			if(vals[i][j] == None or (vals[i][j] == '!' and (not puzzle[j][i]))):
				return False
	return True

判断游戏是否成功

这里认为满足如下两点的所有状态都可以认为游戏成功:

  1. 没有空格
  2. 所有!背后都是炸弹
def sweep(display,puzzle,x,y,w,h):
	dir = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]
	def _sweep(display,puzzle,x,y,w,h):
		dir = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]
		display[x][y] = 0
		for dx,dy in dir:
			tx,ty = x + dx,y + dy
			if(tx in range(h) and ty in range(w) and \
			   puzzle[ty][tx]):
				display[x][y] += 1
		return display
	if(display[x][y] not in (None,'!') or puzzle[y][x]):
		return display
	display = _sweep(display,puzzle,x,y,w,h)
	if(display[x][y] == 0):
		for dx,dy in dir:
			tx,ty = x + dx,y + dy
			if(tx in range(h) and ty in range(w)):
				display = sweep(display,puzzle,tx,ty,w,h)
	return display

使用类似深度优先搜索的方式实现点击效果
至于深度优先搜索是啥算法,出门左转百度

def main():
	src = pygame.display.set_mode((50 * WIDTH,50 * HEIGHT))
	puzzle = generate(WIDTH,HEIGHT)
	display = []
	for i in range(HEIGHT):
		ls = []
		for j in range(WIDTH):
			ls.append(None)
		display.append(ls)
	while(1):
		pygame.display.update()
		src.fill((255,255,255))
		show(src,display)
		if(judge(display,puzzle)):
			pygame.display.update()
			showinfo('Congratulations!','Congratulations!You\'ve done it!')
			exit()
		for ev in pygame.event.get():
			if(ev.type == QUIT):
				exit()
			elif(ev.type == MOUSEBUTTONDOWN):
				x = ev.pos[0] // 50
				y = ev.pos[1] // 50
				if(ev.button == 3):
					if(display[x][y] == '!'):
						display[x][y] = None
					else:
						display[x][y] = '!'
				else:
					if(puzzle[y][x]):
						showinfo('Failed','You click a BOMB!')
						exit()
					else:
						display = sweep(display,puzzle,x,y,WIDTH,HEIGHT)

这里分开剖析

def main():
	src = pygame.display.set_mode((50 * WIDTH,50 * HEIGHT))
	puzzle = generate(WIDTH,HEIGHT)
	display = []
	for i in range(HEIGHT):
		ls = []
		for j in range(WIDTH):
			ls.append(None)
		display.append(ls)

初始化变量:

  • src为窗口对象
  • puzzle为炸弹的分布情况
  • display为显示情况
	while(1):
		pygame.display.update()
		src.fill((255,255,255))
		show(src,display)
		if(judge(display,puzzle)):
			pygame.display.update()
			showinfo('Congratulations!','Congratulations!You\'ve done it!')
			exit()

刷新窗口,判断游戏结束

		for ev in pygame.event.get():
			if(ev.type == QUIT):
				exit()

事件循环开始,判断关闭窗口事件

			elif(ev.type == MOUSEBUTTONDOWN):
				x = ev.pos[0] // 50
				y = ev.pos[1] // 50
				if(ev.button == 3):
					if(display[x][y] == '!'):
						display[x][y] = None
					else:
						display[x][y] = '!'

判断右键键标记炸弹

				else:
					if(puzzle[y][x]):
						showinfo('Failed','You click a BOMB!')
						exit()
					else:
						display = sweep(display,puzzle,x,y,WIDTH,HEIGHT)

判断左键展示数字,踩雷扫雷结束游戏

if(__name__ == '__main__'):
	main()

运行游戏

项目github

项目github


作者

hit-road

拜拜,下课!

hit-road不定期跟新,不见不散!

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值