数独sudoku
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
- 数字
1-9
在每一行只能出现一次。 - 数字
1-9
在每一列只能出现一次。 - 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。
类似的
https://www.cnblogs.com/ansver/p/9034095.html
python穷举法解数独
总体思路 :
数独九行九列,一个list装一行,也就需要一个嵌套两层的list
初始会有很多数字,我可不想一个一个赋值
那就要想办法偷懒啦
然后再是穷举,如何科学的穷举
可破解中等难度数独(耗时约50~200ms),但对于超难数独不能短时破解,算法有待改善。
默认赠送一个数独.游戏模式选择“1”时,可修改此数独进行游戏(数独空处请填0)。
工具
anaconda-Jupyter Notebook
mac终端运行 /anaconda3/bin/jupyter_mac.command
jupyter notebook 这个不行
一、jupyter notebook里ipynb文件转为py文件
法一:
在xxx.ipynb所在目录下,打开终端,并输入命令:
jupyter nbconvert --to script xxx.ipynb
其中xxx.ipynb是要转换文件的名字,转换后在该目录下出现xxx.py文件。
法二:
启动Jupyter notebook
在网页下找打ipynb文件,然后
选择file--download as--python file
二、jupyter notebook 加载py文件(即转为ipynb文件)
In [ ]:%run xxx.py
加载了 xxx.py文件,相当于导包。
In [ ]:%load xxx.py
把 xxx.py的代码显示出来。
这句代表是王八github上
# Node.js JavaScript runtime :sparkles::turtle::rocket::sparkles:
数独.py
https://github.com/fibncci/fbCode/blob/master/suduku.ipynb
default_data = [[0,0,8,0,4,0,0,0,0],[0,0,0,0,0,9,0,8,2],[0,0,0,5,0,6,7,9,1],[5,4,0,0,0,0,0,0,0],[7,0,0,0,0,0,0,0,8],[0,0,0,0,0,0,0,7,3],[3,1,6,2,0,4,0,0,0],[8,5,0,1,0,0,0,0,0],[0,0,0,0,6,0,1,0,0]]
def get_data(): #初始化,输入数独数据data
data = []
for n in range(9):
data.append(list(map(int, input('Enter {}th line:'.format(n+1)).split())))
print('Your data:')
print_sudoku(data)
return data
def interface(): #提高用户体验
print('***Method 1: Modify the default sudoku***')
print('***Method 2: Through input method***\n')
while True:
choice = input('Please select the data input method:1 or 2\n')
if choice == '1':
data = default_data
break
elif choice == '2':
while True:
data = get_data()
check = input('Confirm? Y or N\n')
if check == 'Y' or check == 'y':
break
break
else:
print('Error, chooce again~')
return data
def print_sudoku(data): #打印最终数独破解结果
for i in range(9):
for j in range(9):
print('{:^3}'.format(data[i][j]),end='')
print('')
def build_data_list(data): #初始化,未每个空位建立备选数字列表
data_list = []
for y in range(9):
for x in range(9):
if data[y][x] == 0:
data_list.append([(x, y), [1, 2, 3, 4, 5, 6, 7, 8, 9]])
return data_list
def judge(data, x, y, num): #关键函数一,判断数字是否重复,是否允许填入
if data[y].count(num) > 0: #行判断
#print('error1')
return False
for col in range(9): #列判断
if data[col][x] == num:
#print('error2')
return False
for a in range(3): #九宫格判断 求整数,让计算机认识
for b in range(3):
if data[a+3*(y//3)][b+3*(x//3)] == num:
#print('error3')
return False
return True
def data_list_filter(data, data_list, start):
for blank_index in range(start, len(data_list)):
data_list[blank_index][1] = []
for num in range(1,10):
if judge(data, data_list[blank_index][0][0], data_list[blank_index][0][1], num):
data_list[blank_index][1].append(num)
return data_list
def fill_num(data, data_list, start):
#关键函数二,对有多个备选数字的位置循环猜数字。
#类似深度优先遍历算法,一旦某位置的数字judge为True,
#则允许开始下一位置的猜测;若某位置为False,则忽略。
if start < len(data_list):
one = data_list[start]
for num in one[1]:
if judge(data, one[0][0], one[0][1], num):
data[one[0][1]][one[0][0]] = num
tem_data = fill_num(data, data_list, start+1)
if tem_data != None:
return tem_data
data[one[0][1]][one[0][0]] = 0
#有可能再往后猜了好几步后才发现前面错误,此时需要将过程中的所有赋值操作清零。
else:
return data
def main(): #主函数
try:
data = interface()
data_list = data_list_filter(data, build_data_list(data), 0)
newdata = fill_num(data, data_list, 0)
print('Answer:')
print_sudoku(newdata)
except:
print('Error occurred! please check your data~')
main()
例1
# default_data = [[0,0,8,0,4,0,0,0,0],
# [0,0,0,0,0,9,0,8,2],
# [0,0,0,5,0,6,7,9,1],
# [5,4,0,0,0,0,0,0,0],
# [7,0,0,0,0,0,0,0,8],
# [0,0,0,0,0,0,0,7,3],
# [3,1,6,2,0,4,0,0,0],
# [8,5,0,1,0,0,0,0,0],
# [0,0,0,0,6,0,1,0,0]]
答案:
***Method 1: Modify the default sudoku***
***Method 2: Through input method***
Please select the data input method:1 or 2
1
Answer:
1 9 8 7 4 2 3 6 5
6 7 5 3 1 9 4 8 2
4 3 2 5 8 6 7 9 1
5 4 3 6 7 8 2 1 9
7 6 1 9 2 3 5 4 8
2 8 9 4 5 1 6 7 3
3 1 6 2 9 4 8 5 7
8 5 4 1 3 7 9 2 6
9 2 7 8 6 5 1 3 4
例二:
# default_data = [[1 ,0 ,6 ,2 ,0 ,0 ,0 ,0 ,0 ],
# [0 ,0 ,0 ,4 ,0 ,0 ,8 ,2 ,0 ],
# [2 ,0 ,0 ,0 ,0 ,5 ,0 ,0 ,0 ],
# [0 ,8 ,0 ,0 ,4 ,0 ,0 ,0 ,7 ],
# [0 ,0 ,0 ,6 ,0 ,3 ,0 ,0 ,0 ],
# [5 ,0 ,0 ,0 ,1 ,0 ,0 ,4 ,0 ],
# [0 ,0 ,0 ,9 ,0 ,0 ,0 ,0 ,0 ],
# [0 ,3 ,9 ,0 ,0 ,4 ,0 ,0 ,0 ],
# [0 ,0 ,0 ,0 ,0 ,2 ,9 ,0 ,5 ]]
Answer:
1 4 6 2 7 8 5 9 3
7 5 3 4 9 6 8 2 1
2 9 8 1 3 5 4 7 6
3 8 1 5 4 9 2 6 7
9 7 4 6 2 3 1 5 8
5 6 2 8 1 7 3 4 9
6 2 5 9 8 1 7 3 4
8 3 9 7 5 4 6 1 2
4 1 7 3 6 2 9 8 5
例三
default_data = [[0,0,9,0,4,7,0,0,0],[0,0,0,0,0,0,1,0,6],[0,8,0,0,2,0,0,0,0],[8,0,1,0,0,3,0,0,0],[0,7,3,0,0,0,0,0,0],[0,0,0,0,0,0,0,5,4],[0,0,0,2,0,0,0,0,1],[3,0,0,0,0,9,0,7,0],[0,9,0,8,0,6,0,4,0],[],[]]
Answer:
2 1 9 6 4 7 5 8 3
7 3 4 9 8 5 1 2 6
6 8 5 3 2 1 4 9 7
8 5 1 4 9 3 7 6 2
4 7 3 5 6 2 8 1 9
9 2 6 7 1 8 3 5 4
5 6 8 2 7 4 9 3 1
3 4 2 1 5 9 6 7 8
1 9 7 8 3 6 2 4 5
例四
***Method 1: Modify the default sudoku***
***Method 2: Through input method***
Please select the data input method:1 or 2
2
Enter 1th line: 1 0 6 2 0 0 0 0 0
Enter 2th line: 0 0 0 4 0 0 8 2 0
Enter 3th line: 2 0 0 0 0 5 0 0 0
Enter 4th line: 0 8 0 0 4 0 0 0 7
Enter 5th line: 0 0 0 6 0 3 0 0 0
Enter 6th line: 5 0 0 0 1 0 0 4 0
Enter 7th line: 0 0 0 9 0 0 0 0 0
Enter 8th line: 0 3 9 0 0 4 0 0 0
Enter 9th line: 0 0 0 0 0 2 9 0 5
Your data:
1 0 6 2 0 0 0 0 0
0 0 0 4 0 0 8 2 0
2 0 0 0 0 5 0 0 0
0 8 0 0 4 0 0 0 7
0 0 0 6 0 3 0 0 0
5 0 0 0 1 0 0 4 0
0 0 0 9 0 0 0 0 0
0 3 9 0 0 4 0 0 0
0 0 0 0 0 2 9 0 5
Confirm? Y or N
例五
选择2 ,空格随便打 。
***Method 1: Modify the default sudoku***
***Method 2: Through input method***
Please select the data input method:1 or 2
2
Enter 1th line:5 3 0 0 7 0 0 0 0
Enter 2th line:6 0 0 1 9 5 0 0 0
Enter 3th line:0 9 8 0 0 0 0 6 0
Enter 4th line:8 0 0 0 6 0 0 0 3
Enter 5th line:4 0 0 8 0 3 0 0 1
Enter 6th line:7 0 0 0 2 0 0 0 6
Enter 7th line:0 6 0 0 0 0 2 8 0
Enter 8th line:0 0 0 4 1 9 0 0 5
Enter 9th line:0 0 0 0 8 0 0 7 9
Your data:
5 3 0 0 7 0 0 0 0
6 0 0 1 9 5 0 0 0
0 9 8 0 0 0 0 6 0
8 0 0 0 6 0 0 0 3
4 0 0 8 0 3 0 0 1
7 0 0 0 2 0 0 0 6
0 6 0 0 0 0 2 8 0
0 0 0 4 1 9 0 0 5
0 0 0 0 8 0 0 7 9
Confirm? Y or N
Y
Answer:
5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
例6
***Method 1: Modify the default sudoku***
***Method 2: Through input method***
Please select the data input method:1 or 2
1
Answer:
1 2 3 4 5 6 7 8 9
4 6 5 7 8 9 3 1 2
9 7 8 3 1 2 4 5 6
5 3 2 8 4 7 9 6 1
7 9 1 6 3 5 2 4 8
6 8 4 9 2 1 5 7 3
3 1 6 2 7 4 8 9 5
8 5 7 1 9 3 6 2 4
2 4 9 5 6 8 1 3 7
default_data = [[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,8],
[0,0,0,0,0,0,0,7,3],
[3,1,6,2,0,4,0,0,0],
[8,5,0,1,0,0,0,0,0],
[0,0,0,0,6,0,1,0,0]]
10s
default_data = [[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,8],
[0,0,0,0,0,0,0,7,3],
[3,1,6,2,0,4,0,0,0],
[8,5,0,1,0,0,0,0,0],
[0,0,0,0,6,0,1,0,0]]
Answer:
1 2 3 4 5 6 7 8 9
4 6 5 7 8 9 2 1 3
7 8 9 3 1 2 4 5 6
2 3 1 5 4 7 6 9 8
5 9 7 6 2 8 3 4 1
6 4 8 9 3 1 5 2 7
3 1 6 2 9 4 8 7 5
8 5 2 1 7 3 9 6 4
9 7 4 8 6 5 1 3 2
default_data = [[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[8,5,0,1,0,0,0,0,0],
[0,0,0,0,6,0,1,0,0]]
Answer:
1 2 3 4 5 6 7 8 9
4 6 5 7 8 9 2 1 3
7 8 9 3 1 2 4 5 6
2 3 1 5 4 7 6 9 8
5 9 7 6 2 8 3 4 1
6 4 8 9 3 1 5 2 7
3 1 6 2 9 4 8 7 5
8 5 2 1 7 3 9 6 4
9 7 4 8 6 5 1 3 2
default_data = [[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,6,0,1,0,0]]
Answer:
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 2 1 3
7 8 9 1 2 3 4 5 6
2 1 4 3 7 5 6 9 8
3 6 7 2 9 8 5 4 1
5 9 8 6 1 4 3 2 7
6 3 1 8 4 2 9 7 5
9 7 2 5 3 1 8 6 4
8 4 5 9 6 7 1 3 2
default_data = [[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0]]
Answer:
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 2 1 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 7 8 9 1 5 2 4
5 9 8 2 4 7 3 6 1
6 3 1 5 7 2 9 4 8
8 7 2 9 1 4 6 3 5
9 4 5 6 3 8 1 7 2
--------------------------------------------------
Your data:
6 0 9 7 5 1 0 0 0
0 0 0 0 0 3 0 0 4
0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 8 0
0 0 8 0 6 7 0 0 0
0 0 0 0 0 9 1 5 6
1 5 0 2 0 0 4 0 0
0 0 0 0 0 0 0 0 5
7 0 0 0 0 0 0 6 0
Confirm? Y or N
Y
Answer:
6 4 9 7 5 1 2 3 8
5 2 1 9 8 3 6 7 4
3 8 7 6 4 2 5 1 9
2 6 5 1 3 4 9 8 7
9 1 8 5 6 7 3 4 2
4 7 3 8 2 9 1 5 6
1 5 6 2 7 8 4 9 3
8 9 4 3 1 6 7 2 5
7 3 2 4 9 5 8 6 1
数独界面
运行之后电脑自动重启
简单学习了tkinter库,做了GUI. 注意哦,我还没有加入错误判断语句,以及对于超难的数独解题速度极慢,
总之碰到这两种情况很可能会卡死、无响应,默默关掉重来就好…
数独gui.py
import tkinter as tk
def isValidSudoku(board): #判断Sudoku数据是否有效
for y in range(9):
for x in range(9):
if board[y][x] != 0:
if board[y].count(board[y][x]) > 1:
return False
for col in range(9):
if board[y][x] != 0 and col != y:
if board[col][x] == board[y][x]:
return False
for i in range(3):
for j in range(3):
if board[y][x] != 0 and (i+3*(y//3), j+3*(x//3)) != (y, x):
if board[i+3*(y//3)][j+3*(x//3)] == board[y][x]:
return False
return True
def get_sudoku():
window = tk.Tk()
window.title('Solve a Sudoku')
window.geometry('600x450')
width = 3
height = 1
labels = []
entrys = []
sudoku = [[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0]]
for i in range(81):
entrys.append(tk.Entry(window, width=width)) #初始化entrys
labels.append(tk.Label(window, width=3, height=1, bg='yellow')) #初始化labels
l1 = tk.Label(window, text='How to solve a SUDOKU?', bg='yellow', font=('Arial',15)) #设计标题
l1.place(x='170', y='15')
b1 = tk.Button(window, text='Just click here', bg='red', font=('Arial',12), command=lambda: get_data()) #设计按钮
b1.place(x='230', y='320')
for e in entrys:
e.place(x=str(entrys.index(e)%9*28+entrys.index(e)//3%3*6+20),
y=str(entrys.index(e)//9*24+entrys.index(e)//27*6+70)) #GUI中用来将数独矩阵分割成9个九宫格
def get_data(): #获取数独矩阵的值
for e in entrys:
sudoku[entrys.index(e)//9][entrys.index(e)%9] = int(e.get()) if e.get() != '' else 0
if isValidSudoku(sudoku): #判断输入的Sudoku是否有效
data = sudoku #将输入的数独代入算法中计算
data_list = data_list_filter(data, build_data_list(data), 0) #针对Sudoku中的每一个空格子,都算出其可能的备选数字,存入data_list中;每当空格被确认唯一值时,剩余data_list都需要再被刷新
newdata = fill_num(data, data_list, 0) #计算得到完整数独newdata
print_sudoku(newdata) #程序输出数独newdata
for l in labels:
labels[labels.index(l)]['text']= newdata[labels.index(l)//9][labels.index(l)%9] #将完整数独的值代入label中
l.place(x=str(labels.index(l)%9*28+labels.index(l)//3%3*6+300),
y=str(labels.index(l)//9*24+labels.index(l)//27*6+70)) #用labels将数独输出到GUI界面
else:
pass
window.mainloop()
def get_data(): #初始化,用来手动输入数独数据data
data = []
for n in range(9):
data.append(list(map(int, input('Enter {}th line:'.format(n+1)).split())))
print('Your data:')
print_sudoku(data)
return data
def print_sudoku(data): #打印最终数独破解结果
for i in range(9):
for j in range(9):
print('{:^3}'.format(data[i][j]),end='')
print('')
print('')
def build_data_list(data): #初始化,未每个空位建立备选数字列表data_list
data_list = []
for y in range(9):
for x in range(9):
if data[y][x] == 0:
data_list.append([(x, y), [1, 2, 3, 4, 5, 6, 7, 8, 9]])
return data_list
def judge(data, x, y, num): #关键函数一,判断数字是否重复,是否允许填入
if data[y].count(num) > 0: #行判断
#print('error1')
return False
for col in range(9): #列判断
if data[col][x] == num:
#print('error2')
return False
for a in range(3): #九宫格判断
for b in range(3):
if data[a+3*(y//3)][b+3*(x//3)] == num:
#print('error3')
return False
return True
def data_list_filter(data, data_list, start): #用来再次刷新备选数字
for blank_index in range(start, len(data_list)):
data_list[blank_index][1] = []
for num in range(1,10):
if judge(data, data_list[blank_index][0][0], data_list[blank_index][0][1], num):
data_list[blank_index][1].append(num)
return data_list
def fill_num(data, data_list, start): #关键函数二,对具有多个备选数字的位置依次尝试。类似深度优先遍历算法,一旦某位置的数字judge为True,则允许开始下一位置的猜测;若某位置为False,则忽略。
if start < len(data_list):
one = data_list[start]
for num in one[1]:
if judge(data, one[0][0], one[0][1], num):
data[one[0][1]][one[0][0]] = num
tem_data = fill_num(data, data_list, start+1)
if tem_data != None:
return tem_data
data[one[0][1]][one[0][0]] = 0 #有可能再往后猜了好几步后才发现前面错误,此时需要将过程中的所有赋值操作清零。
else:
return data
def main(): #主函数
try:
get_sudoku()
except:
print('Error occurred! please check your data~')
main()