Python-实现九宫格
来源:互联网 发布:汇川 4da编程 编辑:程序博客网 时间:2024/05/18 02:52
分享 数独 Python算法 话不多说,脚本如下:
代码可以直接用python运行。
#!/usr/bin/env python# -*- coding: utf-8 -*-# @Time : 2017/9/29 下午2:09# @Author : maxdong# @Site : # @File : sudu.py# @Software: PyCharm__author__ = u"maxdong"# 思路# numpy可以创建多维的数组,并且可以快速得到对应行、列和九宫格的位置。那么我可以创建1个9*9的二维数组。# 若其中某个坐标的值是确定的,则用数字填入;没有确定下来,则用一个list列表,列表中是可能的值作为候选import numpy as np #在python中numpy可以创建多维的数组,并且可以快速得到对应行、列和九宫格的位置import timeimport copyfrom Queue import Queue, LifoQueue #后进先出class Recoder(): point = None # 进行猜测的点 point_index = 0 # 猜测候选列表使用的值的索引 value = None # 回溯记录的值class Sudo(): def __init__(self, data): # 数据初始化(二维的object数组) self.value = np.array([[0] * 9] * 9, dtype=object) # 九宫格的基准列表 self.base_points = [[0, 0], [0, 3], [0, 6], [3, 0], [3, 3], [3, 6], [6, 0], [6, 3], [6, 6]] # 猜测次数 self.guess_times = 0 # 先进先出的新解坐标 self.new_points = Queue() # 先进后出的回溯器 self.recoder = LifoQueue() # 把81个元素的list转化为9*9的二维数组 data = np.array(data).reshape(9, -1) for r in range(0, 9): for c in range(0, 9): if data[r, c]: self.value[r, c] = data[r, c] # 把新点添加到列表中,方便以后遍历 self.new_points.put((r, c)) else: self.value[r, c] = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 对于数字来说每一行每一列以及每一个小九宫格只能出现一次,所以进行筛选 def _cut_num(self, point): r, c = point val = self.value[r, c] # enumerate在字典上是枚举、列举的意思 # 对于一个可迭代的(iterable)/可遍历的对象(如列表、字符串), # enumerate将其组成一个索引序列,利用它可以同时获得索引和值 # 每一行 for i, item in enumerate(self.value[r]): if isinstance(item, list): if item.count(val): item.remove(val) # 判断移除后,是否剩下一个元素 if len(item) == 1: self.new_points.put((r, i)) self.value[r, i] = item[0] # 每一列 for i, item in enumerate(self.value[:, c]): if isinstance(item, list): if item.count(val): item.remove(val) # 判断移除后,是否剩下一个元素 if len(item) == 1: self.new_points.put((i, c)) self.value[i, c] = item[0] # 所在九宫格(3x3的数组) b_r, b_c = map(lambda x: x / 3 * 3, point) # 九宫格基准点 for m_r, row in enumerate(self.value[b_r:b_r + 3, b_c:b_c + 3]): for m_c, item in enumerate(row): if isinstance(item, list): if item.count(val): item.remove(val) # 判断移除后,是否剩下一个元素 if len(item) == 1: r = b_r + m_r c = b_c + m_c self.new_points.put((r, c)) self.value[r, c] = item[0] # 同一行、列或九宫格中1~9可能性只有一个的情况 def _check_one_possbile(self): # 同一行只有一个数字的情况 for r in range(0, 9): values = filter(lambda x: isinstance(x, list), self.value[r]) for c, item in enumerate(self.value[r]): if isinstance(item, list): for value in item: if sum(map(lambda x: x.count(value), values)) == 1: self.value[r, c] = value self.new_points.put((r, c)) return True # 同一列只有一个数字的情况 for c in range(0, 9): values = filter(lambda x: isinstance(x, list), self.value[:, c]) for r, item in enumerate(self.value[:, c]): if isinstance(item, list): for value in item: if sum(map(lambda x: x.count(value), values)) == 1: self.value[r, c] = value self.new_points.put((r, c)) return True # 九宫格内的单元格只有一个数字的情况 for r, c in self.base_points: values = filter(lambda x: isinstance(x, list), self.value[r:r + 3, c:c + 3].reshape(1, -1)[0]) for m_r, row in enumerate(self.value[r:r + 3, c:c + 3]): for m_c, item in enumerate(row): if isinstance(item, list): for value in item: if sum(map(lambda x: x.count(value), values)) == 1: self.value[r + m_r, c + m_c] = value self.new_points.put((r + m_r, c + m_c)) return True # 同一个九宫格内数字在同一行或同一列处理 def _check_same_num(self): for b_r, b_c in self.base_points: block = self.value[b_r:b_r + 3, b_c:b_c + 3] # 判断数字1~9在该九宫格的分布情况 data = block.reshape(1, -1)[0] for i in range(1, 10): result = map(lambda x: 0 if not isinstance(x[1], list) else x[0] + 1 if x[1].count(i) else 0, enumerate(data)) result = filter(lambda x: x > 0, result) r_count = len(result) if r_count in [2, 3]: # 2或3个元素才有可能同一行或同一列 rows = map(lambda x: (x - 1) / 3, result) cols = map(lambda x: (x - 1) % 3, result) if len(set(rows)) == 1: # 同一行,去掉其他行的数字 result = map(lambda x: b_c + (x - 1) % 3, result) row = b_r + rows[0] for col in range(0, 9): if not col in result: item = self.value[row, col] if isinstance(item, list): if item.count(i): item.remove(i) # 判断移除后,是否剩下一个元素 if len(item) == 1: self.new_points.put((row, col)) self.value[row, col] = item[0] return True elif len(set(cols)) == 1: # 同一列 result = map(lambda x: b_r + (x - 1) / 3, result) col = b_c + cols[0] for row in range(0, 9): if not row in result: item = self.value[row, col] if isinstance(item, list): if item.count(i): item.remove(i) # 判断移除后,是否剩下一个元素 if len(item) == 1: self.new_points.put((row, col)) self.value[row, col] = item[0] return True # 排除法解题 def solve_sudu(self): is_run_same = True is_run_one = True while is_run_same: while is_run_one: # 筛选数字 while not self.new_points.empty(): point = self.new_points.get() # 先进先出 self._cut_num(point) # 检查单个数字的情况 is_run_one = self._check_one_possbile() # 检查同行或列的情况 is_run_same = self._check_same_num() is_run_one = True # 得到有多少个确定的数字 def get_num_count(self): return sum(map(lambda x: 1 if isinstance(x, int) else 0, self.value.reshape(1, -1)[0])) # 评分,找到最佳的猜测坐标 def get_best_point(self): best_score = 0 best_point = (0, 0) for r, row in enumerate(self.value): for c, item in enumerate(row): point_score = self._get_point_score((r, c)) if best_score < point_score: best_score = point_score best_point = (r, c) return best_point # 计算某坐标的评分 def _get_point_score(self, point): # 评分标准 (10-候选个数) + 同行确定数字个数 + 同列确实数字个数 r, c = point item = self.value[r, c] if isinstance(item, list): score = 10 - len(item) score += sum(map(lambda x: 1 if isinstance(x, int) else 0, self.value[r])) score += sum(map(lambda x: 1 if isinstance(x, int) else 0, self.value[:, c])) return score else: return 0 # 检查有没错误 def check_value(self): # 行 for row in self.value: nums = [] lists = [] for item in row: (lists if isinstance(item, list) else nums).append(item) if len(set(nums)) != len(nums): return False # 数字要不重复 if len(filter(lambda x: len(x) == 0, lists)): return False # 候选列表不能为空集 # 列 for c in range(0, 9): nums = [] lists = [] col = self.value[:, c] for item in col: (lists if isinstance(item, list) else nums).append(item) if len(set(nums)) != len(nums): return False # 数字要不重复 if len(filter(lambda x: len(x) == 0, lists)): return False # 候选列表不能为空集 # 九宫格 for b_r, b_c in self.base_points: nums = [] lists = [] block = self.value[b_r:b_r + 3, b_c:b_c + 3].reshape(1, -1)[0] for item in block: (lists if isinstance(item, list) else nums).append(item) if len(set(nums)) != len(nums): return False # 数字要不重复 if len(filter(lambda x: len(x) == 0, lists)): return False # 候选列表不能为空集 return True # 猜测记录 def recode_guess(self, point, index=0): # 记录 recoder = Recoder() recoder.point = point recoder.point_index = index # recoder.value = self.value.copy() #numpy的copy不行 recoder.value = copy.deepcopy(self.value) self.recoder.put(recoder) self.guess_times += 1 # 记录猜测次数 # 新一轮的排除处理 item = self.value[point] self.value[point] = item[index] self.new_points.put(point) self.solve_sudu() # 回溯,需要先进后出 def reback(self): while True: if self.recoder.empty(): raise Exception('sudo is wrong') else: recoder = self.recoder.get() point = recoder.point index = recoder.point_index + 1 item = recoder.value[point] # 判断索引是否超出范围。若超出,则再回溯一次 if index < len(item): break self.value = recoder.value self.recode_guess(point, index) # 解题 def calc(self): # 第一次解题 self.solve_sudu() # 检查有没错误的,有错误的则回溯;没错误却未解开题目,则再猜测 while True: if self.check_value(): if self.get_num_count() == 81: break else: # 获取最佳猜测点 point = self.get_best_point() # 记录并处理 self.recode_guess(point) else: # 出错,则回溯,尝试下一个猜测 self.reback()if __name__ == '__main__': # 号称最难的数独 data = [8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 0, 0, 0, 0, 0, 0, 7, 0, 0, 9, 0, 2, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 6, 8, 0, 0, 8, 5, 0, 0, 0, 1, 0, 0, 9, 0, 0, 0, 0, 4, 0, 0] try: t1 = time.time() sudo = Sudo(data) sudo.calc() t2 = time.time() print(u"完成,猜测了%s次" % sudo.guess_times) print(sudo.value) print(u"耗时:%.3fs" % (t2 - t1)) except Exception as e: print(e)
阅读全文
0 0
- Python-实现九宫格
- Android实现九宫格
- WEB 九宫格实现
- 九宫格的实现
- Android实现九宫格
- ios九宫格实现
- Android实现九宫格
- Adnroid 九宫格实现
- iOS实现九宫格
- 九宫格布局实现
- Masonry实现九宫格
- 九宫格实现
- GridView实现九宫格
- gridView九宫格实现
- RN实现九宫格
- 九宫格实现
- 实现九宫格
- GridView实现九宫格
- mmap 访问DDR,加了 O_RDWR| O_SYNC,仍不能同步
- Unity3D动画帧事件
- substring和substr的区别
- 欢迎使用CSDN-markdown编辑器
- vs2017下linux远程调试经验
- Python-实现九宫格
- 使用 Azure CLI 2.0 从自定义磁盘创建 Linux VM
- TensorFlow与中文手写汉字识别
- 安装与卸载应用程序 (Package Installer)
- laravel错误1071 Specified key was too long; max key length is 1000 bytes
- UGUI基础组件Text
- VMware打卡虚拟机提示“此虚拟机可能已被复制或移动”
- mysql 创建用户,添加权限
- 高维空间中, cosine similarity 的 k-近邻 搜索