python实现扫雷小游戏

1. 简介

扫雷是一个经典的小游戏,现在我们使用Python语言来编写一个扫雷小游戏。本文将会详细介绍如何实现扫雷游戏,包括界面设计和核心逻辑实现等方面。

2. 界面设计

2.1 Pygame

Pygame是Python编写游戏的一种库,他可以为我们提供游戏的框架,包括窗口、图像、声音等等。对于本文的扫雷游戏来说,我们需要使用Pygame来实现游戏界面。

首先我们需要安装Pygame库:

!pip install pygame

接下来我们就可以开始编写代码了。我们需要先导入Pygame库,如下所示:

import pygame

from pygame.locals import *

接下来我们需要初始化Pygame,如下所示:

pygame.init()

然后我们需要创建一个窗口,并设置窗口大小和标题,如下所示:

window = pygame.display.set_mode((800, 600))

pygame.display.set_caption('Minesweeper')

以上代码创建了一个800 * 600像素大小的窗口,并设置了窗口标题为“Minesweeper”。

2.2 界面元素

接下来我们需要在窗口中添加游戏界面元素。一个典型的扫雷游戏界面包括地图和计数器。

地图:扫雷游戏的核心就在于地图,我们可以使用二维数组来模拟一个M * N的地图。

计数器:计数器用于显示玩家还剩下多少雷没有被找到。

以上介绍了扫雷游戏界面的两个主要元素,接下来我们来一步步实现。

2.3. 地图

本游戏的核心是地图,我们需要使用二维数组来表示地图。在地图中,0代表没有雷,1代表有雷。我们还可以使用另一个二维数组作为标记,标记哪些位置已经被翻开,哪些位置还没有被翻开。

生成地图:我们可以使用Python的随机数函数来生成雷的位置。代码如下:

import random

def generate_map(m, n, num_mines):

map = [[0] * n for i in range(m)]

mines = random.sample(range(m * n), num_mines)

for mine in mines:

i = mine // n

j = mine % n

map[i][j] = 1

return map

以上代码中,generate_map函数用于生成地图,m和n分别代表地图的纵横长度,num_mines代表地雷数量。

接下来我们可以在游戏界面中显示地图。我们可以通过遍历地图数组,来决定每个格子显示的状态。例如,如果某个位置没有被翻开,则显示一个未知的方块;如果某个位置翻开并且有雷,则显示一个地雷;如果某个位置翻开并且没有雷,则显示周围雷的数量。

显示地图:我们可以使用pygame中的矩形来显示地图中的每个小格子。代码如下:

cell_size = 32  # 每个格子的大小

# 绘制地图

def draw_map(map):

rows = len(map)

cols = len(map[0])

for i in range(rows):

for j in range(cols):

rect = pygame.Rect(j * cell_size, i * cell_size, cell_size, cell_size)

if map[i][j] == 0: # 未翻开

pygame.draw.rect(window, (192, 192, 192), rect) # 灰色方块

pygame.draw.rect(window, (255, 255, 255), rect, 1) # 白色边框

elif map[i][j] == 1: # 有雷

pygame.draw.rect(window, (192, 192, 192), rect) # 灰色方块

pygame.draw.rect(window, (255, 255, 255), rect, 1) # 白色边框

draw_mine(rect) # 显示地雷

else: # 显示周围雷的数量

num = count_mines(map, i, j)

pygame.draw.rect(window, (192, 192, 192), rect) # 灰色方块

pygame.draw.rect(window, (255, 255, 255), rect, 1) # 白色边框

if num > 0:

draw_text(rect, str(num))

以上代码中,我们使用了两个函数来绘制地图中的方块:一个是draw_mine函数用于绘制地雷;一个是draw_text函数用于绘制数字。

2.4 计数器

我们需要在游戏界面上显示玩家还剩下多少雷没有被找到。我们可以使用一个全局的变量来存储还剩下多少雷没有被找到,并在游戏界面中将其显示出来。

显示计数器:计数器可以用Pygame的文字显示功能来实现,代码如下:

num_mines_left = num_mines  # 还剩下多少雷没有找到

font = pygame.font.SysFont(None, 32) # 字体

text_mines_left = font.render("Mines left: {}".format(num_mines_left), True, (255, 255, 255)) # 创建文本

window.blit(text_mines_left, (400, 10)) # 绘制文本

2.5 完整代码

下面是界面设计部分的完整代码:

import pygame

from pygame.locals import *

import random

pygame.init()

# 创建窗口

window = pygame.display.set_mode((800, 600))

pygame.display.set_caption('Minesweeper')

cell_size = 32 # 每个格子的大小

# 字体

font = pygame.font.SysFont(None, 32)

# 生成地图

def generate_map(m, n, num_mines):

map = [[0] * n for i in range(m)]

mines = random.sample(range(m * n), num_mines)

for mine in mines:

i = mine // n

j = mine % n

map[i][j] = 1

return map

# 计算某个位置周围的雷的数量

def count_mines(map, i, j):

rows = len(map)

cols = len(map[0])

num = 0

for r in range(max(i-1, 0), min(i+2, rows)):

for c in range(max(j-1, 0), min(j+2, cols)):

if map[r][c] == 1:

num += 1

return num

# 绘制地雷

def draw_mine(rect):

x, y, w, h = rect

pygame.draw.circle(window, (0, 0, 0), (x + w // 2, y + h // 2), cell_size // 4)

# 绘制文本

def draw_text(rect, text):

x, y, w, h = rect

text_surface = font.render(text, True, (0, 0, 0))

text_rect = text_surface.get_rect()

text_rect.center = (x + w // 2, y + h // 2)

window.blit(text_surface, text_rect)

# 绘制地图

def draw_map(map):

rows = len(map)

cols = len(map[0])

for i in range(rows):

for j in range(cols):

rect = pygame.Rect(j * cell_size, i * cell_size, cell_size, cell_size)

if map[i][j] == 0: # 未翻开

pygame.draw.rect(window, (192, 192, 192), rect) # 灰色方块

pygame.draw.rect(window, (255, 255, 255), rect, 1) # 白色边框

elif map[i][j] == 1: # 有雷

pygame.draw.rect(window, (192, 192, 192), rect) # 灰色方块

pygame.draw.rect(window, (255, 255, 255), rect, 1) # 白色边框

draw_mine(rect) # 显示地雷

else: # 显示周围雷的数量

num = count_mines(map, i, j)

pygame.draw.rect(window, (192, 192, 192), rect) # 灰色方块

pygame.draw.rect(window, (255, 255, 255), rect, 1) # 白色边框

if num > 0:

draw_text(rect, str(num))

# 主循环

def main_loop():

# 生成地图

num_rows = 16

num_cols = 16

num_mines = 40

map = generate_map(num_rows, num_cols, num_mines)

while True:

# 事件处理

for event in pygame.event.get():

if event.type == QUIT:

pygame.quit()

sys.exit()

# 绘制地图

draw_map(map)

# 显示计数器

num_mines_left = num_mines # 还剩下多少雷没有找到

text_mines_left = font.render("Mines left: {}".format(num_mines_left), True, (255, 255, 255))

window.blit(text_mines_left, (400, 10))

# 更新屏幕

pygame.display.update()

# 运行游戏

if __name__ == '__main__':

main_loop()

3. 核心逻辑实现

3.1 点击事件

我们需要实现翻开某个格子的操作,也就是在游戏中点击某个格子后,该格子会出现对应的数字或地雷。

点击事件:我们可以使用pygame的事件处理机制来检测鼠标点击事件。代码如下:

def main_loop():

# 生成地图

num_rows = 16

num_cols = 16

num_mines = 40

map = generate_map(num_rows, num_cols, num_mines)

while True:

# 事件处理

for event in pygame.event.get():

if event.type == QUIT:

pygame.quit()

sys.exit()

elif event.type == MOUSEBUTTONUP:

if event.button == 1: # 左键

x, y = event.pos

i = y // cell_size

j = x // cell_size

if map[i][j] == 0: # 未翻开

map[i][j] = 2 # 已标记

# 绘制地图

draw_map(map)

# 显示计数器

num_mines_left = num_mines # 还剩下多少雷没有找到

text_mines_left = font.render("Mines left: {}".format(num_mines_left), True, (255, 255, 255))

window.blit(text_mines_left, (400, 10))

# 更新屏幕

pygame.display.update()

以上代码中,我们检测到鼠标左键被点击后,获取鼠标点击的坐标,并根据坐标计算出点击的格子的位置。如果该位置未翻开,则将该位置标记为2(已标记,未翻开)。下一步,我们需要实现将某个格子翻开的操作。

3.2 翻开格子

我们需要实现如下操作:当未翻开的格子被点击后,如果该位置没有雷,则翻开该位置,并显示周围8个位置中雷的数量;如果该位置有雷,则游戏失败。

翻开格子:我们可以在之前检测到鼠标点击事件的代码中,添加如下代码来实现翻开格子的操作:

elif event.type == MOUSEBUTTONUP:

if event.button == 1: # 左键

x, y = event.pos

i = y // cell_size

j = x // cell_size

if map[i][j] == 0: # 未翻开

if count_mines(map, i, j) == 0: # 周围没有雷,翻开周围8个格子

flip_empty(map, i, j)

elif map[i][j] == 1: # 有雷,游戏结束

gameover()

else: # 显示周围雷的数量

map[i][j] = count_mines(map, i, j)

以上代码中,我们添加了一个flip_empty函数用于翻开周围8个位置中没有雷的格子,并添加了一个gameover函数用于在游戏结束时显示“Game Over”。

翻开周围的空格:我们可以使用递归的方式来翻开周围的空格,代码如下所示:

def flip_empty(map, i, j):

rows = len(map)

cols = len(map[0])

if i >= 0 and i < rows and j >= 0 and j < cols and map[i][j] == 0:

map[i][j] = count_mines(map, i, j)

if map[i][j] == 0:

flip_empty(map, i-1, j-1)

flip_empty(map, i-1, j)

flip_empty(map, i-1, j+1)

flip_empty(map, i, j-1)

flip_empty(map, i, j+1)

flip_empty(map, i+1, j-1)

flip_empty(map, i+1, j)

flip_empty(map, i+1, j+1)

以上代码中,我们首先检查该位置是否在地图范围内并且是否为0,如果是,我们就将该位置的值设置为周围雷的数量。如果该位置周围没有雷,我们就递归地翻开周围的8个位置。

游戏结束:我们可以使用Pygame的文字显示功能来在游戏结束后显示“Game Over”。代码如下所示:

def gameover():

text_game_over = font.render("Game Over", True, (255, 0, 0))

window.blit(text_game_over, (400, 30))

3.3 判断游戏胜利

后端开发标签