利用python解决简单数独

相信大家对数独都不陌生。

不过笔者并不算十分忠实的数独玩家,但数独是一种规则和形式都十分简单的游戏。

于是萌生了用python来解决数独的想法。

第一条判断方式最为简单,也最容易实现。但是之后的思考模式代码化就不是很容易了。

计划以后添加更多判断方式。

所以最终的结果大概算是一个半成品,但已经能解决比较基本的数独。

示例如下:

 本来打算利用pyautogui实现完全的自动化的。但是考虑到不同的网页的数独呈现方式的差异可能会使得程序的局限性更大。于是采用了一种麻烦一点,但可以接受的方式进行数据输入。

用0来代表未知的数字,其他的数字则表示已知数字。

最终需要的就是下面那一行数字。(9*9的表示只是为了自己检查方便)

运行过程如下:

可以看到程序返回了完整数独。

测试文本如下:

028009000
000070180
700050002
000930570
050107004
410000060
630700200
105008403
000095700

028009000000070180700050002000930570050107004410000060630700200105008403000095700

 代码如下:


class Square():
    def __init__(self,position,num):
        self.position = position
        self.num = num

    def __str__(self):
        return '[%s,%s]'% (self.position,self.num)

    def getaround(self):
        aroundlist = []
        x = self.position[0]
        y = self.position[1]
        if 0 <= x <3:
            startx = 0
        elif 3 <= x <6:
            startx = 3
        else :
            startx = 6
        if 0 <= y < 3:
            starty = 0
        elif 3 <= y < 6:
            starty = 3
        else:
            starty = 6
        for each in wholepart:
            if startx <= each.position[0] < startx+3:
                if starty <= each.position[1] <starty+3:
                    aroundlist.append(each)
        return aroundlist

    def getaline(self):
        linelist = []
        for each in wholepart:
            if each.position[1] == self.position[1]:
                linelist.append(each)
        return linelist

    def getarow(self):
        rowlist = []
        for each in wholepart:
            if each.position[0] == self.position[0]:
                rowlist.append(each)
        return rowlist

def set(alist,num):
    returnlist = []
    typelist = [[0,3,0,3],[0,3,3,6],[0,3,6,9],\
        [3,6,0,3],[3,6,3,6],[3,6,6,9],\
        [6,9,0,3],[6,9,3,6],[6,9,6,9]]
    for i in alist:
        if typelist[num][0] <= i.position[0] <typelist[num][1] and \
            typelist[num][2] <= i.position[1] <typelist[num][3]:
            returnlist.append(i)
    return returnlist



# 生成整个棋局
wholepart = []
for row in range(9):
    for line in range(9):
        example = Square((row,line),[])
        wholepart.append(example)


replacelist = []
tolist = []
times = 0
enter = input('please enter:')
print(enter)
for i in enter:
    if i != '0':
        tolist.append(int(i))
        replacelist.append(times)
    times = times + 1

print(tolist)
print(replacelist)

h = dict(zip(replacelist,tolist))
for known,t in h.items():
    wholepart[known].num.append(t)

# 核心代码,计算填什么
# 1.通过交叉初步确定可以填的简单空
def caculate(originpart):
    check1=[] #用于递归判断是否凭借已有方法无法继续填空
    check2=[] #也就时对比本次递归和上一次递归的结果是否相同,相同则说明已到终点
    for i in originpart:
        check1.append(i.num)
    wholepart = originpart[:]
    for crossnum in range(1,10):
        copylist = wholepart[:]
        eightnumlist = []
        for h in wholepart:
            if h.num == [crossnum]:
                eightnumlist.append(h)
                copylist.remove(h)
        #         移除8方块
        for m in eightnumlist:
            doublecopylist = copylist[:]  #获得副本,避免跳删
            for t in doublecopylist:
                if t.position[0] == m.position[0] or \
                        t.position[1] == m.position[1]:
                    copylist.remove(t)
        #         移除8方块同行同列的元素
        anothercopylist = copylist[:]
        for h in anothercopylist:
            if h.num != []:
                copylist.remove(h)
        for k in range(9):
            processlist = set(copylist,k)
            if len(processlist) == 1:
                do = True
                for each in processlist[0].getaround():
                    if each.num == [crossnum]:
                        do = False
                if do:
                    processlist[0].num = [crossnum]
    for i in originpart:
        check2.append(i.num)
    if check1 == check2:
        return
    else :
        caculate(wholepart)

print('-'*40)

# 运算
caculate(wholepart)

# 通过确定某数字必在某条线上从而排除某条线
# 第二层逻辑未成功,有机会跟新(一下内容未使用)
def caculate2(originpart):
    wholepart = originpart[:]
    for crossnum in range(1, 10): #crossnum就是正在分析的可以填在哪里的数字
        copylist = wholepart[:]
        eightnumlist = []
        for h in wholepart:
            if h.num == [crossnum]:
                eightnumlist.append(h)
                copylist.remove(h)
        #         移除8方块
        for m in eightnumlist:
            doublecopylist = copylist[:]  # 获得副本,避免跳删
            for t in doublecopylist:
                if t.position[0] == m.position[0] or \
                        t.position[1] == m.position[1]:
                    copylist.remove(t)
        #         移除8方块同行同列的元素
        anothercopylist = copylist[:]
        for h in anothercopylist:
            if h.num != []:
                copylist.remove(h)
        nocrossnumlist = []
        for k in range(9):
            processlist = [i.num for i in set(wholepart, k)]
            if [crossnum] not in processlist:
                nocrossnumlist.append(k)
        # 检查是否在同一竖线上
        for every in nocrossnumlist:
            copynclist = nocrossnumlist[:]
            for everyother in copynclist.remove(every):
                checklist = set(copylist,everyother)
                removable = True
                x = [everySquare.position[0] \
                     for everySquare in checklist]
                y = [everySquare.position[0] \
                     for everySquare in checklist]
                startx = x[0]
                starty = y[0]
                for every in x:
                    if every != startx:
                        removable = False

                for every in y:
                    if every != starty:
                        removable = False




lne = 0
for i in wholepart:
    lne += 1
    if i.num != []:
        if not lne%9 == 0:
            print(i.num,end='')
        else:
            print(i.num,end='\n')
    else:
        if not lne % 9 == 0:
            print('[_]', end='')
        else:
            print('[_]', end='\n')





对于复杂的数独,这个程序也起到一种辅助的作用。

以上代码还有诸多不足,有很多看上去多余的部分是留着给更复杂的判断方式的。

欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值