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
英文地址,請注明出處:http://en.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格…