编程入门的有趣实践:用Python玩转经典扫雷游戏

亲爱的编程爱好者们,你们还记得小时候在电脑上玩的那个小小的扫雷游戏吗?那个让我们无数次紧张刺激、小心翼翼地点开每一个格子的游戏。但这次,我们不是玩家,而是创造者!我们将用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所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img
img

二、Python必备开发工具

工具都帮大家整理好了,安装就可直接上手!img

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、Python视频合集

观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

五、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

六、面试宝典

在这里插入图片描述

在这里插入图片描述

简历模板在这里插入图片描述
若有侵权,请联系删除
  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值