python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python数独小游戏

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

作者:xcLeigh

数独是一种基于逻辑推理的数字填充谜题,目标是在9×9网格中填入1–9的数字,使得每行、每列及每个3×3子宫格内均无重复,这篇文章主要介绍了Python打造视觉精美的数独小游戏的相关资料,需要的朋友可以参考下

一、前言

Python作为一门简洁、易读、功能强大的编程语言,其基础语法是入门学习的核心。掌握好基础语法,能为后续的编程实践打下坚实的基础。本文将全面讲解Python3的基础语法知识,适合编程初学者系统学习。Python以其简洁优雅的语法和强大的通用性,成为当今最受欢迎的编程语言。本专栏旨在系统性地带你从零基础入门到精通Python核心。无论你是零基础小白还是希望进阶的专业开发者,都将通过清晰的讲解、丰富的实例和实战项目,逐步掌握语法基础、核心数据结构、函数与模块、面向对象编程、文件处理、主流库应用(如数据分析、Web开发、自动化)以及面向对象高级特性,最终具备独立开发能力和解决复杂问题的思维,高效应对数据分析、人工智能、Web应用、自动化脚本等广泛领域的实际需求。

数独是一款经典的逻辑推理数字游戏,通过填充数字1-9到9x9的网格中,使得每行、每列和每个3x3子网格都包含1-9的所有数字,不重复。本文将带大家使用Python的Pygame库实现一个视觉精美、交互友好的数独小游戏。

二、开发准备

2.1 所需环境

2.2安装依赖

首先确保安装了Pygame库,如果没有安装,可以使用pip命令安装:

pip install pygame

三、项目结构设计

我们将项目分为两个主要文件:

这种分离设计使代码结构更清晰,便于维护和扩展。

四 、核心功能实现

4.1. 数独谜题生成与验证(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)))

4.2. 游戏界面与交互(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()

运行效果图:

五 、 功能解析

5.1. 数独生成逻辑

5.2. 游戏界面设计

5.3. 用户交互

六、游戏玩法

  1. 运行程序,可通过命令行参数指定空白格数量(难度):

    python main.py 20  # 生成有20个空白格的数独
    
  2. 鼠标点击要填充的单元格(蓝色高亮显示)

  3. 按键盘1-9数字键填入数字

  4. 绿色数字表示符合数独规则,红色数字表示有冲突

  5. 填满所有空白且全部正确后,游戏结束并提示成功

七、优化建议

  1. 增加难度选择界面,无需通过命令行参数设置
  2. 添加计时器功能,记录完成时间
  3. 增加错误次数限制
  4. 添加提示功能
  5. 优化UI,增加更精美的背景和动画效果
  6. 保存游戏进度功能

八、总结

本项目通过Pygame实现了一个功能完整的数独游戏,包含了数独生成、规则验证、用户交互等核心功能。代码结构清晰,注释完善,便于理解和扩展。

通过这个项目,我们学习了递归回溯算法在数独生成中的应用,以及如何使用Pygame构建图形界面和处理用户交互。希望这个教程能帮助你入门Python游戏开发,也欢迎在此基础上进行更多创新和改进!

附录:扩展学习资源

  1. 官方资源

到此这篇关于Python打造视觉精美的数独小游戏的文章就介绍到这了,更多相关Python数独小游戏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文