Python 数独小游戏进阶实现

下面我将实现一个具有自动填数和错误检测功能的数独游戏。该程序包含以下核心功能:

  1. 自动填入唯一可能数字
  2. 实时错误检测
  3. 可视化界面
import pygame
import sys
import numpy as np

# 初始化pygame
pygame.init()

# 游戏常量
WIDTH, HEIGHT = 540, 600
GRID_SIZE = 9
CELL_SIZE = WIDTH // GRID_SIZE
FONT_SIZE = 36
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
RED = (255, 0, 0)
BLUE = (0, 120, 255)

class SudokuGame:
    def __init__(self):
        self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
        pygame.display.set_caption("数独游戏")
        self.font = pygame.font.SysFont(None, FONT_SIZE)
        self.small_font = pygame.font.SysFont(None, FONT_SIZE - 10)
        self.board = np.zeros((GRID_SIZE, GRID_SIZE), dtype=int)
        self.original = None
        self.selected = None
        self.errors = set()
        
        # 初始化数独板
        self.initialize_board()
        
    def initialize_board(self):
        """初始化数独板"""
        # 示例数独(0表示空格)
        self.board = np.array([
            [5, 3, 0, 0, 7, 0, 0, 0, 0],
            [6, 0, 0, 1, 9, 5, 0, 0, 0],
            [0, 9, 8, 0, 0, 0, 0, 6, 0],
            [8, 0, 0, 0, 6, 0, 0, 0, 3],
            [4, 0, 0, 8, 0, 3, 0, 0, 1],
            [7, 0, 0, 0, 2, 0, 0, 0, 6],
            [0, 6, 0, 0, 0, 0, 2, 8, 0],
            [0, 0, 0, 4, 1, 9, 0, 0, 5],
            [0, 0, 0, 0, 8, 0, 0, 7, 9]
        ])
        self.original = self.board.copy()
        self.errors = set()
    
    def is_valid(self, row, col, num):
        """检查在(row, col)位置填入num是否合法"""
        # 检查行
        if num in self.board[row]:
            return False
        
        # 检查列
        if num in self.board[:, col]:
            return False
        
        # 检查3x3宫格
        box_row, box_col = row // 3 * 3, col // 3 * 3
        if num in self.board[box_row:box_row+3, box_col:box_col+3]:
            return False
        
        return True
    
    def find_empty(self):
        """找到下一个空格位置"""
        for i in range(GRID_SIZE):
            for j in range(GRID_SIZE):
                if self.board[i][j] == 0:
                    return (i, j)
        return None
    
    def auto_fill_single(self):
        """自动填入唯一可能数字"""
        filled = False
        for i in range(GRID_SIZE):
            for j in range(GRID_SIZE):
                if self.board[i][j] == 0:
                    possible = []
                    for num in range(1, 10):
                        if self.is_valid(i, j, num):
                            possible.append(num)
                    
                    # 如果只有一个可能数字
                    if len(possible) == 1:
                        self.board[i][j] = possible[0]
                        filled = True
        return filled
    
    def detect_errors(self):
        """检测所有错误位置"""
        self.errors = set()
        
        # 检查行
        for i in range(GRID_SIZE):
            seen = set()
            for j in range(GRID_SIZE):
                num = self.board[i][j]
                if num != 0:
                    if num in seen:
                        for k in range(GRID_SIZE):
                            if self.board[i][k] == num:
                                self.errors.add((i, k))
                    else:
                        seen.add(num)
        
        # 检查列
        for j in range(GRID_SIZE):
            seen = set()
            for i in range(GRID_SIZE):
                num = self.board[i][j]
                if num != 0:
                    if num in seen:
                        for k in range(GRID_SIZE):
                            if self.board[k][j] == num:
                                self.errors.add((k, j))
                    else:
                        seen.add(num)
        
        # 检查3x3宫格
        for box_i in range(0, 9, 3):
            for box_j in range(0, 9, 3):
                seen = set()
                positions = []
                for i in range(box_i, box_i+3):
                    for j in range(box_j, box_j+3):
                        num = self.board[i][j]
                        positions.append((i, j))
                        if num != 0:
                            if num in seen:
                                for pos in positions:
                                    if self.board[pos[0]][pos[1]] == num:
                                        self.errors.add(pos)
                            else:
                                seen.add(num)
    
    def draw(self):
        """绘制游戏界面"""
        self.screen.fill(WHITE)
        
        # 绘制网格线
        for i in range(GRID_SIZE + 1):
            line_width = 4 if i % 3 == 0 else 1
            pygame.draw.line(self.screen, BLACK, (0, i * CELL_SIZE), (WIDTH, i * CELL_SIZE), line_width)
            pygame.draw.line(self.screen, BLACK, (i * CELL_SIZE, 0), (i * CELL_SIZE, WIDTH), line_width)
        
        # 绘制数字
        for i in range(GRID_SIZE):
            for j in range(GRID_SIZE):
                num = self.board[i][j]
                if num != 0:
                    color = BLUE if self.original[i][j] == 0 else BLACK
                    text = self.font.render(str(num), True, color)
                    text_rect = text.get_rect(center=(j * CELL_SIZE + CELL_SIZE // 2, 
                                                     i * CELL_SIZE + CELL_SIZE // 2))
                    self.screen.blit(text, text_rect)
        
        # 绘制错误标记
        for (i, j) in self.errors:
            pygame.draw.rect(self.screen, RED, 
                            (j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE), 3)
        
        # 绘制选中单元格
        if self.selected:
            i, j = self.selected
            pygame.draw.rect(self.screen, BLUE, 
                            (j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE), 3)
        
        # 绘制按钮
        pygame.draw.rect(self.screen, GRAY, (180, HEIGHT - 50, 180, 40))
        text = self.small_font.render("自动填数", True, BLACK)
        self.screen.blit(text, (250, HEIGHT - 40))
        
        pygame.display.flip()
    
    def run(self):
        """运行游戏主循环"""
        running = True
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                
                if event.type == pygame.MOUSEBUTTONDOWN:
                    x, y = pygame.mouse.get_pos()
                    
                    # 点击网格
                    if y < WIDTH:
                        col = x // CELL_SIZE
                        row = y // CELL_SIZE
                        self.selected = (row, col)
                    
                    # 点击按钮
                    elif 180 <= x <= 360 and HEIGHT-50 <= y <= HEIGHT-10:
                        self.auto_fill_single()
                
                if event.type == pygame.KEYDOWN and self.selected:
                    row, col = self.selected
                    # 只能修改原始为0的位置
                    if self.original[row][col] == 0:
                        if event.key == pygame.K_1: self.board[row][col] = 1
                        if event.key == pygame.K_2: self.board[row][col] = 2
                        if event.key == pygame.K_3: self.board[row][col] = 3
                        if event.key == pygame.K_4: self.board[row][col] = 4
                        if event.key == pygame.K_5: self.board[row][col] = 5
                        if event.key == pygame.K_6: self.board[row][col] = 6
                        if event.key == pygame.K_7: self.board[row][col] = 7
                        if event.key == pygame.K_8: self.board[row][col] = 8
                        if event.key == pygame.K_9: self.board[row][col] = 9
                        if event.key == pygame.K_DELETE or event.key == pygame.K_BACKSPACE:
                            self.board[row][col] = 0
            
            # 实时错误检测
            self.detect_errors()
            
            # 绘制界面
            self.draw()
        
        pygame.quit()
        sys.exit()

if __name__ == "__main__":
    game = SudokuGame()
    game.run()

功能说明

  1. 自动填数功能

    • 点击"自动填数"按钮,程序会扫描所有空格
    • 当某个空格只有一个可能数字时,自动填入该数字
    • 使用auto_fill_single()方法实现
  2. 错误检测系统

    • 实时检查行、列和3×3宫格内的数字冲突
    • 冲突数字会用红色方框标记
    • 使用detect_errors()方法实现
  3. 游戏操作

    • 点击选择单元格
    • 按数字键1-9填入数字
    • 按Delete键清除数字
    • 蓝色数字表示玩家填入的数字
    • 黑色数字表示初始题目数字
  4. 数独规则验证

    • 使用is_valid()方法检查填入数字的合法性
    • 验证行、列和宫格内的唯一性

使用说明

  1. 运行程序后,会显示初始数独棋盘
  2. 点击单元格后按数字键填入数字
  3. 点击"自动填数"按钮可自动填入唯一可能的数字
  4. 冲突的数字会被红色方框标记
  5. 按ESC键或关闭窗口退出游戏

这个实现包含了完整的数独游戏功能,特别适合用于学习Python游戏开发和算法设计。自动填数功能使用了简单推理算法,错误检测系统则确保玩家遵循数独规则。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐