Python学习案例2——数独解题及出题程序
第二个求解案例,我想到了数独。曾经有一段时间对数独求解非常感兴趣,在学习C++语言时也编写了数独求解程序。本次Python学习,要求比之前高一点,把出题程序也一起编写了吧。
1、数独简介
数独 (英语:Sudoku)是一种逻辑性的数字填充游戏,玩家须以数字填进每一格,而每行、每列和每个宫(即3x3的大格)有1至9所有数字。游戏设计者会提供一部分的数字,使谜题只有一个答案。答案满足同一个数字不可能在同一行、列或宫中出现多于一次。
2、算法
2.1 数独解题算法
最简单直接的算法就是:从第一个空格开始,尝试填入数字;之后再尝试下一个空格;如果失败,就回退,成功就继续,直至所有空格填满。具体如下:
(1)使用9X9二维矩阵表示数独局面,0表示空格,非零表示已经填写数字。从第一个元素开始,转步骤(2)
(2)搜索下一个空格。
(2-1)搜索到空格,转步骤(3);
(2-2)搜索不到空格,说明所有空格填写完毕,搜索到一个成功解题方案,结束程序。
(3)按照数独规则搜索当前空格可填写的数字集合。
(3-1)搜索不到可填写数字。当前方案不可行,将当前格恢复为0,回退一步,重新填写当前格数字。
(3-2)搜索到可填写的数字集合。从集合中取出一个数字,填入当前格。转步骤(2)。
第(2)、(3)步可以用递归程序实现,比较好实现回退和继续搜索功能。
这个算法简单粗暴,求解一般的数独题目都没有问题。但是在后续出题程序中,用这个算法测试出题结果是否可行时,经过大量随机数据测试,发现以下问题:
(1)效率低。有时甚至程序长时间运行不出结果,只能强行中止。
(2)一次只能搜索一个解法,不能测试题目的求解结果是否唯一。
分析问题(1)的原因主要在于初始搜索的可选数字较多,造成程序需要搜索方案数目剧增。因此,可以计算当前局面中所有空格的可选数字数目,从最小可选数字数目空格开始尝试填写数字。这样可以大大减少需要搜索方案数目。同时,为了避免频繁计算所有空格的可选数字数目,将搜索到的空格的可选数字集合存起来,在设置空格新数字、回退时更新相关空格的可选数字集合。
问题(2)的原因在于搜索到一个方案就结束,可以设置搜索的可行方案数目上限(上限设置为2就可以搜索求解方案是否唯一),达不到上限就回退继续搜索。
修改后的算法如下:
(1)使用9X9二维矩阵表示数独局面,0表示空格,非零表示已经填写数字。设置求解方案数目上限为NUP,搜索当前局面所有空格的可选数字集合,存入二维数组lsava中。转步骤(2)
(2)根据lsava,搜索可选数字数目最小的空格。
(2-1)搜索到空格,转步骤(3);
(2-2)搜索不到空格,说明所有空格填写完毕。搜索到一个成功解题方案,存储当前成功方案至成功方案列表。如果成功方案列表总数等于NUP,结束程序;否则将当前格恢复为0,恢复相关空格可选数字集合至lsava,回退一步,重新填写当前格数字。
(3)从lsava中取得当前空格可填写的数字集合。
(3-1)数字集合为空。当前方案不可行,将当前格恢复为0,恢复相关空格可选数字集合至lsava。回退一步,重新填写当前格数字。
(3-2)搜索到可填写的数字集合。从集合中取出一个数字,填入当前格。更新相关空格可选数字集合至lsava,同时暂存更新之前的集合,用于后续可能的回退操作。转步骤(2)。
2.2 数独出题算法
出题方法一:
最先想到的出题方法是仿照解题过程,从空盘开始逐渐填写数字:
- 从全部为空的局面开始;
- 在所余空格中随机挑选一个;
- 在选定空格的可用数字集合中随机挑选一个数字填入空格;
- 利用数独解题算法判断当前局面是否有解,如果否,则回退一步,恢复当前空格,转到步骤(3);如果有解,进一步判断解是否唯一,如果唯一,则找到结果,返回,否则转步骤(2)。
该算法的实现详见3.2。运行后发现,尽管采用了2.1中的优化后求解策略,但是由于随机设置数字过程很容易出现很多不可解局面,耗费大量搜索时间,有时甚至无法在10分钟内求解出结果。
为了解决这个问题,查阅网络文献,有了出题方法二:
主要思路是从一个完成的数独结果开始,随机挖除一定数目的空格,然后再判断当前局面解是否唯一。这样就避免的无解情况,搜索效率大幅提升。
挖除的空格数目越多,题目求解难度越高,同时多解概率也越高。可以设置空格数目的上限和下限值,调节所出题目的难度。
方法2需要大量数独结果,本算法使用一个固定数独结果,通过随机交换1-9数字位置产生所需大量数独结果,理论上可以产生9!= 362880个结果。再考虑题目上随机位置挖洞,可以产生的数独题目足够用了。具体如下:
- 通过随机交换1-9数字位置,产生一个数独结果;
- 设置空格数目的上限和下限值;
- 随机产生上限空格个位置,挖空位置,并保存挖空前的数值。
- 从空格上限开始,向下限方向搜索;
- 填入一个挖空前的数字。判断当前局面结果是否唯一,如果唯一,则结束;否则继续步骤(5)。
- 如果搜索不到唯一解,转置步骤(1)尝试下一个数独结果。
3、算法实现
3.1 数独解题
主程序Shudu1.py,输入输出及程序调用。
'''' 数独搜索 读取用户输入文件,搜索结果。如果得不到结果,则提示失败。 ''' import sys import CShudu1 as csd # 主程序 if len(sys.argv)<2 : print("使用方法: ") print(sys.argv[0],"FileName") print("FileName为输入文件文件名称前缀,真正输入文件为 Filename.dat, 输出文件名称为FileName.res。") exit(1) fin=sys.argv[1]+".dat" fout=sys.argv[1]+".res" print("输入文件:",fin,"输出文件",fout) #初始化 cs=csd.CShudu() nret=cs.ReadData(fin) if nret!=0: print("读取输入文件错误!") exit(2) print("原始数据:") cs.PrintData() # 开始查找 cs.CalLsava() nr=cs.getNumRes(1) if len(cs.lsres)>=1 : print("成功找到{}个结果!".format(len(cs.lsres))) cs.loadres(0) cs.PrintData() nret=cs.WriteData(fout) if nret!=0: print("写输出文件错误!") exit(3) else : print("本题无解!")
|
子程序CShudu1.py,以类的形式封装数独解题算法。
import random ''' 封装为类的数独搜索 ''' class CShudu : def __init__(self): # 初始化 # 数据 self.clear() def clear(self): # 清除数据 #当前局面数据 self.data=[[0 for i in range(9)] for j in range(9)] #当前局面每个格子的可用数据列表 self.lsava=[[set() for i in range(9)] for j in range(9)] #找到的可行解列表 self.lsres=[] # 从保持data数据至lsres def saveres(self): self.lsres.append([self.data[i].copy() for i in range(9)]) #print("in saveres",self.lsres) # 从lsres装载数据至data def loadres(self,k): #print("in loadres",self.lsres) self.data=[self.lsres[k][i].copy() for i in range(9)] # 从文件读矩阵数据 def ReadData(self,fname) : try: f=open(fname,"r") except FileNotFoundError: #打开文件错误 return 1 for i in range(9): str=f.readline() lstr=str.split() #文件读取错误 if len(lstr) < 9 : return 2 self.data[i]=[int(lstr[j]) for j in range(9)] f.close() return 0 # 写矩阵数据至屏幕 def PrintData(self) : print("-"*40) for i in range(9): print(self.data[i]) # 写矩阵数据至文件 def WriteData(self,fname) : f=open(fname,"w") #打开文件错误 if not f : return 1 for i in range(9): s1='' for j in range(9): s1=s1+str(self.data[i][j])+" " s1=s1+'\n' f.write(s1) f.close() return 0 # 搜索位置(i,j)可用数字集合Sava def FindSava(self,i,j): Sava=set() Snava=set() for k in range(9): if self.data[i][k]>0 : Snava.add(self.data[i][k]) #行 if self.data[k][j]>0 : Snava.add(self.data[k][j]) #列 m=int(i/3)*3 n=int(j/3)*3 for k in range(m,m+3): for l in range(n,n+3): if self.data[k][l]>0 : Snava.add(self.data[k][l]) Sava= {i for i in range(1,10)}-Snava return Sava # 查找目前局面的可行方案数,搜索上限为nup: # 返回值:0,找不到可行方案;1,成功 # self.lsres,列表,存放找到的数独结果 def getNumRes(self,nup): nret=0 nmin=10 for i in range(9): for j in range(9): if self.data[i][j]==0 : if len(self.lsava[i][j])<nmin: nmin=len(self.lsava[i][j]) ni=i nj=j if nmin>9: self.saveres() nret=1 #print("In getNumRes,len(self.lsres),nret=",len(self.lsres),nret) #self.PrintData() return nret #找到一个方案 # 找到ni,nj点 #self.PrintData() Sava=self.lsava[ni][nj].copy() #print("In getNumRes1 ni,nj,Sava=",ni,nj,Sava) while len(Sava) > 0 : x=Sava.pop() self.data[ni][nj]=x ls1=self.UpdateLsava(ni,nj) #print("In getNumRes2, ni=",ni,"nj=",nj,"X=",x) nret=self.getNumRes(nup) #恢复 self.data[ni][nj]=0 self.RestoreLsava(ls1) if len(self.lsres)>=nup : break # 搜索完成 #print("In getNumRes3,len(self.lsres),nret=",len(self.lsres),nret) return nret #计算全部空格的可行数字列表 def CalLsava(self): for i in range(9): for j in range(9): if self.data[i][j]==0 : self.lsava[i][j]=self.FindSava(i,j) #更新指定格相关的数字列表,返回原始列表 def UpdateLsava(self,i,j): ls1=[] for k in range(9): if self.data[i][k]==0 : ls1.append((i,k,self.lsava[i][k].copy())) self.lsava[i][k]=self.FindSava(i,k) #行 if self.data[k][j]==0 : ls1.append((k,j,self.lsava[k][j].copy())) self.lsava[k][j]=self.FindSava(k,j) #列 m=int(i/3)*3 n=int(j/3)*3 for k in range(m,m+3): if k==i: continue for l in range(n,n+3): if l==j: continue if self.data[k][l]==0 : ls1.append((k,l,self.lsava[k][l].copy())) self.lsava[k][l]=self.FindSava(k,l) return ls1 #根据列表恢复Lsava def RestoreLsava(self,lsava): for i,j,s1 in lsava: self.lsava[i][j]=s1 # 进行一次数独出题 def set1(self): self.clear() Imax=60 #设置数字的格子上限 lb1=random.sample(range(81),Imax) lb=[] for k in lb1: i=int(k/9) j=k-i*9 lb.append((i,j)) #print("lb=",lb) self.CalLsava() nret=self.TrySetNext(lb,0) return nret # 递归尝试填充第k步 def TrySetNext(self,lb,k): nret=0 i,j=lb[k] Sava=self.lsava[i][j].copy() print("In TrySetNext,k,Sava=",k,Sava) while len(Sava)>0: m=Sava.pop() #尝试设置一个数字 self.data[i][j]=m ls1=self.UpdateLsava(i,j) #print("In TrySetNext,i,j,m=",i,j,m) #self.PrintData() #print("lsava=",self.lsava) self.lsres=[] #找到的方案数目 if k>20: n=self.getNumRes(2) else: n=1 self.lsres=[1,2] #print("In TrySetNext,len(self.lsres)=",len(self.lsres)) if len(self.lsres)>=2:#大于等于2个结果 #继续搜索下一个点 if (k+1<len(lb)): nret=self.TrySetNext(lb,k+1) if nret: break elif len(self.lsres)==1:#只有一个结果 nret=1 break #没有成功结果 #恢复,尝试下一个可用点 self.data[i][j]=0 self.RestoreLsava(ls1) #print("In TrySetNext,nret=",nret) return nret |
运行结果:
E:\程序\test\python\shudu>Shudu1.py data\1
输入文件: data\1.dat 输出文件 data\1.res
原始数据:
----------------------------------------
[7, 0, 0, 0, 0, 2, 0, 0, 1]
[3, 0, 0, 0, 5, 0, 0, 7, 0]
[0, 8, 1, 4, 0, 0, 3, 0, 0]
[0, 0, 0, 0, 6, 0, 0, 0, 0]
[0, 7, 3, 0, 0, 9, 0, 0, 2]
[0, 0, 8, 1, 4, 0, 5, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 8]
[0, 1, 5, 0, 3, 0, 0, 6, 0]
[0, 6, 0, 7, 0, 0, 9, 0, 5]
成功找到1个结果!
----------------------------------------
[7, 4, 6, 3, 9, 2, 8, 5, 1]
[3, 9, 2, 8, 5, 1, 4, 7, 6]
[5, 8, 1, 4, 7, 6, 3, 2, 9]
[1, 5, 9, 2, 6, 3, 7, 8, 4]
[4, 7, 3, 5, 8, 9, 6, 1, 2]
[6, 2, 8, 1, 4, 7, 5, 9, 3]
[9, 3, 7, 6, 2, 5, 1, 4, 8]
[8, 1, 5, 9, 3, 4, 2, 6, 7]
[2, 6, 4, 7, 1, 8, 9, 3, 5]
3.2 数独出题实现1
仿照解题过程,从空盘开始逐渐填写数字。
- 主程序SDSet1.py
''' 数独出题程序 出题结果存在在指定文件中。 ''' import sys import CShudu1 as sd # 主程序 if len(sys.argv)<3 : print("数独出题程序使用方法: ") print(sys.argv[0],"FileName N") print("FileName为输出文件文件名称前缀,第i个数独结果输出文件名称为FileName_i.dat;N为生成的数独题目数目。") exit(1) fout=sys.argv[1] nout=int(sys.argv[2]) #初始化 cs=sd.CShudu() # 开始出题 for i in range(nout): nr=cs.set1() fout=sys.argv[1]+"-"+str(i)+".dat" print("生成第",i+1,"个数独题目:",fout) cs.PrintData() nret=cs.WriteData(fout) if nret!=0: print("写输出文件错误!") exit(3) if len(cs.lsres)>=1 : cs.loadres(0) fout=sys.argv[1]+"-"+str(i)+".res" print("生成第",i+1,"个数独结果:",fout) cs.PrintData() nret=cs.WriteData(fout) if nret!=0: print("写输出文件错误!") exit(3) |
这里调用的子程序同3.1子程序CShudu1.py。
运行结果:
E:\程序\test\python\shudu>SDSet1.py data\t 1
生成第 1 个数独题目: data\t-0.dat
----------------------------------------
[3, 4, 0, 8, 1, 9, 2, 0, 5]
[2, 5, 0, 0, 3, 0, 4, 8, 1]
[0, 1, 0, 0, 2, 4, 9, 3, 0]
[0, 0, 0, 0, 5, 0, 0, 1, 6]
[0, 0, 0, 0, 0, 2, 0, 0, 0]
[0, 0, 3, 1, 0, 0, 5, 0, 2]
[0, 0, 0, 2, 4, 0, 8, 0, 0]
[4, 0, 0, 9, 0, 0, 1, 0, 0]
[0, 0, 1, 0, 8, 3, 0, 2, 0]
生成第 1 个数独结果: data\t-0.res
----------------------------------------
[3, 4, 7, 8, 1, 9, 2, 6, 5]
[2, 5, 9, 6, 3, 7, 4, 8, 1]
[6, 1, 8, 5, 2, 4, 9, 3, 7]
[9, 2, 4, 3, 5, 8, 7, 1, 6]
[1, 6, 5, 4, 7, 2, 3, 9, 8]
[8, 7, 3, 1, 9, 6, 5, 4, 2]
[7, 3, 6, 2, 4, 1, 8, 5, 9]
[4, 8, 2, 9, 6, 5, 1, 7, 3]
[5, 9, 1, 7, 8, 3, 6, 2, 4]
3.3 数独出题实现2
主要思路是从一个完成的数独结果开始,随机挖除一定数目的空格,然后再判断当前局面解是否唯一。
主程序SDSet2.py
''' 数独出题程序 出题结果存在在指定文件中。 ''' import sys import CShudu2 as sd # 主程序 if len(sys.argv)<3 : print("数独出题程序使用方法: ") print(sys.argv[0],"FileName N") print("FileName为输出文件文件名称前缀,第i个数独结果输出文件名称为FileName_i.dat;N为生成的数独题目数目。") exit(1) fout=sys.argv[1] nout=int(sys.argv[2]) #初始化 cs=sd.CShudu() # 开始出题 for i in range(nout): nr=cs.set2() if len(cs.lsres)==1 : fout=sys.argv[1]+"-"+str(i)+".dat" nb=0 for k in range(9):nb+=cs.data[k].count(0) print("生成第{}个数独题目:{}。题目中数字总数{}个。".format(i+1,fout,81-nb)) cs.PrintData() nret=cs.WriteData(fout) if nret!=0: print("写输出文件错误!") exit(3) cs.loadres(0) fout=sys.argv[1]+"-"+str(i)+".res" print("生成第",i+1,"个数独结果:",fout) cs.PrintData() nret=cs.WriteData(fout) if nret!=0: print("写输出文件错误!") exit(3) else: print("生成第",i+1,"个数独失败!") |
子程序CShudu2.py
import random ''' 封装为类的数独搜索 ''' class CShudu : def __init__(self): # 初始化 # 数据 self.clear() def clear(self): # 清除数据 #当前局面数据 self.data=[[0 for i in range(9)] for j in range(9)] #当前局面每个格子的可用数据列表 self.lsava=[[set() for i in range(9)] for j in range(9)] #找到的可行解列表 self.lsres=[] # 从保持data数据至lsres def saveres(self): self.lsres.append([self.data[i].copy() for i in range(9)]) #print("in saveres",self.lsres) # 从lsres装载数据至data def loadres(self,k): #print("in loadres",self.lsres) self.data=[self.lsres[k][i].copy() for i in range(9)] # 从文件读矩阵数据 def ReadData(self,fname) : try: f=open(fname,"r") except FileNotFoundError: #打开文件错误 return 1 for i in range(9): str=f.readline() lstr=str.split() #文件读取错误 if len(lstr) < 9 : return 2 self.data[i]=[int(lstr[j]) for j in range(9)] f.close() return 0 # 写矩阵数据至屏幕 def PrintData(self) : print("-"*40) for i in range(9): print(self.data[i]) # 写矩阵数据至文件 def WriteData(self,fname) : f=open(fname,"w") #打开文件错误 if not f : return 1 for i in range(9): s1='' for j in range(9): s1=s1+str(self.data[i][j])+" " s1=s1+'\n' f.write(s1) f.close() return 0 # 搜索位置(i,j)可用数字集合Sava def FindSava(self,i,j): Sava=set() Snava=set() for k in range(9): if self.data[i][k]>0 : Snava.add(self.data[i][k]) #行 if self.data[k][j]>0 : Snava.add(self.data[k][j]) #列 m=int(i/3)*3 n=int(j/3)*3 for k in range(m,m+3): for l in range(n,n+3): if self.data[k][l]>0 : Snava.add(self.data[k][l]) Sava= {i for i in range(1,10)}-Snava return Sava # 查找目前局面的可行方案数,搜索上限为nup: # 返回值:0,找不到可行方案;1,成功 # self.lsres,列表,存放找到的数独结果 def getNumRes(self,nup): nret=0 nmin=10 for i in range(9): for j in range(9): if self.data[i][j]==0 : if len(self.lsava[i][j])<nmin: nmin=len(self.lsava[i][j]) ni=i nj=j if nmin>9: self.saveres() nret=1 #print("In getNumRes,len(self.lsres),nret=",len(self.lsres),nret) #self.PrintData() return nret #找到一个方案 # 找到ni,nj点 #self.PrintData() Sava=self.lsava[ni][nj].copy() #print("In getNumRes1 ni,nj,Sava=",ni,nj,Sava) while len(Sava) > 0 : x=Sava.pop() self.data[ni][nj]=x ls1=self.UpdateLsava(ni,nj) #print("In getNumRes2, ni=",ni,"nj=",nj,"X=",x) nret=self.getNumRes(nup) #恢复 self.data[ni][nj]=0 self.RestoreLsava(ls1) if len(self.lsres)>=nup : break # 搜索完成 #print("In getNumRes3,len(self.lsres),nret=",len(self.lsres),nret) return nret #计算全部空格的可行数字列表 def CalLsava(self): for i in range(9): for j in range(9): if self.data[i][j]==0 : self.lsava[i][j]=self.FindSava(i,j) #更新指定格相关的数字列表,返回原始列表 def UpdateLsava(self,i,j): ls1=[] for k in range(9): if self.data[i][k]==0 : ls1.append((i,k,self.lsava[i][k].copy())) self.lsava[i][k]=self.FindSava(i,k) #行 if self.data[k][j]==0 and k!=i: ls1.append((k,j,self.lsava[k][j].copy())) self.lsava[k][j]=self.FindSava(k,j) #列 m=int(i/3)*3 n=int(j/3)*3 for k in range(m,m+3): if k==i: continue for l in range(n,n+3): if l==j: continue if self.data[k][l]==0 : ls1.append((k,l,self.lsava[k][l].copy())) self.lsava[k][l]=self.FindSava(k,l) return ls1 #根据列表恢复Lsava def RestoreLsava(self,lsava): for i,j,s1 in lsava: self.lsava[i][j]=s1 # 进行一次数独出题 def set2(self): self.clear() Iall=81 Imax=35 #设置有数字格子上限 Imin=30 #设置有数字格子下限 IBmax=Iall-Imin+1 IBmin=Iall-Imax NT=10000 #尝试的上限 nt=0 nret=0 while nt<NT : nt+=1 #设置数据 self.setObj() #将要挖空格的位置 lb1=random.sample(range(Iall),IBmax) lb=[] for k in lb1: i=int(k/9) j=k-i*9 lb.append((i,j,self.data[i][j])) #print("lb=",lb) for k in range(IBmax): i,j,d=lb[k] self.data[i][j]=0 self.CalLsava() for k in range(IBmax-1,IBmin-1,-1): i,j,d=lb[k] self.data[i][j]=d ls1=self.UpdateLsava(i,j) self.lsres=[] n=self.getNumRes(2) #print("In set2,nt,k,i,j,n=",nt,k,i,j,n) #print("In set2,len(self.lsres)=",len(self.lsres)) if len(self.lsres)==1:#只有一个结果 nret=1 break elif len(self.lsres)<1:#无结果 nret=0 break else: #2个结果 nret=2 if len(self.lsres)==1:#只有一个结果 break return nret
# 设置data为目标数据 def setObj(self): dobj=[ [9,7,6,4,3,2,8,5,1], [5,3,4,8,7,1,9,2,6], [1,8,2,5,9,6,4,7,3], [6,1,9,2,4,3,5,8,7], [7,5,3,1,8,9,6,4,2], [4,2,8,6,5,7,1,3,9], [3,4,7,9,6,5,2,1,8], [8,9,1,3,2,4,7,6,5], [2,6,5,7,1,8,3,9,4] ] m=random.sample(range(1,10),9) for i in range(9): for j in range(9): self.data[i][j]=m[dobj[i][j]-1]
|
运行结果:
E:\程序\test\python\shudu>SDSet2.py data\t 3
生成第1个数独题目:data\t-0.dat。题目中数字总数34个。
----------------------------------------
[0, 0, 0, 0, 2, 0, 6, 4, 9]
[0, 0, 0, 0, 0, 0, 0, 0, 7]
[0, 6, 3, 0, 5, 0, 1, 0, 0]
[7, 0, 5, 3, 0, 0, 4, 0, 0]
[0, 0, 0, 0, 6, 5, 0, 1, 0]
[1, 0, 0, 0, 0, 8, 9, 2, 5]
[0, 0, 8, 5, 0, 4, 0, 0, 0]
[0, 5, 9, 2, 3, 0, 0, 0, 4]
[0, 0, 4, 8, 0, 6, 2, 5, 0]
生成第 1 个数独结果: data\t-0.res
----------------------------------------
[5, 8, 7, 1, 2, 3, 6, 4, 9]
[4, 2, 1, 6, 8, 9, 5, 3, 7]
[9, 6, 3, 4, 5, 7, 1, 8, 2]
[7, 9, 5, 3, 1, 2, 4, 6, 8]
[8, 4, 2, 9, 6, 5, 7, 1, 3]
[1, 3, 6, 7, 4, 8, 9, 2, 5]
[2, 1, 8, 5, 7, 4, 3, 9, 6]
[6, 5, 9, 2, 3, 1, 8, 7, 4]
[3, 7, 4, 8, 9, 6, 2, 5, 1]
生成第2个数独题目:data\t-1.dat。题目中数字总数33个。
----------------------------------------
[1, 0, 0, 0, 0, 0, 0, 0, 0]
[2, 0, 0, 0, 5, 0, 1, 8, 0]
[0, 7, 8, 2, 1, 0, 6, 5, 3]
[0, 0, 1, 0, 6, 3, 0, 7, 5]
[0, 0, 3, 4, 7, 0, 0, 0, 0]
[6, 0, 0, 0, 0, 0, 4, 0, 0]
[3, 0, 0, 1, 0, 0, 0, 0, 7]
[0, 1, 0, 3, 0, 6, 5, 0, 0]
[0, 9, 0, 5, 0, 7, 3, 0, 0]
生成第 2 个数独结果: data\t-1.res
----------------------------------------
[1, 5, 9, 6, 3, 8, 7, 2, 4]
[2, 3, 6, 7, 5, 4, 1, 8, 9]
[4, 7, 8, 2, 1, 9, 6, 5, 3]
[9, 4, 1, 8, 6, 3, 2, 7, 5]
[5, 2, 3, 4, 7, 1, 9, 6, 8]
[6, 8, 7, 9, 2, 5, 4, 3, 1]
[3, 6, 5, 1, 9, 2, 8, 4, 7]
[7, 1, 4, 3, 8, 6, 5, 9, 2]
[8, 9, 2, 5, 4, 7, 3, 1, 6]
生成第3个数独题目:data\t-2.dat。题目中数字总数35个。
----------------------------------------
[0, 0, 0, 1, 4, 0, 0, 2, 0]
[2, 4, 0, 0, 6, 9, 7, 0, 8]
[0, 3, 0, 0, 0, 8, 0, 6, 4]
[8, 9, 0, 5, 0, 0, 0, 0, 0]
[0, 0, 4, 9, 3, 0, 0, 1, 0]
[1, 0, 0, 8, 2, 6, 9, 4, 0]
[4, 0, 6, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 4, 0, 1, 0, 8, 2]
[5, 8, 2, 0, 0, 0, 0, 0, 0]
生成第 3 个数独结果: data\t-2.res
----------------------------------------
[7, 6, 8, 1, 4, 5, 3, 2, 9]
[2, 4, 1, 3, 6, 9, 7, 5, 8]
[9, 3, 5, 2, 7, 8, 1, 6, 4]
[8, 9, 7, 5, 1, 4, 2, 3, 6]
[6, 2, 4, 9, 3, 7, 8, 1, 5]
[1, 5, 3, 8, 2, 6, 9, 4, 7]
[4, 1, 6, 7, 8, 2, 5, 9, 3]
[3, 7, 9, 4, 5, 1, 6, 8, 2]
[5, 8, 2, 6, 9, 3, 4, 7, 1]
Python学习案例2——数独解题及出题程序相关推荐
- python漂亮界面 数独游戏源代码_使用Python编写数独游戏自动出题程序
原标题:使用Python编写数独游戏自动出题程序 数独是一个很好玩的游戏,可以锻炼推理能力.下面的代码可以自动生成数独游戏题目. fromrandom importshuffle, randrange ...
- python递归算法案例教案_Python电子教案2-1-Python程序实例解析.ppt
Python电子教案2-1-Python程序实例解析.ppt 简单说,eval()的作用是将输入的字符串内容变成Python语句,并执行这个语句.实例代码1.1使用eval()函数将用户的部分输入(T ...
- python数独游戏源代码_使用Python编写数独游戏自动出题程序
数独是一个很好玩的游戏,可以锻炼推理能力.下面的代码可以自动生成数独游戏题目. from random import shuffle, randrange def generate(): # 初始网格 ...
- 数独游戏python制作_使用Python编写数独游戏自动出题程序
数独是一个很好玩的游戏,可以锻炼推理能力.下面的代码可以自动生成数独游戏题目. from random import shuffle, randrange def generate(): # 初始网格 ...
- 使用Python编写数独游戏自动出题程序
数独是一个很好玩的游戏,可以锻炼推理能力.下面的代码可以自动生成数独游戏题目. from random import shuffle, randrange def generate(): # ...
- python学习案例——中国人口统计
import numpy as np import matplotlib as mpl import matplotlib.pyplot as pltmpl.rcParams['font.sans-s ...
- Python综合案例—利用tkinter实现计算器的程序
目录 一.导入 tkinter 库 定义全局变量 二.定义回调函数 三.创建窗口对象 四.创建标签控件 五.创建数字按钮 六.创建加.减.乘.除和等于按钮 七.创建清空按钮 八.总结 用Python实 ...
- 数独解题程序的python实现_python实现自动解数独小程序
跟朋友最近聊起来数独游戏,突发奇想使用python编写一个自动计算数独解的小程序. 数独的规则不再过多阐述,在此描述一下程序的主要思路: (当前程序只针对于简单的数独,更复杂的还待深入挖掘) 1.计算 ...
- Python项目实战学习案例--股票模拟交易系统
Python学习案例–股票模拟交易系统 源代码地址:https://gitee.com/wujize188_admin/mini_stock.git 主要技术 后台:Flask框架,sqlalchem ...
最新文章
- bitcoin全节点部署及bitcoind bitcoin-cli命令使用解释
- 160个Crackme004
- C#中提示:当前上下文中不存在名称“ConfigurationManager”
- Java中 synchronized 关键字的理解
- bzoj 3343 教主的魔法 分块
- 通过 Service 访问 Pod - 每天5分钟玩转 Docker 容器技术(136)
- Loading动画加载素材模板,UI设计师好帮手
- Flutter基础布局组件及实现
- 我的2009:知识管理篇
- [转]Asp.Net下导出/导入规则的Excel(.xls)文件
- 给新服务器装linux系统,新服务器安装linux系统安装教程
- LaTeX下载安装-1
- jclasslib安装
- 战神引擎传奇手游源码【诛仙玛法单职业五大陆】
- 0014 UVA1589 象棋 Xiangqi
- 实战案例!使用 Python 进行 RFM 客户价值分析!
- Allegro-PCB导入DXF文件
- 国科大学习资料--人工智能原理与算法-第十四次作业解析(学长整理)
- 计算机论文课题来源,浅析论文题目的来源和意义
- 上线切换 - 如何导入在制品
热门文章
- 从零搭建开发脚手架 Spring Boot集成Mybatis-plus之一
- 阿里云ECS服务器 跨域Access-Control-Allow-Origin 问题
- 红外温度传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
- 直播预告|ICML专场最后一场啦!来蹲守直播间呀
- 能编程100行的c语言题目,C语言编程100题
- BAT机器学习面试1000道
- 树莓派与win10主机传输文件方式(未完,占坑)
- 吉林大学计算机李昕,本报新聘百名特约教工通讯员
- 每逢佳节胖三斤? 春节过后天猫上家用健身机3天被疯抢10万台
- HPUX 11iV3 LVM新变化