`
xlaohe1
  • 浏览: 127130 次
  • 性别: Icon_minigender_1
  • 来自: 来处
社区版块
存档分类
最新评论

9x9数独算法

阅读更多
下面给出了源代码
sdks文件里面含有120个数独
请各位大大纠正

这个算法也可以用来做生成数独,然后取出几个
比如你给定数独为
000000000000000000000000000000000000000000000000000000000000000000000000000000001
# 嘿嘿,这解可多了,机器别跑死了。


# -*- coding:utf-8 -*-
'''
首先生成9x9x9的三维数组,每个值为[1,2,3,4,5,6,7,8,9]
1,然后确定有独一的值,清除行,列,块当中的值 clean(data)函数
继续1
然后找到唯一值,即行、列或块当中只出现一次的值,设置当前值,然后执行1,clean_help(data)函数
最后如果没有唯一值那就找最少候选的那个格子先尝试这个格子的其中一个候选,再尝试剩余的候选数字
'''

#1. 先遍历一遍,找出所有“只有一个候选数字”的格子, 清除行,列,块数据
#2. 填满这些数字,重复第一步
#3. 如果没有“只有一个候选数字”的格子,那就找最少候选的那个格子
#  先尝试这个格子的其中一个候选,再尝试剩余的候选数字
from copy import deepcopy
# 移除数组中指定的值
def rm(s, n):
    i = 0
    try:
        s.remove(n)
        i = i + 1
    except:
        pass
    return i
# 根据行,列坐标,返回行,列,块数组
def find(fbs, i, j):
    block = [] 
    br = i / 3 * 3
    bc = j / 3 * 3
    for l in range(0, 3):
        r = br + l
        for k in range(0, 3):
            c = bc + k
            block.append(fbs[r][c])
    return {"row":fbs[i], "column":[fbs[a][j] for a in range(0, 9)], "block":block}
# 打印
def pnt(dbss):
    print "============"
    for i in range(0, 9):
        print dbss[i], "\n" 
# 生成9×9×9的三维数组
base = [[[i for i in range(1, 10)] for a in range(1, 10)] for b in range(1, 10)]
sudo1 = [
        [0,8,1, 0,9,0, 0,0,0], 
        [0,0,0, 1,0,7, 0,5,0],
        [0,7,5, 0,4,0, 0,0,1],
        [0,0,0, 0,3,4, 2,0,0],
        [5,0,0, 7,0,1, 0,0,0],
        [0,0,0, 0,0,2, 1,0,9],
        [0,0,6, 0,8,0, 0,0,4],
        [8,0,7, 6,0,0, 5,0,0],
        [0,0,3, 0,0,0, 6,0,8]
        ]
# 此数独没有解出来。
sudo2 = [ 
                [ 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, 6, 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 ]  
                   ]
                   
# 此数独有解,但死循环                   
sudo3 = [
         [0, 0, 0, 0, 1, 0, 0, 0, 0],
         [0, 0, 0, 2, 0, 3, 0, 0, 0],
         [0, 0, 4, 0, 0, 0, 5, 0, 0],
         [0, 6, 0, 0, 0, 0, 0, 7, 0],
         [8, 0, 0, 0, 5, 0, 0, 0, 9],
         [0, 7, 0, 0, 0, 0, 0, 6, 0],
         [0, 0, 5, 0, 0, 0, 4, 0, 0],
         [0, 0, 0, 3, 0, 2, 0, 0, 0],
         [0, 0, 0, 0, 9, 0, 0, 0, 0]
         ]
sudo4 = [
         [0, 0, 0, 0, 1, 0, 8, 7, 0],
         [0, 2, 0, 0, 9, 0, 0, 0, 0],
         [0, 0, 0, 5, 0, 0, 0, 0, 0],
         [2, 0, 0, 0, 6, 8, 0, 9, 0],
         [0, 0, 8, 0, 7, 0, 3, 0, 0],
         [0, 9, 7, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 4, 6, 3, 0],
         [0, 8, 0, 0, 5, 0, 0, 0, 0],
         [0, 7, 1, 3, 0, 0, 9, 0, 0]
         ]

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

# 初始化填充base
def inits(b, s):
    for i in range(0, 9):
        sudo = s[i]
        for j in range(0, 9):
            num = sudo[j]
            if num != 0:
                b[i][j] = [num]
                finds = find(b, i, j)
                for f in finds:
                    ff = finds[f]
                    for fff in ff:
                        if len(fff) > 1:
                            rm(fff, num)
    return b
            
# 根据独一值,清除行,列,块值                            
def clean(clean_data):
    flag = True
    while flag:
        # 退出条件
        rms = 0
        for i in range(0, 9):
            for j in range(0, 9):
                num = clean_data[i][j]
                if len(num) == 1:
                    # 根据独一值清除行,列,块
                    finds = find(clean_data, i, j)
                    for f1 in finds:
                        f2 = finds[f1]
                        for f3 in f2:
                            if len(f3) > 1:
                                rms += rm(f3, num[0])
        if rms == 0:
            flag = False
    return clean_data
# 找到唯一值,并清除行列块
def clean_help(data):
    while True:
        # 退出条件
        flag = True
        for i in range(0, 9):
            for j in range(0, 9):
                brk = 0
                cur = data[i][j]
                if len(cur) > 1:
                    finds = find(data, i, j)
                    for f in finds:
                        a = [0] * 9
                        f1 = finds[f]
                        for f2 in f1:
                            for f3 in f2:
                                a[f3 - 1] += 1
                        for m in cur:
                            # 找到了唯一值,并进行设置,清除数独,退出当前循环
                            if a[m - 1] == 1:
                                flag = False
                                brk = 1
                                data[i][j] = [m]
                                clean(data)
                                break
                        if brk == 1:
                            break
        # 当没有唯一值是退出循环
        if flag:
            break
    return data

# 读取数独源
def readSdks(i):
    sudokus = open("sdks", "r")
    if i < 0 or i > 125:
        print "Not found sudoku data"
        return
    sdk = sudokus.readlines()[i].replace("\n","")
    sdks = [sdk[j:j + 9] for j in range(0, 81, 9)]
    #print sdks
    ret = [[int(sk[l]) for l in range(0, 9)] for sk in sdks]
    sudokus.close()
    
    return ret
    
# 验证数独    
def isOk(data):
    for i in range(0, 9):
        for j in range(0, 9):
            finds = find(data, i, j)
            for f in finds:
                a = [0] * 9
                ff = finds[f]
                for fff in ff:
                    if len(fff) > 1:
                        return False
                    a[fff[0] - 1] += 1
                for ia in a:
                    if ia > 1 or ia == 0:
                        return False
    print  "ok"
    return True

# 找到数独当中最小候选对象元祖
#([], x, y) 数组为候选可能值,x为行坐标,y为列坐标
def small(data):
    ret_sm = ([0] * 9, -1, -1)
    for i in range(0, 9):
        for j in range(0, 9):
            if len(data[i][j]) > 1 and len(data[i][j]) < len(ret_sm[0]):
                ret_sm = (data[i][j], i, j)
    return ret_sm

# 最后数独完成操作 设置候选值
def done(data):
    if isOk(data):
        pnt(data)
        return
    sm_tuple = small(data)
    #print sm_tuple
    if sm_tuple[1] == -1:
        #print "no solve"
        return
    # 设置候选值
    for sm in sm_tuple[0]:
        #pnt(data)
        # 复制数独源,上次的结果不然还存在,就不能求多解了
        copy_data = deepcopy(data)
        # 设置候选值
        copy_data[sm_tuple[1]][sm_tuple[2]] = [sm]
        # 然后执行清除操作
        copy_data = clean_help(clean(copy_data))
        if isOk(copy_data):
            #print "in done"
            pnt(copy_data)
            return
        # 如果没有完成,继续设置候选值
        done(copy_data)


def main():
    for i in range(0, 120):
        print "The %d index" % i
        #readSdks(1)
        sudokuData = readSdks(i)
        base = [[[j for j in range(1, 10)] for a in range(1, 10)] for b in range(1, 10)]
        init_data = inits(base, sudokuData)
        #print "init:"
        #pnt(init_data)
        clean_data = clean(init_data)
        #print "clean:"
        #pnt(clean_data)
        only_data = clean_help(clean_data)
        #print "only:"
        #pnt(only_data)
        done(only_data)
        
if __name__ == "__main__":
    main()

0
2
分享到:
评论

相关推荐

    人工智能之回溯法python求解9X9数独

    给出求解9*9数独至少一种搜索方法(回溯、爬山、模拟退火,束搜索、遗传算法),并分析其算法的性能(四个搜索算法评价指标)。 答: 回溯: 深度优先搜索+变量分配,即每次分配一个变量+约束检查,即考虑与前面分配...

    java数独题库高效生成算法代码

    可以根据设置不同难度生成9x9数独题

    数独求解代码

    c#求解数独,主要利用回溯算法来完成对数独的求解,供学习参考

    shudu.rar_数独_数独实现

    数独的实现过程,其中介绍了如何来判定实现一个9x9的数独算法,并且判断填数是否成功。

    标准数独秒破解程序

    该程序用Perl编程语言编写,用来破解标准的9x9数独,从简单数独到骨灰级数独,都可以秒破。

    Sudoku command line solver:使用命令行实用程序解决9x9数独难题-开源

    这个用C语言编写的工具使用Backtracking算法来解决数独难题。 这个想法是通过参加德国互联网论坛的编码挑战而诞生的。 ...

    sudokogenetico:通过遗传算法的数独解决方案

    在标准形式下,数独是由包含3x3子网格的9x9网格构成的逻辑游戏。 一些正方形已经预先填充了1到9之间的数字。游戏的目的是填充整个网格,而在9x9网格的行和列中均不重复任何数字。每个子网格都不能存在重复项。 在...

    MATLAB 中的递归数独求解器:采用 (9x9) 矩阵并输出求解矩阵的数独求解器。-matlab开发

    这以递归方式解决了数独谜题(假设它最初是有效的)。 虽然它不是最快的,但我认为它对于 18 行代码来说很好。 我制作了另一个更快的,但它的时间要长得多。

    backtrack-sudoku:使用Backtrack算法的数独解算器

    回溯数独使用回溯算法的数独求解器该项目该应用程序允许用户尝试解决各种大小和难度... 有一些程序可以在3x3、4x4、6x6、8x8和9x9板上测试该算法,这些板与该应用程序内置的板相同。依存关系Python3PyQt5未来可能的改进

    快速数独解算器:快速找到数独谜题的所有可能解决方案-matlab开发

    M = 初始数独矩阵,空条目为零Mout = 如果有唯一解,则解为 9x9 矩阵,如果有 N 个解,则解为 9x9xN 矩阵 笔记: (1) 该算法采用递归,但在每个递归级别都尽可能多地进行直接确定性推导,以提高整体速度。 (2) 为该...

    libsudoku:数独生成解题库

    概要生成、验证和解决 9x9 数独谜题。 它使用 Knuth 算法 X 的实现,这是对双向链表的奇特使用,可以在保留元素原始顺序的同时有效地添加和删除元素。 鉴于数独的可能性很小,与朴素的蛮力算法相比,它是矫枉过正的...

    数独求解matlab代码-Sudoku_Solver:数独求解程序,使用MATLAB从图像文件中获取数独迷宫的输入

    •该项目可以在3秒内解决9x9数独问题,包括图像处理时间。 回溯被证明是一种很棒的算法,可在程序的数独求解部分中使用。 •代替Sudoku解决方案,该项目可能会在纸上进行一些小的改动而进行一些计算; 节省了将其...

    parallel-sudoku-solver:GPU 上的并行数独求解器

    数独是一种流行的益智游戏,通常在 1 到 9 之间的 9x9 数字板上玩。 游戏的目标是用数字填满棋盘。 但是,每行只能包含 1 到 9 之间的每个数字之一。同样,每列和 3x3 子板只能包含 1 到 9 之间的每个数字之一。这...

    sudoku-solver:用 C 编写的递归回溯数独求解器

    当您在 9x9 零数组上调用 solve(Sudoku p) 方法时,此算法会生成所有可能的数独解决方案(有 6.671*10^21)。 显然,您的计算机将无法完成此操作,因为它可能需要数十年的时间。 在低效版本中调用 solve 函数 1 亿...

    数独解算器

    数独解算器此C ++应用程序使用回溯搜索解决了9x9数独板。 算法将探索每个位置上的所有可能的数值,如果到达无效的棋盘状态则回溯,直到棋盘被解决。

    sudoku_solver:适用于任何大小数独设置的数独求解器

    数独解算器 适用于任何大小数独设置的数独求解器 ... 文本文件的前三个值是尺寸 (9x9 = 9)、行间 # 列和行间 # 行。 下一行是数独,空格使用 0。 请注意,我没有实现猜测算法,因此它无法解决需要猜测数字的数独问题。

    Sudoku-Solver:小数独解算器

    我练习C ++基础知识的小型Sudoku求解器 特征: 。 通过回溯算法解决给定的9x9数独难题。 在递归方法上采用了迭代方法\ 目前正在从事: 。 数独发生器

    Python如何判断数独是否合法

    介绍 该数独可能只填充了部分数字,其中缺少的数字用 ....# @param board, a 9x9 2D array # @return a boolean def isValidSudoku(self, board): rows = [list(lst[::]) for lst in board] colum

    ML-Soduku-Analysis

    ML数独分析 数独难题由9×9网格表示,该网格由9个3×3子网格(称为块)组成。 拼图的81个单元中的某些单元被分配... 通过3种策略解决9x9数独游戏的问题。 进化算法 模拟退火 可推广性 分析每种解决方案,看哪种更好。

Global site tag (gtag.js) - Google Analytics