infer

更新时间:2023-04-14 01:20:22 阅读: 评论:0


2023年4月14日发(作者:retina)

解数独算法

昨天在Ubuntu18.04上打开⾃带的数独游戏,宿舍⼏个⼈⼀起玩了很久,今天整理了⼀下玩的过程,研究出算法并写成程序,以⾃动求解数独游

戏,具体实现步骤已在代码注释中详细说明。

代码已发布在我的github上:HelloGithubHaHa

'''计算机⾃动解9x9数独游戏,输⼊题⽬后进⾏推断,若⽆法继续推断,则进⾏猜测,若猜测错误,则进⾏回溯,直到成功解出结果'''

'''题⽬信息保存在9x9的数组中,推断信息以t集合的形式存储于cheet_with_infer数组中''古代的四大美女 '

'''有两个主要的数据结构,⼀个是元素全为int的cheet_without_infer,⼀个是元素为int或t的cheet_with_infer'''

#需要⽤到深拷贝importcopy

defprint_cheet_without_infer(cheet):

'''打印没有推断信息的数组'''print()

forlineincheet:fornuminline:

print('{:^3}'.format(num),end='')print()

defprint_cheet_without_infer_to_input_again(cheet):

'''以与输⼊相同的格式,打印没有推断信息的数组,便于⼿动猜测后再次输⼊'''print()

forlineincheet:

print(','.join([str(x)forxinline]).replace('-1',''))

defprint_cheet_with_infer(cheet):

'''打印包含推断信息的数组'''print()

forlineincheet:forinferinline:

print('{:^15}'.format(str(infer).replace('','')),end='')print()

definfer(cheet,cheet_origin):'''

cheet为不包含推断信息的数组,cheet_origin为包含推断信息的数组

根据基本规则进⾏推断,每⼀个数所在⾏、列以及九宫格不能包含相同的数字

若数组中的所有元素都已经推断出,则返回2

若数组中的某个元素在此次函数调⽤中可以明确推断出,则返回1

若不能推断出任何未知元素,则返回0

若有错(某⼀位置的推断信息为空t集合),说明不满⾜任何数独的基本规则,返回-1'''

finish=True#如果数组中的所有元素都已经推断出,则finish为True

foriinrange(9):forjinrange(9):

ifcheet_origin[i][j]==-1:

finish=Fal#数组中尚有元素未推断出,finish为Fal

infer_t=t(range(1,10))#初始化推断信息

#通过⾏和列不能包含相同的数字进⾏推断forkinrange(9):

ifk!=jandcheet_origi创新英文 n[i][k]!=-1:

infer_d(cheet[i][k])

ifk!=iandcheet_origin[k][j]!=-1:infer_d(cheet[k][j])

#通过九宫格内不能包含相同的数字进⾏推断

x=j//3*3y=i//3*3

forminrange(y,y+3):forninrange(x,x+3):

if(m!=iorn!=j)andcheet_origin[m][n]!=-1:infer_d(cheet[m][n])

#判断此位置的推断信息,据此控制程序流程iflen(infer_t)==1:

cheet[i][j]=infer_()

cheet[i][j]=infer_()

cheet_origin[i][j]=cheet[i][j]return1

eliflen(infer_t)==0:

return-1el:

cheet[i][j]=infer_t

iffinish:

return2el:

return0

defpower_t(s):

'''求⼀个集合的所有⾮空真⼦集(⼆进制法),为了进⾏速度优化,需要在返回前对其进⾏排序'''

t_list=[]l=list(s)

n=len(l)

#⾮空,所以下界为1;真⼦集,所以上界是2的n次⽅

foriinrange(1,2**n-1):

combo=t()

forjinrange(n):

if(i>>j)%2==1:

(l[j])t_(combo)

t_list=sorted(t_list,key=lambdax:len(x))returnt_list

defdeep_infer(cheet,cheet_origin):'''

根据推断信息进⾏推断,去除某些位置的可能性数字

对于每⼀⾏、每⼀列、每⼀九宫格内的推断信息,

先求出这些推断信息的并集,再求出此并集的所有⾮空真⼦集,对于每⼀个⾮空真⼦集,

若推断信息中有⼩于等于此真⼦集⼤⼩数⽬的超集,并且对于其他推断信息,此真⼦集与其的交集均为空(不包含此真⼦集中的元素),

则这些位置的推断信息可置为此真⼦集

如某⼀⾏中有四个待推断元素,推断信息为:{1,3,6},{1,3,6},{1,4},{1,4}

在对其并集的⾮空真⼦集的遍历过程中,发现集合{3,6}的超集有{1,3,6}和{1,3,6},并且其他推断信息{1,4}与此集合{3,6}的交集为空,

因此,可以将两个推断信息{1,3,6}置为{3,6}

若不能推断出任何未知元素,则返回2

若数组中的某个元素在此次函数调⽤中可以明确推断出,则返回1

若推断信息在此次函数调⽤中有修改,则返回0'''

change=Fal#推断信息是否有修改的标志

#根据每⼀⾏已有的推断信息进⾏推断

foriinrange(9):

#求并集

union_t=t()forjinrange(9):

ifisinstance(cheet[i][j],t):

union_t=union_(cheet[i][j])

#遍历根据长度排序的所有⾮空真⼦集

forsinpower_t(union_t):

contain_t_list=[]#保存列号

finish=True#若此⾏中的所有列上的推断信息的长度都⼩于等于集合s的长度,则可以提前退出,finish为True

satisfy=True#若除了集合s的超集以外,此⾏还含有推断信息与集合s的交集不为空的位置,则不能进⾏推断,satisfy为Falforjinrange(9):

ifisinstance(cheet[i][j],t老师的师怎么写 ):

iflen(cheet[i][j])>len(s):finish=Fal

et(cheet[i][j]):

contain_t_(j)

eliflen(ection(cheet[i][j]))>0:

satisfy=Fal

iffinish:

break

ifnotsatisfy:continue

iflen(contain_t_list)<=len(s)andlen(contain_t_list)>0:

#若s长度为1,则表明已经明确推断出此位置的数字,于是将t中的元素提取出来放到此位置上iflen(s)==1:

j=contain_t_list[0]cheet[i][j]=()

cheet_origin[i][j]=cheet[i][j]

cheet_origin[i][j]=cheet[i][j]return1

forjincontain_t_list:

iflen(cheet[i][j])>len(s):

cheet[i][j]=()change=True

#根据每⼀列已有的推断信息进⾏推断,和前⾯类似

forjinrange(9):

union_t=t()foriinrange(9):

ifisinstance(cheet[i][j],t):

union_t=union_(cheet[i][j])

forsinpower_t(union_t):

contain_t_list=[]

finish=Truesatisfy=True

foriinrange(9):

ifisinstance(cheet[i][j],t):

iflen(cheet[i][j])>len(s):finish=Fal

et(cheet[i][j]):

contain_t_(i)

eliflen(ection(cheet[i][j]))>0:

satisfy=Fal

iffinish:

break

ifnotsatisfy:continue

iflen(contain_t_list)<=len(s)andlen(contain_t_list)>0:iflen(s)==1:

i=contain_t_list[0]cheet[i][j]=()

cheet_origin[i][j]=cheet[i][j]return1

foriincontain_t_list:

iflen(cheet[i][j])>len(s):

cheet[i][j]=()change=True

#根麸炒白术的功效 据每⼀九宫格已有的推断信息进⾏推断,和前⾯类似

forminrange(3):

forninrange(3):union_t=t()

foriinrange(m*3,m*3+3):

forjinrange(n*3,n*3+3):ifisinstance(cheet[i][j],t):

union_t=union_(cheet[i][j])

forsinpower_t(union_t):

contain_t_list=[]

finish=Truesatisfy=True

foriinrange(m*3,m*3+3):

forjinrange(n*3,n*3+3):

ifisinstance(cheet[i][j],t):

iflen(cheet[i][j])>len(s):

finish=et(cheet[i][j]):

contain_t_((i,j))

eliflen(ection(cheet[i][j]))>0:

satisfy=Fal

iffinish:

break

ifnotsatisfy:continue

iflen(冰草的功效与作用 contain_t_list)<=len(s)andlen(contain_t_list)>0:iflen(s)==1:

i,j=contain_t_list[0]cheet[i][j]=()

cheet_origin[i][j]=cheet[i][j]return1

fori,jincontain_t_list:

iflen(cheet[i][j])>len(s):

cheet[i][j]=()change=True

ifnotchange:

return2el:

return0

deffind_min_to_guess(cheet_with_infer):

'''找到并返回⼀个推断信息的长度最⼩的位置'''

min_length=10#初始化最⼩长度标记foriinrange(9):

forjinrange(9):

ifisinstance(cheet_with_infer[i][j],t):

length=len(cheet_with_infer[i][j])

ifmin_length>length:

min_length=length

m=i

n=jreturnm,n

defstart(cheet_with_infer,cheet_without_infer):

'''开始进⾏推断,若推断成功,则返回True,否则返回Fal'''whileTrue:

print_cheet_without_infer(cheet_without_infer)

res=infer(cheet_with_infer,cheet_without_infer)

ifres==1:

continue

elifres==2:

returnTrue

elifres==-1:returnFal

whileTrue:

res=deep_infer(cheet_with_infer,cheet_without_infer)

ifres==1:

breakelifres==2:

#⽆法继续进⾏推断,于是在推断信息长度最⼩的位置进⾏假设,然后继续进⾏推断(递归),若猜测错误,则进⾏回溯

print_cheet_without_infer_to_input_again(cheet_without_infer)

print_cheet_with_infer(cheet_with_infer)

print('Cannotcontinuerefer!Beginguess!')

i,j=find_min_to_guess(cheet_with_infer)fornumincheet_with_infer[i][j]:

new_cheet_with_infer=py(cheet_with_in收据单怎么写 fer)

new_cheet_without_infer=py(cheet_without_infer)

new_cheet_with_infer[i][j]=numnew_cheet_without_infer[i][j]=num

res=start(new_cheet_with_infer,new_cheet_without_infer)ifres:

cheet_with_()

cheet_with_(new_cheet_with_infer)cheet_without_()

cheet_without_(new_cheet_without_infer)returnTrue

el:

print('Guesrror,beginnextguess!')

#⽤户通过图形界⾯输⼊题⽬信息,程序通过图形界⾯展⽰结果importtkinter

ebox

definfer_handler():

#没有推断信息的数组

cheet_without_infer=[]

forlabelsinall_labels:

nums=[]

forlabelinlabels:iflabel['text']:

(int(label['text']))el:

(-1)

cheet_without_(nums)

#有推断信息的数组,推断信息在推断的过程中加⼊

cheet_with_infer=py(cheet_without_infer)

cheet_with_infer=py(cheet_without_infer)

#开始推断

res=start(cheet_with_infer,cheet_without_infer)ifnotres:

ror('题⽬信息有误,⽆法进⾏推断!')

foriinrange(9):forjinrange(9):

all_labels[i][j]['text']=str(cheet_without_infer[i][j])

defclear_handler():

forlabelsinall_labels:

forlabelinlabels:label['text']=''

defchange_bg(source,origin_color):

forlabelsinall_labels:

forlabelinlabels:

label['bg']=origin_color

source['bg']='skyblue'defkeyboard_handler(event):

t()e==8:

forlabelsinall_labels:forlabelinlabels:

iflabel['bg']=='skyblue':

e==8:

label['text']=''el:

label['text']=ot=()

ble(Fal,Fal)

('数独解题器')

_all('',keyboard_handler)

#九宫格⾯板

top_frame=(root)

top_()

all_labels=[]

foriinrange(9):

row_labels=[]forjinrange(9):

label=(top_frame,font=('',18),width=2,height=1,relief=)origin_color=label['bg']

('',lambdaevent披着狼皮的羊 ,label=label:change_bg(label,origin_color))

(row=i,column=j)

row_(label)

all_(row_labels)

#底部按钮⾯板

bottom_frame=(root)bottom_()

infer_button=(bottom_frame,text='推断',font=('',18),command=infer_h胡豆黄 andler)infer_(side=,padx=5,pady=5)

clear_button=(bottom_frame,text='清空',font=('',18),command=clear_handler)

clear_(side=,padx=5,pady=5)op()


本文发布于:2023-04-14 01:20:22,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/93210.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:retrieves
下一篇:nsitivity
标签:infer
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图