用Python解数独的方法示例


Posted in Python onOctober 24, 2019

芬兰数学家因卡拉花费3个月时间设计出的世界上迄今难度最大的数独。数独是 9 横 9 竖共有 81 个格子,同时又分为 9 个九宫格。规则很简单:每个空格填入 1~9 任意一个数字,需要保证每个横排和竖排以及九宫格内无相同数字。

用Python解数独的方法示例

解数独是一个可有可无的爱好,知道这个益智游戏,但是不很上心。但是前两天,由于自己的学生装了一个 ubuntu 18.04 的系统,上面有一些数独游戏,偶然间,让我看见了,为了更好的显摆自己的 Python 知识,决定用 Python 写一个程序,所以就有了下面的文字。

1、将待解的数独转换成 Python 矩阵

m = [
 [6, 0, 0, 1, 0, 0, 7, 0, 8],
 [0, 0, 0, 8, 0, 0, 2, 0, 0],
 [2, 3, 8, 0, 5, 0, 1, 0, 0],
 [0, 0, 0, 0, 4, 0, 0, 9, 2],
 [0, 0, 4, 3, 0, 8, 6, 0, 0],
 [3, 7, 0, 0, 1, 0, 0, 0, 0],
 [0, 0, 3, 0, 7, 0, 5, 2, 6],
 [0, 0, 2, 0, 0, 4, 0, 0, 0],
 [9, 0, 7, 0, 0, 6, 0, 0, 4]
]

就是这么简单,将待填写的空白格用 0 来代替。

2、寻找第一个空格位置

def start_pos(m:"数独矩阵"):
 """ 功能:返回第一个空白格的位置坐标"""
 for x in range(9):
  for y in range(9):
   if m[x][y] == 0:
    return x, y
 return False, False # 若数独已完成,则返回 False, False

找到 Python 矩阵中第一个是 0 的元素的位置坐标。

3、寻找下一个空格位置

def get_next(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):
 """ 功能:获得下一个空白格在数独中的坐标。  
 """
 for next_y in range(y+1, 9): # 下一个空白格和当前格在一行的情况
  if m[x][next_y] == 0:
   return x, next_y
 for next_x in range(x+1, 9): # 下一个空白格和当前格不在一行的情况
  for next_y in range(0, 9):
   if m[next_x][next_y] == 0:
    return next_x, next_y
 return -1, -1    # 若不存在下一个空白格,则返回 -1,-1

找到 Python 矩阵中下一个是 0 的元素的位置坐标。详细内容看注释。

4、寻找适合当前空格的数字的集合

def value(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):
 """ 功能:返回符合"每个横排和竖排以及
    九宫格内无相同数字"这个条件的有效值。
 """ 
 i, j = x//3, y//3
 grid = [m[i*3+r][j*3+c] for r in range(3) for c in range(3)]
 v = set([x for x in range(1,10)]) - set(grid) - set(m[x]) - \
  set(list(zip(*m))[y])
 return list(v)

每个空格可以填入 1~9 中的任意一个数字,但要符合规则:每个空格填入 1~9 任意一个数字,需要保证每个横排和竖排以及九宫格内无相同数字。下面的代码中的 grid 变量,保存的是当前位置所处的九宫格。v 变量是通过集合运算,将 1~9 这个数字集合中,与行的数字集合、列的数字集合以及九宫格的数字集合重叠的部分去除掉。剩余的部分就是符合条件的数字的集合。

5、使用递归尝试解数独(Sudoku)

def try_sudoku(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):
 """ 功能:试着填写数独 """
 for v in value(m, x, y):
  m[x][y] = v
  next_x, next_y = get_next(m, x, y)
  if next_y == -1: # 如果无下一个空白格
   return True
  else:
   end = try_sudoku(m, next_x, next_y) # 递归
   if end: # 数独解完之后,此处的 end 会是 True
    return True
   m[x][y] = 0 # 在递归的过程中,如果数独没有解开,
      # 则回溯到上一个空白格

详细内容看注释。

6、代码展示

import random 
import sys 
sys.setrecursionlimit(100000) # 发现python默认的递归深度是很有限的
        #(默认是1000),因此当递归深度超过999的
        # 样子,就会引发这样的一个异常。


def get_next(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):
 """ 功能:获得下一个空白格在数独中的坐标。  
 """
 for next_y in range(y+1, 9): # 下一个空白格和当前格在一行的情况
  if m[x][next_y] == 0:
   return x, next_y
 for next_x in range(x+1, 9): # 下一个空白格和当前格不在一行的情况
  for next_y in range(0, 9):
   if m[next_x][next_y] == 0:
    return next_x, next_y
 return -1, -1    # 若不存在下一个空白格,则返回 -1,-1
  
def value(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):
 """ 功能:返回符合"每个横排和竖排以及
    九宫格内无相同数字"这个条件的有效值。
 """ 
 i, j = x//3, y//3
 grid = [m[i*3+r][j*3+c] for r in range(3) for c in range(3)]
 v = set([x for x in range(1,10)]) - set(grid) - set(m[x]) - \
  set(list(zip(*m))[y]) 
 return list(v)

def start_pos(m:"数独矩阵"):
 """ 功能:返回第一个空白格的位置坐标"""
 for x in range(9):
  for y in range(9):
   if m[x][y] == 0:
    return x, y
 return False, False # 若数独已完成,则返回 False, False

def try_sudoku(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):
 """ 功能:试着填写数独 """
 for v in value(m, x, y):
  m[x][y] = v
  next_x, next_y = get_next(m, x, y)
  if next_y == -1: # 如果无下一个空白格
   return True
  else:
   end = try_sudoku(m, next_x, next_y) # 递归
   if end:
    return True
   m[x][y] = 0 # 在递归的过程中,如果数独没有解开,
      # 则回溯到上一个空白格

def sudoku(m):  
 x, y = start_pos(m)
 try_sudoku(m, x, y)
 print(m)  
 
  

     
if __name__ == "__main__":
 m = [
  [6, 0, 0, 1, 0, 0, 7, 0, 8],
  [0, 0, 0, 8, 0, 0, 2, 0, 0],
  [2, 3, 8, 0, 5, 0, 1, 0, 0],
  [0, 0, 0, 0, 4, 0, 0, 9, 2],
  [0, 0, 4, 3, 0, 8, 6, 0, 0],
  [3, 7, 0, 0, 1, 0, 0, 0, 0],
  [0, 0, 3, 0, 7, 0, 5, 2, 6],
  [0, 0, 2, 0, 0, 4, 0, 0, 0],
  [9, 0, 7, 0, 0, 6, 0, 0, 4]
 ]

 sudoku(m)
 
""" 数独结果如下:
[
 [6, 9, 5, 1, 2, 3, 7, 4, 8], 
 [7, 4, 1, 8, 6, 9, 2, 5, 3], 
 [2, 3, 8, 4, 5, 7, 1, 6, 9], 
 [8, 1, 6, 7, 4, 5, 3, 9, 2], 
 [5, 2, 4, 3, 9, 8, 6, 7, 1], 
 [3, 7, 9, 6, 1, 2, 4, 8, 5], 
 [4, 8, 3, 9, 7, 1, 5, 2, 6], 
 [1, 6, 2, 5, 8, 4, 9, 3, 7], 
 [9, 5, 7, 2, 3, 6, 8, 1, 4]
]
"""

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python命令行参数解析OptionParser类用法实例
Oct 09 Python
Python中使用语句导入模块或包的机制研究
Mar 30 Python
python实现文件快照加密保护的方法
Jun 30 Python
浅析Python四种数据类型
Sep 26 Python
python实现读取excel文件中所有sheet操作示例
Aug 09 Python
Anaconda 查看、创建、管理和使用python环境的方法
Dec 03 Python
pytorch 实现tensor与numpy数组转换
Dec 27 Python
python字符串替换re.sub()实例解析
Feb 09 Python
Python绘图之二维图与三维图详解
Aug 04 Python
使用jupyter notebook运行python和R的步骤
Aug 13 Python
如何基于matlab相机标定导出xml文件
Nov 02 Python
python DataFrame中stack()方法、unstack()方法和pivot()方法浅析
Apr 06 Python
Python3 sys.argv[ ]用法详解
Oct 24 #Python
window7下的python2.7版本和python3.5版本的opencv-python安装过程
Oct 24 #Python
原生python实现knn分类算法
Oct 24 #Python
python KNN算法实现鸢尾花数据集分类
Oct 24 #Python
python爬虫爬取幽默笑话网站
Oct 24 #Python
python栈的基本定义与使用方法示例【初始化、赋值、入栈、出栈等】
Oct 24 #Python
python 队列基本定义与使用方法【初始化、赋值、判断等】
Oct 24 #Python
You might like
php购物车实现代码
2011/10/10 PHP
phpmail类发送邮件函数代码
2012/02/20 PHP
用php代码限制国内IP访问我们网站
2015/09/26 PHP
PHP中__autoload和Smarty冲突的简单解决方法
2016/04/08 PHP
PHP 使用位运算实现四则运算的代码
2021/03/09 PHP
JavaScript 核心参考教程 内置对象
2009/10/13 Javascript
jquery实现固定顶部导航效果(仿蘑菇街)
2013/03/21 Javascript
一个css与js结合的下拉菜单支持主流浏览器
2014/10/08 Javascript
JavaScript定时显示广告代码分享
2015/03/02 Javascript
JS组件Bootstrap Select2使用方法解析
2016/05/30 Javascript
JS实现保留n位小数的四舍五入问题示例
2016/08/03 Javascript
Bootstrap基本组件学习笔记之下拉菜单(7)
2016/12/07 Javascript
vue路由跳转时判断用户是否登录功能的实现
2017/10/26 Javascript
移动web开发之touch事件实例详解
2018/01/17 Javascript
JavaScript创建对象的常用方式总结
2018/08/10 Javascript
详解微信JS-SDK选择图片遇到的坑
2018/08/15 Javascript
js正则取值的结果数组调试方法
2018/10/10 Javascript
Node.js Buffer模块功能及常用方法实例分析
2019/01/05 Javascript
在微信小程序中保存网络图片
2019/02/12 Javascript
[48:29]2018DOTA2亚洲邀请赛3月30日 小组赛A组 LGD VS KG
2018/03/31 DOTA
[56:14]Fnatic vs OG 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python代码实现KNN算法
2017/12/20 Python
Python+selenium点击网页上指定坐标的实例
2019/07/05 Python
英国厨房与餐具用品为主的设计品牌:Joseph Joseph
2018/04/26 全球购物
豪华床上用品 :Jennifer Adams
2019/09/15 全球购物
美国第一大药店连锁机构:Walgreens(沃尔格林)
2019/10/10 全球购物
托管代码(Managed Code)和非托管代码(Unmanaged Code)有什么区别
2014/09/29 面试题
linux面试题参考答案(5)
2014/09/01 面试题
教育科研先进个人材料
2014/01/26 职场文书
学校消防演习方案
2014/02/19 职场文书
中学生运动会新闻稿
2014/09/24 职场文书
2014年工程工作总结
2014/11/25 职场文书
企业党支部工作总结2015
2015/05/21 职场文书
2015暑假假期总结
2015/07/13 职场文书
2015暑期爱心支教策划书
2015/07/14 职场文书
Python基础数据类型tuple元组的概念与用法
2021/08/02 Python