亲爱的编程爱好者们,你们还记得小时候在电脑上玩的那个小小的扫雷游戏吗?那个让我们无数次紧张刺激、小心翼翼地点开每一个格子的游戏。但这次,我们不是玩家,而是创造者!我们将用Python来重新打造扫雷这个经典游戏,让你在编程的世界里找到童年的影子。不论你是Python初学者还是资深开发者,这个项目都将给你带来新的挑战和乐趣。想象一下,你的一行行代码变成了一个有趣的游戏,这不仅是学习编程的最好方式,也是展示你技能的舞台。让我们开始这段旅程,一起探索编程的魔法,用代码书写乐趣!
游戏规则
扫雷,一个大家耳熟能详的游戏,目标是找出所有没有雷的格子,同时不触碰任何雷。每个数字代表周围八个格子中雷的数量。玩家需要用逻辑和直觉来避开雷区。
使用库介绍
-
turtle: 一个简单的图形绘制库,用于绘制游戏界面和交互。
-
random: 用于生成雷区。
-
math: 提供基本的数学运算,比如向下取整。
代码示例
接下来是我们的代码部分。代码首先设置了游戏的基本参数,比如网格大小、格子数等。然后,我们用Turtle来绘制网格,处理玩家的点击事件,以及标记雷区和揭示周围雷数的逻辑。
from turtle import *
from math import floor
from random import randint
# 初始化游戏参数
n = 10 # 游戏网格的行/列数
gz = 40 # 每个格子的大小
bc = n * gz # 计算整个游戏板的尺寸
win = False # 游戏胜利标志
dead = False # 游戏失败标志
can_start = True # 是否可以开始新游戏
fx = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]] # 用于检测周围8个方向
booms = randint(n * n // 10, n * n // 2) # 随机生成雷的数量
d = [] # 存储雷的位置
m = [] # 存储标记的位置
c = [] # 存储已经点击的格子
b = [] # 存储每个格子周围的雷数
# 初始化绘图的turtle
t = Turtle()
t.ht()
t.up()
t.speed(0)
title("海水加糖的扫雷游戏") # 设置游戏窗口标题
# 初始化用于显示信息的turtle
judge = Turtle()
judge.ht()
judge.up()
judge.speed(0)
# 绘制游戏网格的函数
def draw():
t.clear()
t.seth(0)
t.color("black")
t.goto(-bc / 2, bc / 2)
# 绘制水平线
for i in range(n + 1):
t.down()
t.fd(bc)
t.bk(bc)
t.up()
t.goto(-bc / 2, bc / 2 - (i + 1) * gz)
# 绘制垂直线
t.goto(-bc / 2, bc / 2)
t.rt(90)
for i in range(n + 1):
t.down()
t.fd(bc)
t.bk(bc)
t.up()
t.goto(-bc / 2 + (i + 1) * gz, bc / 2)
# 显示剩余雷数的函数
def write_booms():
judge.clear()
judge.goto(-gz, bc / 2 + gz - gz / 8)
judge.color("red")
judge.dot(20)
judge.goto(0, bc / 2 + gz / 2)
judge.write(": {}".format(booms), align="center", font=("Kai", 30, "bold"))
# 初始化列表的函数
def init_list(n, default=0):
return [[default for _ in range(n)] for _ in range(n)]
# 打印列表用于调试的函数
def print_list(lines):
for line in lines:
print(' '.join(map(str, line)))
print()
# 将鼠标点击的坐标转换为网格索引
def xytoij(x, y):
ix = floor(x / gz) * gz
iy = floor(y / gz) * gz
j = (ix + bc / 2) / gz
i = (bc / 2 - iy) / gz - 1
return int(i), int(j)
# 将网格索引转换为坐标的函数
def ijtoxy(i, j):
x = -bc / 2 + gz / 2 + j * gz
y = bc / 2 - gz / 2 - i * gz - gz / 4
return x, y
# 根据周围的雷数设置颜色的函数
def set_color(booms):
colors = ["green", "blue", "brown", "orange", "red", "purple"]
t.color(colors[min(booms, len(colors) - 1)])
# 开始游戏的函数
def start():
global d, m, c, b, booms, can_start, win, dead
if can_start:
win = False
dead = False
can_start = False
draw()
d = init_list(n) # 雷的位置
m = init_list(n) # 标记的位置
c = init_list(n) # 已点击的格子
b = init_list(n) # 周围的雷数
booms = randint(n * n // 10, n * n // 2)
for k in range(booms):
i, j = randint(0, n - 1), randint(0, n - 1)
d[i][j] = 1
write_booms()
for i in range(n):
for j in range(n):
if d[i][j] == 1:
b[i][j] = -1
for f in fx:
ni, nj = i + f[0], j + f[1]
if 0 <= ni < n and 0 <= nj < n and b[ni][nj] != -1:
b[ni][nj] += 1
# 检查周围的函数
def check_around(i, j):
cnt = sum(d[i + f[0]][j + f[1]] == 1 and m[i + f[0]][j + f[1]] == 1 for f in fx if 0 <= i + f[0] < n and 0 <= j + f[1] < n)
return b[i][j] == cnt
# 自动点击周围格子的递归函数
def check_and_auto_click(i, j):
if 0 <= i < n and 0 <= j < n and check_around(i, j):
for f in fx:
ni, nj = i + f[0], j + f[1]
if 0 <= ni < n and 0 <= nj < n and b[ni][nj] != -1 and c[ni][nj] == 0:
c[ni][nj] = 1
check_and_auto_click(ni, nj)
x, y = ijtoxy(ni, nj)
t.goto(x, y)
set_color(b[ni][nj])
t.write(b[ni][nj], align="center", font=("Arial", 20, "normal"))
# 检查是否赢得游戏的函数
def check_win():
return all(m[i][j] == d[i][j] for i in range(n) for j in range(n))
# 左键点击处理的函数
def click(x, y):
global dead, win, can_start
if not dead and not win:
i, j = xytoij(x, y)
if 0 <= i < n and 0 <= j < n and c[i][j] == 0:
c[i][j] = 1
if d[i][j] == 1:
t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2)
t.color("red")
t.dot(20)
dead = True
can_start = True
judge.clear()
judge.color("red")
judge.write("Failed, press Space to restart.", align="center", font=("Kai", 40, "bold"))
else:
t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 4)
set_color(b[i][j])
t.write(b[i][j], align="center", font=("Arial", 20, "normal"))
check_and_auto_click(i, j)
if check_win():
win = True
can_start = True
judge.clear()
judge.color("green")
judge.write("Success, press Space to restart.", align="center", font=("Kai", 40, "bold"))
# 右键标记处理的函数
def mark(x, y):
global booms, win, can_start
if not dead and not win:
i, j = xytoij(x, y)
if 0 <= i < n and 0 <= j < n and c[i][j] == 0:
t.goto(floor(x / gz) * gz + gz / 2, floor(y / gz) * gz + gz / 2)
if m[i][j] == 0:
m[i][j] = 1
t.color("green")
t.dot(20)
booms -= 1
else:
m[i][j] = 0
t.color("white")
t.dot(22)
booms += 1
write_booms()
if check_win():
win = True
can_start = True
judge.clear()
judge.color("green")
judge.write("Success, press Space to restart.", align="center", font=("Kai", 40, "bold"))
# 启动游戏
start()
# 设置屏幕和鼠标点击事件
screen = Screen()
screen.onscreenclick(click, 1)
screen.onscreenclick(mark, 2)
screen.onkey(start, "space")
screen.listen()
done()
代码解析
-
draw() 函数用来绘制网格,这是游戏界面的基础。
-
click() 和 mark() 函数处理玩家的点击动作,判断游戏的输赢。
-
start() 函数初始化游戏,随机放置雷区。
-
check_and_auto_click() 递归地揭示周围无雷的区域,模拟了扫雷游戏中的自动揭示逻辑。
效果展示
探索与改进
-
加入难度选择功能,让玩家可以根据自己的水平选择不同的难度。
-
增加计时器,记录玩家完成游戏所用的时间。
-
使用更高级的图形库,如Pygame,来提升游戏的视觉效果和响应速度。
结语
通过这个项目,我们不仅学会了基本的Python编程和图形处理,还能深入理解逻辑运算和事件处理的原理。这是一个极好的实战项目,可以让初学者通过实践加深理解,也为更有经验的程序员提供了一个有趣的挑战。编程不只是关于写代码,更是关于解决问题和创造有趣的东西!欢迎大家尝试这个项目,也可以在评论区分享你们的作品和心得!
感兴趣的小伙伴,全套Python学习资料免费赠送,具体看这里。
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
工具都帮大家整理好了,安装就可直接上手!
三、最新Python学习笔记
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试宝典
简历模板
