使用基本的算法,实现数独游戏的填值

来源:互联网 发布:淘宝网实时销售额 编辑:程序博客网 时间:2024/06/05 15:24

可以实现简单级别的数独填值,经本人验证,目前测试的是难度系数在2.0一下的都没有问题,后面会考虑接入神经网络的自组织学习方法,来实现自动的识别高难度系数的数独计算

# encoding: utf-8"""九宫格算法"""import copy  class Numobj(object):    def __init__(self):        self.num_idx = range(1,82,1)   # 所有数独数字的索引        self.num = None               # 该索引确定的值        self.dic_num = dict()      # 索引所对应的全盘的值        self.ok_num = 0            # 记录自动填写的值的数量        self.small_9_no_can = []   # 其他小九宫空格的不能填数字        # 九宫格所对应的各个编码的索引序列,如下图示例        """        ####################        # 11#12#10#        # # # ## ##        # 21#22#20#        # # ## # ##        # 01#02#00#        #################        """        self.R9key_dic = {'11':[0,1,2,9,10,11,18,19,20],                        '12':[-1,0,1,8,9,10,17,18,19],                        '10':[-2,-1,0,7,8,9,16,17,18],                        '21':[-9,-8,-7,0,1,2,9,10,11],                        '22':[-10,-9,-8,-1,0,1,8,9,10],                        '20':[-11,-10,-9,-2,-1,0,7,8,9],                        '01':[-18,-17,-16,-9,-8,-7,0,1,2],                        '02':[-19,-18,-17,-10,-9,-8,-1,0,1],                        '00':[-20,-19,-18,-11,-10,-9,-2,-1,0]}     def setNum(self,idx,num):        """        设置索引字典的确定的值        :param idx:  当前的字典索引        :param num:  当前字典索引的值        :return:        """        self.dic_num[idx] = num        print "idx = %d 填value= %d" % (idx, num)     def getNum(self,idx):        """        找到指定索引的值        :param idx: 指定索引        :return:        """         # 如果有值,则不需要进行判断,没值才需要判断        if self.dic_num[idx] is not None:            return         # 获得行和列的并集        # unionlist1:表示idx 所在行,列值的并集        linenum, rownum,union_idx = self.getRCSet(idx,"U")         m9list = []   # 小九宫存在数字        mkey = self.R9key_dic[str(linenum%3)+str(rownum%3)]        self.small_9_no_can = []   # 此处需要清理一下之前数据        for key in mkey:            mvalue = self.dic_num[idx+key]            if mvalue is not None:                m9list.append(mvalue)            if key == 0:                continue            else:                # 得到小九宫中,不能填写的值列表                if mvalue is None:                    lm_9_other, rm_9_other,union_9_other = self.getRCSet((idx+key),"U")                    self.small_9_no_can.append(union_9_other)                #    idx_9_other_union_all = self.getListUnion(idx_9_other_union_all,union_9_other)         union_all_idx = self.getListUnion(union_idx,m9list)        self.GetNoValue(idx,union_all_idx)     def getRCSet(self,idx,flag=None):        """        获得行和列的已知元素集合        :param idx:该元素的索引        :param flag:判断使用并集还是交集        :return:行列元素的集合        """        linenum = (idx-1) / 9 +1  # 当前行号        rlist = []    # 横行的存在数字         rownum = (idx-1) % 9 +1   # 当前列号        clist = []    # 纵行存在数字         for i in xrange(9):            rvalue = self.dic_num[((linenum-1)*9 +1 + i)]            cvalue = self.dic_num[(rownum + 9 * i)]            if rvalue is not None:                rlist.append(rvalue)            if cvalue is not None:                clist.append(cvalue)         if flag == "U" or flag is None:   # 并集            unionlist = self.getListUnion(rlist,clist)            return linenum,rownum,unionlist        elif flag == "N":   # 交集            insectlist = list(set(rlist).intersection(set(clist)))            return insectlist     def getListUnion(self,a,b):        """        获取数组的并集        :param a:数组        :param b:数组        :return:a,b数组的并集        """        return list(set(a).union(set(b)))     def GetNoValue(self, idx, union_all_idx):        """        提取行,列,小九宫中相同的值,找到没有的1-9的数值,如果大于两个,则废弃,如果有一个,则继续        :param union_all_idx: idx所在的行,列及小九宫所有值得并集        :param idx_9_other_union_all:idx所在小九宫,其他已经存在值得行,列的并集        :return:        """        l_novalue = [] # 可填的值列表        if idx == 2:            print "union_all_idx = %s" % union_all_idx            print "self.small_9_no_can = %s" % self.small_9_no_can        #    exit(0)     #    print "union_all_idx = %s" % union_all_idx        for i in range(1,10):            if i not in union_all_idx:     # 所填值不能出现在已知的行,列和小九宫内                l_novalue.append(i)            else:                continue        if len(l_novalue) == 0:            print "值已经填错,请检查"            exit(0)         if len(l_novalue) > 1:            # 将该数组的九宫格的所有已知数字的相关数字全部拿出来,再次比较,从中排除可能的选项,从而确定必须填的值            tempvalue = []            cangetvalue = self.getOptimiseVlue(l_novalue,self.small_9_no_can)            if cangetvalue is not None:                self.setNum(idx,cangetvalue)                self.ok_num += 1            pass        else:            print "when idx =%d ,l_novalue = %s" % (idx,l_novalue)            self.setNum(idx,l_novalue[0])            self.ok_num += 1     def getOptimiseVlue(self,waitvalue,l_other_9_no_value):        """        得到一个不确定值得唯一值        :param waitvalue: 等待选择的值列表        :param l_other_9_no_value: 其他小九宫的不能选数值        :return: 唯一可以选填的值        """        if len(waitvalue) == 0:            return None        else:            selectlist = []    # 可选择的值得列表            for objw in waitvalue:                canflag = True      # 此值是否可用                for i in xrange(len(l_other_9_no_value)):                    if objw in l_other_9_no_value[i]:                        continue                    else:                        canflag = False                        break                if canflag:                    selectlist.append(objw)            if len(selectlist) == 1:                return selectlist[0]            else:            #    print "无法得出需要的值,备选项不满足情况=%s" % selectlist                return None      def SetInitValue(self,vlist = None):        """        设置初始的九宫格数据        :param vlist: 初始数据        """        if vlist is None:            for i in xrange(1,82):                self.dic_num[i] = i        else:            self.dic_num = copy.deepcopy(vlist)            self.CompleteInit()     def CompleteInit(self):        """        用于补全所有的值,未初始的则补全None        :return:        """        for i in xrange(1,82):            if self.dic_num.has_key(i):                continue            else:                self.dic_num[i] = None     def ConvertRC(self,line,row,value):        """        行列转换器        :param line: 行标        :param row: 列表        :param value: 设置的值        :return:        """        idx = (line-1) *9 + row        self.setNum(idx,value)     def getNoneNum(self):        """        得到未填写值得数量        :return: None值得数量        """        noneNum = 0        for i in xrange(1,82):            if self.dic_num[i] is None:                noneNum += 1        return noneNum if __name__ == "__main__":    mytest = Numobj()    # level 1    raw_vlist = {1:None,2:None,3:None,             4:None,5:None,6:None,                   7:None,8:None,9:None,                  10:None,11:None,12:None,          13:None,14:None,15:None,                16:None,17:None,18:None,                  19:None,20:None,21:None,          22:None,23:None,24:None,                25:None,26:None,27:None,                   28:None,29:None,30:None,         31:None,32:None,33:None,             34:None,35:None,36:None,                  37:None,38:None,39:None,         40:None,41:None,42:None,             43:None,44:None,45:None,                  46:None,47:None,48:None,         49:None,50:None,51:None,              52:None,53:None,54:None,                   55:None,56:None,57:None,         58:None,59:None,60:None,             61:None,62:None,63:None,                  64:None,65:None,66:None,         67:None,68:None,69:None,             70:None,71:None,72:None,                  73:None,74:None,75:None,         76:None,77:None,78:None,              79:None,80:None,81:None}      raw_vlist1 = {1:None,2:None,3:2,             4:6,5:9,6:None,                   7:5,8:8,9:None,                  10:8,11:None,12:None,          13:None,14:2,15:3,                16:6,17:None,18:None,                  19:7,20:None,21:6,          22:4,23:None,24:5,                25:2,26:None,27:None,                   28:2,29:None,30:9,         31:None,32:None,33:None,             34:3,35:None,36:None,                  37:5,38:None,39:1,         40:3,41:None,42:None,             43:9,44:7,45:8,                  46:6,47:3,48:7,         49:8,50:5,51:None,              52:4,53:2,54:1,                   55:9,56:None,57:8,         58:None,59:4,60:None,             61:1,62:3,63:2,                  64:None,65:6,66:None,         67:None,68:None,69:None,             70:7,71:None,72:9,                  73:None,74:2,75:None,         76:9,77:None,78:None,              79:8,80:None,81:6}      # level 75    raw_vlist75 = {3:1,7:6,11:5,12:9,15:2,19:4,24:6,27:2,31:8,32:7,35:1,37:2,41:9,45:7, \                 47:4,50:5,51:3,55:8,58:5,63:6,67:1,70:7,71:9,75:4,79:5}     mytest.SetInitValue(raw_vlist1)    print mytest.dic_num    j =0           # 当前计算的轮次    while mytest.getNoneNum()>0:        print "当前剩余None的值 = %d" % mytest.getNoneNum()        j+=1        print "当前第%d轮猜值" % j        for i in xrange(1,82):            mytest.getNum(i)        print "猜对的值= %d" % mytest.ok_num        if j > 100:            print "数值有问题,无解!!!"            break    print "未猜对的None值数量为:%d" % mytest.getNoneNum()    for i in xrange(1,82):        if (i-1)%9 == 0:            print "\n"        print mytest.dic_num[i],


0 0
原创粉丝点击