用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 re正则表达式模块(Regular Expression)
Jul 16 Python
在Mac OS上部署Nginx和FastCGI以及Flask框架的教程
May 02 Python
Python编程中的for循环语句学习教程
Oct 14 Python
python字符串连接方法分析
Apr 12 Python
python+matplotlib实现鼠标移动三角形高亮及索引显示
Jan 15 Python
python之DataFrame实现excel合并单元格
Feb 22 Python
浅谈python配置与使用OpenCV踩的一些坑
Apr 02 Python
如何用Python合并lmdb文件
Jul 02 Python
python 字符串格式化的示例
Sep 21 Python
Python urllib3软件包的使用说明
Nov 18 Python
如何查看python关键字
Jan 17 Python
教你如何使用Python实现二叉树结构及三种遍历
Jun 18 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
详细介绍:Apache+PHP+MySQL配置攻略
2006/09/05 PHP
adodb与adodb_lite之比较
2006/12/31 PHP
php 中文字符入库或显示乱码问题的解决方法
2010/04/12 PHP
php调用MySQL存储过程的方法集合(推荐)
2013/07/03 PHP
PHP中func_get_args(),func_get_arg(),func_num_args()的区别
2013/09/30 PHP
php简单获取复选框值的方法
2016/05/11 PHP
PHP实现基本留言板功能原理与步骤详解
2020/03/26 PHP
两个select之间option的互相添加操作(jquery实现)
2009/11/12 Javascript
Javascript Boolean、Nnumber、String 强制类型转换的区别详细介绍
2012/12/13 Javascript
javascript实现仿IE顶部的可关闭警告条
2015/05/05 Javascript
从零学习node.js之搭建http服务器(二)
2017/02/21 Javascript
weebox弹出窗口不居中显示的解决方法
2017/11/27 Javascript
在vue使用clipboard.js进行一键复制文本的实现示例
2019/01/15 Javascript
create-react-app使用antd按需加载的样式无效问题的解决
2019/02/26 Javascript
JavaScript中的ES6 Proxy的具体使用
2019/06/16 Javascript
解决Vue动态加载本地图片问题
2019/10/09 Javascript
学习python处理python编码问题
2011/03/13 Python
在Python中使用列表生成式的教程
2015/04/27 Python
numpy.transpose对三维数组的转置方法
2018/04/17 Python
利用Python将数值型特征进行离散化操作的方法
2018/11/06 Python
python pandas库的安装和创建
2019/01/10 Python
Django uwsgi Nginx 的生产环境部署详解
2019/02/02 Python
pandas计算最大连续间隔的方法
2019/07/04 Python
通过celery异步处理一个查询任务的完整代码
2019/11/19 Python
基于jupyter代码无法在pycharm中运行的解决方法
2020/04/21 Python
python 实现一个简单的线性回归案例
2020/12/17 Python
Amara美国站:英国高端家居礼品网站,世界各地的奢侈家具品牌
2017/07/26 全球购物
Notino匈牙利:购买香水和化妆品
2019/04/12 全球购物
Unix里面如何在后台运行程序
2016/10/14 面试题
实习会计求职自荐信范文
2014/03/10 职场文书
歌唱比赛策划方案
2014/06/06 职场文书
农村党支部书记司法四风问题对照检查材料
2014/09/26 职场文书
职工培训工作总结
2015/08/10 职场文书
自信主题班会
2015/08/14 职场文书
7个你应该知道的JS原生错误类型
2021/04/29 Javascript
Matplotlib绘制混淆矩阵的实现
2021/05/27 Python