当前位置:

首页 > Python打造视觉精美的数独小游戏实战记录

Python打造视觉精美的数独小游戏实战记录

一、前言 想用Python做点有趣的东西?数独游戏是个绝佳的练手项目。它逻辑清晰,规则简单,但实现起来却能让你把Python的基础语法和Pygame图形库玩个遍。 今天,我们就来动手打造一个视觉精美、交互流畅的数独小游戏。从生成谜题到绘制界面,再到处理鼠标键盘事件,整个过程就像搭积木一样,一步步把想

一、前言

想用Python做点有趣的东西?数独游戏是个绝佳的练手项目。它逻辑清晰,规则简单,但实现起来却能让你把Python的基础语法和Pygame图形库玩个遍。

今天,我们就来动手打造一个视觉精美、交互流畅的数独小游戏。从生成谜题到绘制界面,再到处理鼠标键盘事件,整个过程就像搭积木一样,一步步把想法变成现实。无论你是刚学完Python语法想找项目练手,还是对游戏开发感兴趣,这篇教程都能带你走完全程。

准备好了吗?让我们开始吧。

二、开发准备

2.1 所需环境

  • Python 3.6 或更高版本
  • Pygame库(负责图形界面和交互)

2.2 安装依赖

Pygame不是Python自带的,所以第一步就是安装它。打开你的命令行工具,输入下面这行命令,回车即可:

pip install pygame

安装过程通常很快。如果遇到网络问题,可以尝试加上国内镜像源,比如 pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple

三、项目结构设计

为了让代码清晰好维护,我们把项目拆成两个核心文件:

  • main.py:这是游戏的前端,负责一切你看得见的部分——窗口、网格、数字、颜色,以及处理你的鼠标点击和键盘输入。
  • build.py:这是游戏的后端引擎,负责生成数独谜题、验证你填的数字对不对。它只管逻辑,不管显示。

前后端分离,思路清晰,以后想加新功能或者改界面,也不会牵一发而动全身。

四、核心功能实现

4.1. 数独谜题生成与验证(build.py)

数独游戏的核心,首先得有一个合法的谜题。这里我们采用经典的递归回溯算法来生成一个完整的数独盘面,然后再随机“挖”掉一些格子,形成题目。

打开build.py,我们来实现这个逻辑引擎:

import random

def print_matrix(matrix):
    """打印矩阵,用于调试"""
    print('—'*19)
    for row in matrix:
        print('|'+' '.join([str(col) for col in row])+'|')
    print('—'*19)

def shuffle_number(_list):
    """随机打乱列表,用于生成不同的数独"""
    random.shuffle(_list)
    return _list

def check(matrix, i, j, number):
    """
    检查数字是否可以放置在指定位置
    规则:行、列、3x3子网格中不能有重复数字
    """
    # 检查行
    if number in matrix[i]:
        return False
    # 检查列
    if number in [row[j] for row in matrix]:
        return False
    # 检查3x3子网格
    group_i, group_j = int(i/3), int(j/3)
    if number in [matrix[i][j] for i in range(group_i*3, (group_i+1)*3) 
                 for j in range(group_j*3, (group_j+1)*3)]:
        return False
    return True

def build_game(matrix, i, j, number):
    """递归构建完整数独矩阵"""
    if i > 8 or j > 8:
        return matrix
    if check(matrix, i, j, number):
        # 创建矩阵副本进行修改
        _matrix = [[col for col in row] for row in matrix]
        _matrix[i][j] = number
        # 计算下一个位置
        next_i, next_j = (i+1, 0) if j == 8 else (i, j+1)
        # 尝试下一个位置的所有可能数字
        for _number in shuffle_number(number_list):
            __matrix = build_game(_matrix, next_i, next_j, _number)
            # 验证是否生成了完整有效的数独
            if __matrix and sum([sum(row) for row in __matrix]) == (sum(range(1,10)) * 9):
                return __matrix
    return None

def give_me_a_game(blank_size=9):
    """生成带空白的数独游戏"""
    # 生成完整数独
    matrix_all = build_game(matrix, 0, 0, random.choice(number_list))
    # 随机生成要空白的位置
    set_ij = set()
    while len(list(set_ij)) < blank_size:
        set_ij.add(f"{random.choice(range(9))},{random.choice(range(9))}")
    
    # 创建带空白的数独
    matrix_blank = [[col for col in row] for row in matrix_all]
    blank_ij = []
    for ij in list(set_ij):
        i, j = int(ij.split(',')[0]), int(ij.split(',')[1])
        blank_ij.append((i, j))
        matrix_blank[i][j] = 0
    
    return matrix_all, matrix_blank, blank_ij

# 全局变量
number_list = [1,2,3,4,5,6,7,8,9]
matrix = [([0]*9) for i in range(9)]

if __name__ == "__main__":
    # 测试生成数独
    print_matrix(build_game(matrix, 0, 0, random.choice(number_list)))

这段代码的妙处在于build_game函数。它从一个空盘面开始,尝试在每个格子填入数字。如果当前数字合法,就递归地去填下一个格子;如果走到死胡同(所有数字都试了都不行),就回溯到上一步。最终,它要么生成一个完美的数独答案,要么返回None。而give_me_a_game函数则负责在生成答案后,随机挖掉指定数量的格子,把答案、题目以及空白格的位置一起返回给前端。

4.2. 游戏界面与交互(main.py)

逻辑有了,接下来就是让它变得“好看”和“好玩”。main.py文件承载了所有关于视觉和交互的代码。

import sys
import pygame
from pygame.color import THECOLORS as COLORS
from build import print_matrix, give_me_a_game, check

def draw_background():
    """绘制游戏背景和网格"""
    # 白色背景
    screen.fill(COLORS['white'])
    
    # 绘制9x9网格,加粗绘制3x3大格子边界
    # 垂直线
    for i in range(10):
        line_width = 5 if i % 3 == 0 else 2
        pygame.draw.line(screen, COLORS['black'], 
                         (i*100, 0), (i*100, 900), line_width)
    
    # 水平线
    for i in range(10):
        line_width = 5 if i % 3 == 0 else 2
        pygame.draw.line(screen, COLORS['black'], 
                         (0, i*100), (900, i*100), line_width)

def draw_choose():
    """绘制当前选中的单元格高亮框"""
    # 绘制蓝色高亮框,留出边框
    pygame.draw.rect(screen, COLORS['blue'], 
                    (cur_j*100+5, cur_i*100+5, 100-10, 100-10), 0)

def check_win(matrix_all, matrix):
    """检查是否完成数独"""
    return matrix_all == matrix

def check_color(matrix, i, j):
    """检查数字是否符合规则,返回对应的颜色"""
    _matrix = [[col for col in row] for row in matrix]
    _matrix[i][j] = 0  # 临时清空当前位置以便检查
    if check(_matrix, i, j, matrix[i][j]):
        return COLORS['green']  # 合法数字显示绿色
    return COLORS['red']      # 非法数字显示红色

def draw_number():
    """绘制数独中的数字"""
    for i in range(len(MATRIX)):
        for j in range(len(MATRIX[0])):
            # 空白格子的数字颜色根据合法性变化,固定数字显示灰色
            _color = check_color(MATRIX, i, j) if (i,j) in BLANK_IJ else COLORS['gray']
            # 渲染数字,空值不显示
            txt = font80.render(
                str(MATRIX[i][j] if MATRIX[i][j] not in [0, '0'] else ''), 
                True, _color)
            x, y = j*100 + 30, i*100 + 10  # 居中显示
            screen.blit(txt, (x, y))

def draw_context():
    """绘制游戏状态信息"""
    txt = font100.render(
        f'Blank: {cur_blank_size}   Changes: {cur_change_size}', 
        True, COLORS['black'])
    screen.blit(txt, (10, 900))  # 显示在底部

if __name__ == "__main__":
    # 初始化pygame
    pygame.init()
    
    # 常量定义
    SIZE = [900, 1000]  # 窗口大小,额外100像素显示状态信息
    font80 = pygame.font.SysFont('Times', 80)   # 数字字体
    font100 = pygame.font.SysFont('Times', 90)  # 状态信息字体
    
    # 创建窗口
    screen = pygame.display.set_mode(SIZE)
    pygame.display.set_caption("数独小游戏")  # 设置窗口标题
    
    # 变量初始化
    cur_i, cur_j = 0, 0  # 当前选中的单元格
    cur_blank_size = int(sys.argv[1]) if len(sys.argv) > 1 else 10  # 空白数量,可通过命令行参数设置
    cur_change_size = 0  # 已修改次数
    
    # 生成数独游戏
    MATRIX_ANSWER, MATRIX, BLANK_IJ = give_me_a_game(blank_size=cur_blank_size)
    print(BLANK_IJ)
    print_matrix(MATRIX)
    
    # 主游戏循环
    running = True
    while running:
        # 事件处理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                break
            elif event.type == pygame.MOUSEBUTTONDOWN:
                # 鼠标点击选择单元格
                x, y = event.pos
                cur_j, cur_i = int(x / 100), int(y / 100)
                # 确保选择在有效范围内
                cur_i = max(0, min(8, cur_i))
                cur_j = max(0, min(8, cur_j))
            elif event.type == pygame.KEYUP:
                # 键盘输入数字
                if chr(event.key) in ['1','2','3','4','5','6','7','8','9'] and (cur_i, cur_j) in BLANK_IJ:
                    MATRIX[cur_i][cur_j] = int(chr(event.key))
                    # 更新空白数量
                    cur_blank_size = sum(1 for row in MATRIX for col in row if col in [0, '0'])
                    cur_change_size += 1
        
        # 绘制游戏元素
        draw_background()
        draw_choose()
        draw_number()
        draw_context()
        
        # 刷新屏幕
        pygame.display.flip()
        
        # 检查是否完成
        if check_win(MATRIX_ANSWER, MATRIX):
            print('恭喜你,完成了数独挑战!')
            break
    
    # 退出游戏
    pygame.quit()

代码看起来不少,但结构非常清晰。主循环while running是游戏的心脏,它不断做三件事:监听你的操作(事件处理)、根据当前状态重绘屏幕、判断游戏是否结束。几个绘图函数各司其职,把背景、网格、数字、高亮框和状态信息一层层画到屏幕上。

运行效果图:

Python打造视觉精美的数独小游戏实战记录

五、功能解析

5.1. 数独生成逻辑

  • 递归回溯build_game()函数是核心,它尝试所有可能的数字组合,利用递归深入,遇到矛盾则回溯,最终生成一个合法解。
  • 挖洞生成谜题give_me_a_game()函数在得到完整答案后,随机将指定数量的格子清零,并记录下这些空白格的位置,生成可玩的题目。
  • 实时验证check()函数是规则的守护者,确保你填入的每个数字都满足行、列、宫格内不重复的约束。

5.2. 游戏界面设计

  • 清晰的网格:用细线画9x9小格,用粗线区分3x3的宫格,这是数独的标准视觉呈现。
  • 视觉反馈:选中的格子有蓝色高亮;题目自带的固定数字是灰色的,不可更改;而你填入的数字,会实时检查——绿色代表合法,红色则提醒你与现有数字冲突了。
  • 状态提示:窗口底部实时显示还剩多少空白格,以及你已经修改了多少次,让你对自己的游戏进度一目了然。

5.3. 用户交互

  • 鼠标选择:点到哪,就选到哪,简单直观。
  • 键盘输入:选中空白格后,直接按数字键1-9即可填入,操作流畅。
  • 即时反馈:输入后颜色立刻变化,对错立判,学习成本极低。
  • 自动结束:当你填满所有格子且答案完全正确时,游戏会自动在控制台恭喜你,然后优雅退出。

六、游戏玩法

  1. 启动游戏:在命令行中运行程序。你可以指定难度(空白格数量),不指定则默认为10格。

    python main.py 20  # 生成一个有20个空白格的数独(更难)
    
  2. 选择格子:用鼠标点击你想填数字的格子,它会变成蓝色。

  3. 填入数字:直接按键盘上的数字键1到9。

  4. 观察反馈:填入的数字会显示颜色。绿色表示目前没有冲突,可以放心;红色则表示这个数字在当前行、列或宫格里重复了,需要修改。

  5. 赢得游戏:当所有空白格都被正确填满,游戏结束,控制台会弹出成功提示。

七、优化建议

一个基础版本完成了,但让它变得更好玩,还有很大的空间。这里有几个方向供你参考:

  1. 图形化难度选择:别再用命令行参数了,做个开始菜单,让玩家用鼠标点选“简单”、“中等”、“困难”。
  2. 加入计时器:在界面角落增加一个计时器,记录玩家通关用时,增加挑战性。
  3. 错误次数限制:比如只允许犯5次错误(输入红色数字算一次),增加紧张感。
  4. 提示功能:当玩家卡住时,可以按“H”键获得一个正确数字的提示。
  5. 美化UI:换掉纯色背景,使用更柔和的颜色、添加数字填入时的动画效果,甚至加入音效。
  6. 保存与读取:实现游戏进度的保存,下次打开可以接着玩。

八、总结

走到这里,一个由Python和Pygame驱动的数独游戏就从无到有地诞生了。这个项目虽然不大,但“麻雀虽小,五脏俱全”。你不仅实践了递归回溯算法来解决生成问题,还亲手用Pygame搭建了一个包含事件处理、图形绘制、状态管理的完整游戏循环。

更重要的是,你看到了清晰的代码结构如何让项目易于理解和扩展。无论是想增加新功能,还是修改游戏规则,现在你都有了坚实的基础。

希望这个亲手打造的游戏能带给你成就感,也为你打开Python游戏开发的大门。接下来的路,就由你自由探索和创造了。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
Python
相关文章 更多
Python安装后怎么打开:使用IDLE或命令行启动解释器
Python安装后怎么打开:使用IDLE或命令行启动解释器

刚在Windows安装好Python却不知道如何启动?本文详细演示如何通过开始菜单找到并打开IDLE集成开发环境,以及如何在PowerShell或命令提示符中使用python和py命令启动交互式解释器、运行.py脚本文件。包含退出解释器的方法及常见启动问题排查,帮助初学者快速验证安装成功并开始编写代码。

Windows系统Python安装教程:下载、勾选PATH及环境变量配置
Windows系统Python安装教程:下载、勾选PATH及环境变量配置

针对Windows初学者的Python安装实战指南。详细讲解如何从Python官网下载匹配架构的安装包,重点演示安装首屏勾选“Add python.exe to PATH”的关键操作,并提供使用python --version和py命令验证环境变量的具体步骤,帮助新手快速搭建开发环境并排查路径问题。

麒麟OS如何查看Python进程的运行状态
麒麟OS如何查看Python进程的运行状态

要想确认麒麟OS中Python程序的运行状态以及资源占用情况,我们可以这样做:用ps -ef | grep python来筛选进程;通过top命令,按P键排序查看实时负载;使用pgrep -f "script.py"精准获取PID;借助lsof -p PID验证文件打开状态。另外,还可以结合syst

Python在Debian上如何配置SSL证书
Python在Debian上如何配置SSL证书

在Debian系统上配置SSL证书通常涉及以下几个步骤:安装Web服务器:首先,你需要一个Web服务器,比如Apache或Nginx。这里以Apache为例。sudo apt updatesudo apt install apache2获取SSL证书:你可以从Let’s Encrypt免费获取SSL

统信UOS怎么安装Python开发环境
统信UOS怎么安装Python开发环境

要想让Python项目在统信UOS上正常运行,得先安装python3、python3-pip、python3-venv、python3-dev以及build-essential等组件。具体操作就是执行sudo apt install命令来一步到位完成安装,同时别忘了配置清华镜像源来给pip加速哦。在

纯Python方案实现中英文全文搜索
纯Python方案实现中英文全文搜索

在互联网上的各类网站中,无论大小,基本上都会有一个搜索框,用来给用户对内容进行搜索,小到站点搜索,大到搜索引擎搜索。从简单的来说,搜索功能确实很简单,一个简单的select语句就可以实现数据的搜索。而从复杂的来看,无论是搜索的精度还是搜索的效率,都是有很深的研究范围的。对于简单的搜索功能来说,一个s

Mac如何取消通过Python脚本运行的关机程序
Mac如何取消通过Python脚本运行的关机程序

立即在终端输入sudo shutdown -c取消倒计时关机,成功后显示“Shutdown cancelled”;若存在pmset重复任务,需再执行sudo pmset repeat cancel清除。Mac因Python脚本执行了os.system("sudo shutdown -h +10")或

Pythonasyncio异步并发与多固定出口IP调度实战
Pythonasyncio异步并发与多固定出口IP调度实战

之前写过一篇同步场景下用 Python 管理多个固定出口 IP 的实践(ExitPool + requests/httpx),覆盖了健康检查、故障转移和连接池复用。但在实际业务中,越来越多的场景用 asyncio 做高并发采集或批量接口调用——异步事件循环下多出口的管理方式和同步场景完全不同:单线程

Python在静态出口IP产品中的实战:从地址漂移巡检到多IP故障切换
Python在静态出口IP产品中的实战:从地址漂移巡检到多IP故障切换

写在前面:为什么静态出口 IP 不是"买了就行"不少团队在引入静态出口 IP 产品时,第一反应往往是:“地址配上去,这事就算完了。”可真到了真实业务里,静态出口 IP 真正能体现价值的地方,往往不在分配这一步,而在分配之后怎么管:地址有没有漂移,质量是否达标,某一条线路突然不可用时怎么切换,连接层又

using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。