用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的math模块中的常用数学函数整理
Feb 04 Python
人机交互程序 python实现人机对话
Nov 14 Python
Python3爬取英雄联盟英雄皮肤大图实例代码
Nov 14 Python
python实现给scatter设置颜色渐变条colorbar的方法
Dec 13 Python
详解Python装饰器
Mar 25 Python
Python批量生成幻影坦克图片实例代码
Jun 04 Python
python输入多行字符串的方法总结
Jul 02 Python
pycharm设置鼠标悬停查看方法设置
Jul 29 Python
Python从入门到精通之环境搭建教程图解
Sep 26 Python
python 统计文件中的字符串数目示例
Dec 24 Python
python如何求100以内的素数
May 27 Python
Python实现仓库管理系统
May 30 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 登录记住密码实现思路
2013/05/07 PHP
50个PHP程序性能优化的方法
2014/06/02 PHP
PHP实现绘制二叉树图形显示功能详解【包括二叉搜索树、平衡树及红黑树】
2017/11/16 PHP
php实现断点续传大文件示例代码
2020/06/19 PHP
JavaScript入门教程(7) History历史对象
2009/01/31 Javascript
javascript hashtable 修正版 下载
2010/12/30 Javascript
Jquery仿IGoogle实现可拖动窗口示例代码
2014/08/22 Javascript
js代码实现无缝滚动(文字和图片)
2015/08/20 Javascript
js css+html实现简单的日历
2016/07/14 Javascript
canvas实现流星雨的背景效果
2017/01/13 Javascript
为什么使用koa2搭建微信第三方公众平台的原因
2018/05/16 Javascript
Nuxt.js 数据双向绑定的实现
2019/02/17 Javascript
javascript中数组的常用算法深入分析
2019/03/12 Javascript
一个小时快速搭建微信小程序的方法步骤
2019/04/15 Javascript
基于JS实现父组件的请求服务过程解析
2019/10/14 Javascript
微信小程序自定义底部弹出框功能
2020/11/18 Javascript
pyramid配置session的方法教程
2013/11/27 Python
使用XML库的方式,实现RPC通信的方法(推荐)
2017/06/14 Python
pandas数据拼接的实现示例
2020/04/16 Python
Django Admin后台模型列表页面如何添加自定义操作按钮
2020/11/11 Python
英国手机壳购买网站:Case Hut
2019/04/11 全球购物
儿科护理实习自我鉴定
2013/09/19 职场文书
护理专科毕业推荐信
2013/11/10 职场文书
部队学习十八大感言
2014/01/11 职场文书
幼儿教师师德师风自我剖析材料
2014/09/29 职场文书
环境卫生工作汇报材料
2014/10/28 职场文书
2015年圣诞节活动总结
2015/03/24 职场文书
博士论文答辩开场白
2015/06/01 职场文书
小学毕业感言100字
2015/07/30 职场文书
PyQt5爬取12306车票信息程序的实现
2021/05/14 Python
Mysql Online DDL的使用详解
2021/05/20 MySQL
一劳永逸彻底解决pip install慢的办法
2021/05/24 Python
HTML5来实现本地文件读取和写入的实现方法
2021/05/25 HTML / CSS
深入理解CSS 中 transform matrix矩阵变换问题
2021/08/30 HTML / CSS
uniapp 微信小程序 自定义tabBar 导航
2022/04/22 Javascript
Nginx利用Logrotate实现日志分割
2022/05/20 Servers