Python桌面版数独(二版)-增加4X4、6X6

增加选择4x4、6x6模式,以下是三种模式的不同解析:

  1. 4x4模式

    • 数独大小:4x4
    • 每个宫格大小:2x2
    • 数字范围:1-4
  2. 6x6模式

    • 数独大小:6x6
    • 每个宫格大小:2x3
    • 数字范围:1-6
  3. 9x9模式

    • 数独大小:9x9
    • 每个宫格大小:3x3
    • 数字范围:1-9

主要优化点:
4. 添加了模式选择下拉框,可以选择4x4、6x6、9x9模式
5. 根据选择的模式动态创建不同大小的棋盘
6. 生成不同大小的数独题目
7. 验证输入的合法性
8. 检查是否完成数独

以下为非完整代码,完整代码资源有下载


class SudokuGame:
    # 常量定义
    CELL_WIDTH = 3
    CELL_FONT = ('Arial', 18)
    ORIGINAL_COLOR = 'black'
    PLAYER_COLOR = 'blue'
    BG_COLOR = 'white'
    READONLY_BG_COLOR = 'lightgray'
    MIN_REMOVE_COUNT = 1  # 至少保留一个数字
    
    MODE_CONFIG = {
    "4x4": {"base": 2, "remove_count": 8, "size": 4},  # 4x4棋盘,每个宫格为2x2,数字范围1-4,移除数字数量为8个
    "6x6": {"base": 2, "remove_count": 20, "size": 6},  # 6x6棋盘,数字范围1-6,移除数字数量为20个
    "9x9": {"base": 3, "remove_count": 40, "size": 9}   # 9x9棋盘,数字范围1-9,移除数字数量为40个
}

    def __init__(self, root):
        self.root = root
        self.root.title("数独游戏")
        self.board = []
        self.original = []
        self.entries = [[None for _ in range(9)] for _ in range(9)]
        self.mode = "9x9"  # 默认模式
        self.create_mode_selection()
        self.create_widgets()

    def create_mode_selection(self):
        # 创建模式选择区域
        self.mode_frame = tk.Frame(self.root)
        self.mode_frame.grid(row=0, column=0, pady=10)

        tk.Label(self.mode_frame, text="选择模式:").pack(side="left", padx=5)
        
        self.mode_var = tk.StringVar(value="9x9")
        modes = ["4x4", "6x6", "9x9"]
        
        for mode in modes:
            tk.Radiobutton(self.mode_frame, text=mode, variable=self.mode_var, 
                          value=mode, command=self.update_mode).pack(side="left", padx=5)

    def update_mode(self):
        # 更新模式并生成新棋局
        self.mode = self.mode_var.get()
        self.clear_board()
        self.generate_sudoku()

    def clear_board(self):
        # 清理现有的输入框
        for row in range(9):
            for col in range(9):
                if self.entries[row][col]:
                    self.entries[row][col].destroy()
                    self.entries[row][col] = None

    def create_widgets(self):
        # 创建数独棋盘
        self.frame = tk.Frame(self.root)
        self.frame.grid(row=1, column=0, padx=10, pady=10)

        # 根据模式设置棋盘大小
        config = self.MODE_CONFIG.get(self.mode, self.MODE_CONFIG["9x9"])
        size = config["size"]

        for row in range(size):
            for col in range(size):
                entry = tk.Entry(self.frame, width=self.CELL_WIDTH, font=self.CELL_FONT, justify='center')
                entry.grid(row=row, column=col, padx=(0 if col % 3 != 2 else 5),
                           pady=(0 if row % 3 != 2 else 5))
                self.entries[row][col] = entry

        # 按钮
        self.btn_frame = tk.Frame(self.root)
        self.btn_frame.grid(row=2, column=0, pady=10)

        self.reset_button = tk.Button(self.btn_frame, text="重新开始本局", command=self.reset_board)
        self.reset_button.pack(side="left", padx=10)

        self.new_button = tk.Button(self.btn_frame, text="生成新棋局", command=self.generate_sudoku)
        self.new_button.pack(side="left", padx=10)

    def generate_sudoku(self):
        # 根据选择的模式生成数独
        config = self.MODE_CONFIG.get(self.mode, self.MODE_CONFIG["9x9"])
        base = config["base"]
        remove_count = config["remove_count"]
        size = config["size"]
        
        side = size  # 棋盘边长等于size

        def pattern(r, c): return (base * (r % base) + r // base + c) % side

        from random import sample

        def shuffle(s): return sample(s, len(s))

        rBase = range(base)
        rows = [g * base + r for g in shuffle(rBase) for r in shuffle(rBase)]
        cols = [g * base + c for g in shuffle(rBase) for c in shuffle(rBase)]
        nums = shuffle(range(1, size + 1))  # 数字范围根据棋盘大小调整

        # 创建棋盘时使用正确的尺寸
        board = [[0 for _ in range(side)] for _ in range(side)]
        
        # 填充棋盘
        for r in range(side):
            for c in range(side):
                board[r][c] = nums[pattern(r, c)]

        # 移除部分数字,生成题目
        squares = side * side
        # 确保不会尝试移除超过可用数量的数字
        remove_count = min(remove_count, squares - self.MIN_REMOVE_COUNT)  # 至少保留一个数字
        
        # 安全地随机移除数字
        available_positions = [(r, c) for r in range(side) for c in range(side) if r < side and c < side]
        if available_positions:
            # 确保至少保留一个数字
            safe_remove_count = min(remove_count, len(available_positions))
            for r, c in sample(available_positions, safe_remove_count):
                if r < side and c < side:  # 再次检查边界
                    board[r][c] = 0

        # 清空未使用区域
        self.clear_board()
        
        # 重新创建对应当前模式的输入框
        # 使用安全的size值
        current_size = config["size"]
        for row in range(current_size):
            for col in range(current_size):
                # 确保不会越界访问
                if row < len(self.entries) and col < len(self.entries[row]):
                    entry = tk.Entry(self.frame, width=self.CELL_WIDTH, font=self.CELL_FONT, justify='center')
                    entry.grid(row=row, column=col, padx=(0 if col % 3 != 2 else 5),
                               pady=(0 if row % 3 != 2 else 5))
                    entry.bind("<Key>", self.on_key)
                    self.entries[row][col] = entry

        self.board = board
        self.original = copy.deepcopy(board)
        self.update_gui()

    def update_gui(self):
        # 根据模式更新GUI
        config = self.MODE_CONFIG.get(self.mode, self.MODE_CONFIG["9x9"])
        size = config["base"] ** 2
        
        # 确保board已初始化
        if not self.board:
            return

        for row in range(size):
            for col in range(size):
                val = 0
                # 安全访问board元素
                if row < len(self.board) and col < len(self.board[row]):
                    val = self.board[row][col]
                
                entry = self.entries[row][col]
                if entry:
                    entry.delete(0, tk.END)
                    # 安全访问board元素
                    if row < len(self.board) and col < len(self.board[row]):
                        val = self.board[row][col]
                        if val != 0:
                            entry.insert(0, str(val))
                            entry.config(fg=self.ORIGINAL_COLOR, readonlybackground=self.READONLY_BG_COLOR)
                            entry.bind("<Key>", lambda e: "break")  # 不可编辑原始数字
                        else:
                            entry.config(fg=self.PLAYER_COLOR, bg=self.BG_COLOR)
                            entry.bind("<Key>", self.on_key)

    def on_key(self, event):
        widget = event.widget
        if event.char.isdigit() or event.keysym in ('BackSpace', 'Delete'):
            # 允许输入数字或删除
            pass
        else:
            return "break"

    def reset_board(self):
        self.board = copy.deepcopy(self.original)
        self.update_gui()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香蕉可乐荷包蛋

努力写有用的code

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值