Python桌面版数独游戏(三版)-增加难易度模式

数独游戏难度模式解析

在数独游戏中,难度通常由已知数字(提示数)的数量决定。难度越高,已知数字越少,玩家需要推理的步骤越多。以下是不同模式下的算法区别和核心代码解析。
在这里插入图片描述


文章目录

      • 数独游戏难度模式解析
      • 1. **难度模式配置**
        • **1.1 难度与移除数量的关系**
        • **1.2 难度选择界面**
      • 2. **核心算法解析**
        • **2.1 数独生成算法**
        • **2.2 数字移除算法**
      • 3. **完整代码在资源中可以下载**
      • 4. **总结**

1. 难度模式配置

我们定义了三种难度模式:

  • 简单模式:提示数字较多,玩家容易完成。
  • 中等模式:提示数字适中,需要一定的推理能力。
  • 困难模式:提示数字较少,需要较强的逻辑推理。
1.1 难度与移除数量的关系
  • 简单模式:移除较少数字,保留较多提示。
  • 中等模式:移除中等数量数字,提示适中。
  • 困难模式:移除较多数字,提示较少。
MODE_CONFIG = {"9x9": {"base": 3, "remove_count": {"easy": 30, "medium": 40, "hard": 50}, "size": 9},  # 9x9棋盘,数字范围1-9"6x6": {"base": 2, "remove_count": {"easy": 15, "medium": 20, "hard": 25}, "size": 6},  # 6x6棋盘,数字范围1-6"4x4": {"base": 2, "remove_count": {"easy": 5, "medium": 8, "hard": 10}, "size": 4}    # 4x4棋盘,数字范围1-4
}
1.2 难度选择界面

我们为难度模式添加了选择界面,用户可以选择不同的难度:

def create_difficulty_selection(self):# 创建难度选择区域self.difficulty_frame = tk.Frame(self.root)self.difficulty_frame.grid(row=0, column=1, pady=10)tk.Label(self.difficulty_frame, text="选择难度:").pack(side="left", padx=5)self.difficulty_var = tk.StringVar(value="easy")for difficulty in ["easy", "medium", "hard"]:tk.Radiobutton(self.difficulty_frame, text=self.DIFFICULTY_LABELS[difficulty], variable=self.difficulty_var, value=difficulty, command=self.update_difficulty).pack(side="left", padx=5)

2. 核心算法解析

2.1 数独生成算法

数独生成算法基于 拉丁方阵(Latin Square) 的概念,通过以下步骤生成:

  1. 模式函数:用于生成数独的初始填充。
  2. 随机化:通过随机化行、列和数字,确保生成的数独是随机的。
  3. 移除数字:根据难度设置移除一定数量的数字,生成题目。
def pattern(r, c): return (base * (r % base) + r // base + c) % sidefrom random import sampledef 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)]
2.2 数字移除算法

数字移除是根据难度设置的参数进行的,确保不会移除所有数字,并且不会超出棋盘范围:

# 移除部分数字,生成题目
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

3. 完整代码在资源中可以下载

以下是包含难度模式的部分代码:


class SudokuGame:# 常量定义CELL_WIDTH = 3CELL_FONT = ('Arial', 18)ORIGINAL_COLOR = 'black'PLAYER_COLOR = 'blue'BG_COLOR = 'white'READONLY_BG_COLOR = 'lightgray'MIN_REMOVE_COUNT = 1  # 至少保留一个数字MODE_CONFIG = {"9x9": {"base": 3, "remove_count": {"easy": 30, "medium": 40, "hard": 50}, "size": 9},  # 9x9棋盘,数字范围1-9"6x6": {"base": 2, "remove_count": {"easy": 15, "medium": 20, "hard": 25}, "size": 6},  # 6x6棋盘,数字范围1-6"4x4": {"base": 2, "remove_count": {"easy": 5, "medium": 8, "hard": 10}, "size": 4}    # 4x4棋盘,数字范围1-4}DIFFICULTY_LABELS = {"easy": "简单","medium": "中等","hard": "困难"}def __init__(self, root):self.root = rootself.root.title("数独游戏")self.board = []self.original = []self.entries = [[None for _ in range(9)] for _ in range(9)]self.mode = "9x9"  # 默认模式改为9x9self.difficulty = "easy"  # 默认难度self.create_mode_selection()self.create_difficulty_selection()self.create_widgets()self.generate_sudoku()  # 默认生成9x9棋盘和棋局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 create_difficulty_selection(self):# 创建难度选择区域self.difficulty_frame = tk.Frame(self.root)self.difficulty_frame.grid(row=0, column=1, pady=10)tk.Label(self.difficulty_frame, text="选择难度:").pack(side="left", padx=5)self.difficulty_var = tk.StringVar(value="easy")for difficulty in ["easy", "medium", "hard"]:tk.Radiobutton(self.difficulty_frame, text=self.DIFFICULTY_LABELS[difficulty], variable=self.difficulty_var, value=difficulty, command=self.update_difficulty).pack(side="left", padx=5)def update_mode(self):# 更新模式self.mode = self.mode_var.get()def update_difficulty(self):# 更新难度self.difficulty = self.difficulty_var.get()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] = Nonedef create_widgets(self):# 创建数独棋盘self.frame = tk.Frame(self.root)self.frame.grid(row=1, column=0, padx=10, pady=10, columnspan=2)# 根据模式设置棋盘大小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, columnspan=2)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"][self.difficulty]size = config["size"]side = size  # 棋盘边长等于sizedef pattern(r, c): return (base * (r % base) + r // base + c) % sidefrom random import sampledef 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] = entryself.board = boardself.original = copy.deepcopy(board)self.update_gui()def update_gui(self):# 根据模式更新GUIconfig = self.MODE_CONFIG.get(self.mode, self.MODE_CONFIG["9x9"])size = config["base"] ** 2# 确保board已初始化if not self.board:returnfor 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.widgetif event.char.isdigit() or event.keysym in ('BackSpace', 'Delete'):# 允许输入数字或删除passelse:return "break"def reset_board(self):self.board = copy.deepcopy(self.original)self.update_gui()

4. 总结

  • 难度模式:通过配置文件定义不同模式下的难度参数,确保代码的可维护性。
  • 数独生成算法:基于拉丁方阵生成数独,并通过随机化确保生成的数独是随机的。
  • 数字移除算法:根据难度设置移除数字的数量,并确保不会移除所有数字。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89838.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s查看某个pod的svc

在 Kubernetes 中&#xff0c;要查看与特定 Pod 相关的 Service&#xff0c;可以通过以下方法&#xff1a;#### 方法一&#xff1a;通过标签匹配1. **获取 Pod 的标签**bashkubectl get pod <pod-name> --show-labels输出示例&#xff1a;NAME READY STATUS RESTARTS AGE…

通俗易懂卷积神经网络(CNN)指南

本文用直观类比和可视化方法&#xff0c;帮你彻底理解CNN的工作原理&#xff0c;无需深厚数学基础也能掌握计算机视觉的核心技术。卷积神经网络&#xff08;CNN&#xff09;是深度学习中革命性的架构&#xff0c;它彻底改变了计算机"看世界"的方式。本文将用最直观的…

AV1平滑缓冲区

对于解码的每一帧视频数据&#xff0c;解码器都必须从缓冲池中找到一个尚未被使用的帧缓冲区插槽来存储解码后的数据。分配的帧缓冲区插槽用于临时保存解码过程中生成的帧数据&#xff0c;直到它们被用于显示或进一步的处理。函数get_free_buffer的作用是在缓冲池中搜索尚未被分…

Python并发编程:突破GIL枷锁,高效利用多核CPU

解密concurrent.futures的双引擎&#xff1a;线程池与进程池的明智选择在Python并发编程领域&#xff0c;concurrent.futures模块堪称利器&#xff0c;但如何正确使用其两大核心组件——ThreadPoolExecutor和ProcessPoolExecutor&#xff0c;却让许多开发者困惑。本文将深入剖析…

在Windows Server 2012 R2中安装与配置IIS服务并部署mssql靶机教程

在Windows Server 2012 R2中安装与配置IIS服务全指南 IIS&#xff08;Internet Information Services&#xff09;作为Windows系统自带的Web服务组件&#xff0c;在企业级Web部署、内网服务搭建等场景中应用广泛。本文将详细介绍在Windows Server 2012 R2中安装IIS服务的完整流…

C#/.NET/.NET Core技术前沿周刊 | 第 47 期(2025年7.14-7.20)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

一.AD域与DFS集群-AD域安装

目录 1.网络规划 2.主域控安装 3.辅助域控安装 1.网络规划 服务器名称IP地址DNS名称主域控192.168.188.2pdc.test.cn辅助域控192.168.188.3bdc.test.cnDFS1192.168.188.4dfs1.test.cnDFS2192.168.188.5dfs2.test.cn 服务器系统版本为windows server 2022 2.主域控安装 第一…

BUUCTF在线评测-练习场-WebCTF习题[BSidesCF 2020]Had a bad day1-flag获取、解析

解题思路打开靶场&#xff0c;作者对我们进行了亲切的关怀老规矩查看源码、抓包并没有发现什么猫腻点下面两个按钮会出现猫猫狗狗的图片&#xff0c;此时我们发现url多了个 参数category那么比较明显就是提示我们是任意文件包含、任意文件读取漏洞了找不到任何信息&#xff0c;…

stm32mp157f-dk2安装镜像并且部署qt全流程

在网上看的关于stm32mp157的开发教程太少了&#xff0c;于是乎写一篇踩坑笔记&#xff0c;仅供学习参考 大概流程&#xff1a;在虚拟机通过stm32cubeprogrammer烧录镜像&#xff0c;然后烧录成功之后&#xff0c;给stm32mp157连接网线&#xff0c;使得开发板有ip地址&#xff…

遗像照片尺寸要求及手机制作打印方法

遗像作为寄托哀思的重要载体&#xff0c;其规格和质量都有严格要求。本文将详细介绍遗像照片的标准尺寸规范&#xff0c;并提供使用手机快速制作合规遗像的完整方案。一、遗像照片的标准尺寸要求遗像照片的尺寸主要分为传统黑白遗像和现代彩色遗像两种规格。传统黑白遗像一般采…

适配器模式 (Adapter Pattern)

适配器模式 (Adapter Pattern) 适配器模式是一种结构型设计模式&#xff0c;用于解决两个不兼容接口之间的兼容性问题&#xff0c;充当两个不同接口之间的桥梁。 &#x1f31f; 核心思想转换接口&#xff1a;将一个类的接口转换成客户端期望的另一个接口&#xff0c;使原本不兼…

03-虚幻引擎蓝图类的各父类作用讲解

虚幻引擎&#xff08;Unreal Engine&#xff09;的蓝图系统提供了多种父类&#xff0c;每种父类都有其特定的用途和生命周期。理解这些父类的作用&#xff0c;是高效使用蓝图开发游戏的基础。以下是虚幻引擎中常见蓝图父类的详细讲解&#xff1a;1. Actor 作用&#xff1a;所有…

141 个 LangChain4j Maven 组件分类解析、多场景实战攻略

141 个 LangChain4j Maven 组件分类解析、多场景实战攻略 文章目录 141 个 LangChain4j Maven 组件分类解析、多场景实战攻略 1. 引言 2. LangChain4j 组件分类 2.1. 核心模块 (Core Modules) 2.2. LLM 集成 (LLM Integrations) 2.3. 向量存储集成 (Embedding Store Integratio…

Python可迭代归约函数深度解析:从all到sorted的进阶指南

在Python中&#xff0c;归约函数&#xff08;Reduction Functions&#xff09;是处理可迭代对象的利器。它们通过遍历元素并逐步收敛为单个结果&#xff0c;广泛应用于数据分析、逻辑判断和数值计算等场景。本文将系统梳理这些函数的核心特性、使用技巧及底层逻辑&#xff0c;助…

大带宽服务器都有哪些应用场景?

大带宽服务器凭借着高速的数据传输能力和强大的网络承载能力&#xff0c;通常被企业应用在需要高流量和高并发处理能力的业务场景当中&#xff0c;下面&#xff0c;就让我们共同了解一下大带宽服务器的应用场景吧&#xff01;首先&#xff0c;随着科学技术的快速发展&#xff0…

爬虫实战指南:从定位数据到解析请求的全流程解析

爬虫的本质是什么&#xff1f; 爬虫的本质就是用代码模拟人类在浏览器里的操作&#xff0c;像点击网页、填写表单、提交数据等行为&#xff0c;自动化地进行网页数据的获取和处理。比如&#xff1a; 发送 GET 请求 来请求网页内容&#xff0c;相当于你在浏览器地址栏输入网址…

Sentinel dashboard 添加context-path后无法信息无法上传问题

Sentinel dashboard 添加context-path后无法加载问题 添加server.servlet.context-path/sentinel后可以正常访问&#xff0c;但是客户端启动后信息上报失败。 transport: dashboard: localhost:8858/sentinel 经查阅文档需要加入api-path&#xff0c;但是我配置提示无api-path所…

iOS —— 3Gshare项目总结与思考

登陆注册及推出主页面这部分有两种写法&#xff1a;一种是在SceneDelegate中推出LoginVC&#xff0c;后在判断登陆成功后退去主要程序。另一种则是先加载主程序&#xff0c;后推出登陆页面。通过同组同学实践证明&#xff0c;后者在推出登陆页面时会闪一下&#xff0c;因此还是…

硅基计划3.0 学习总结 贰 顺序表与链表 初版

文章目录一、顺序表——ArrayList1. 实现自己MyArrayList1. 实现add基础方法2. 实现指定位置加元素add方法3. 完善数组打印方法display4. 完善根据下标找元素get5. 完善判断数字是否在数组中contains6. 根据数字找下标indexOf7. 更新指定下标元素set8. 获取数组有效长度size9. …

Postman/Apipost中使用Post URL编码发送含换行符参数的问题分析

Postman/Apipost中使用Post URL编码发送含换行符参数的问题分析 在使用Postman或Apipost等API测试工具进行POST请求时&#xff0c;当参数中包含换行符(\n或\r)通过UI界面复制参数时会遇到参数发送失效的问题。 问题原因分析URL编码规范限制&#xff1a; x-www-form-urlencoded格…