python实现求解八数码问题

哎,好久没写博文了,其实仔细想来,时间还是蛮多的,以后还是多写写吧!

之前看过经典的搜索路径方法,印象较深的也就BFS(广度优先),DFS(深度优先)以及A*搜索,但没实践过,就借八数码问题,来通通实现遍,观察下现象呗~~~

首先,怎么说也得把数码这玩意基本操作实现了呗!上代码~

class puzzled:
    def __init__(self,puzzled):
        self.puzzled=puzzled
        self.__getPuzzledInfo()
        
    def __getPuzzledInfo(self):
        self.puzzledWid=len(self.puzzled[0])
        self.puzzledHei=len(self.puzzled)
        self.__f1=False
        for i in range(0,self.puzzledHei):
            for j in range(0,self.puzzledWid):
                if(self.puzzled[i][j]==0):
                    self.zeroX=j
                    self.zeroY=i
                    self.__f1=True
                    break
            if(self.__f1):
                break
    def printPuzzled(self):
        for i in range(0,len(self.puzzled)):
            print self.puzzled[i]
        print ""
            
    def isRight(self):
        if(self.puzzled[self.puzzledHei-1][self.puzzledWid-1]!=0):
            return False
        for i in range(0,self.puzzledHei):
            for j in range(0,self.puzzledWid):
                if(i*self.puzzledWid+j+1!=self.puzzled[i][j]):
                    if(i!=self.puzzledHei-1 or j!=self.puzzledWid-1):
                        return False
        return True
    def move(self,dere):#0 up,1 down,2 left,3 right
        if(dere==0 and self.zeroY!=0):
            self.puzzled[self.zeroY-1][self.zeroX],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY-1][self.zeroX]
            self.zeroY-=1
            return True
        
        
        elif(dere==1 and self.zeroY!=self.puzzledHei-1):
            self.puzzled[self.zeroY+1][self.zeroX],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY+1][self.zeroX]
            self.zeroY+=1            
            return True
        
        
        elif(dere==2 and self.zeroX!=0):
            self.puzzled[self.zeroY][self.zeroX-1],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY][self.zeroX-1]
            self.zeroX-=1
            return True
        
        elif(dere==3 and self.zeroX!=self.puzzledWid-1):
            self.puzzled[self.zeroY][self.zeroX+1],self.puzzled[self.zeroY][self.zeroX] = self.puzzled[self.zeroY][self.zeroX],self.puzzled[self.zeroY][self.zeroX+1]
            self.zeroX+=1
            return True
        return False
    def getAbleMove(self):
        a=[]
        if(self.zeroY!=0):
            a.append(0)
        if(self.zeroY!=self.puzzledHei-1):
            a.append(1)
        if(self.zeroX!=0):
            a.append(2)
        if(self.zeroX!=self.puzzledWid-1):
            a.append(3)             
        return a
    def clone(self):
        a=copy.deepcopy(self.puzzled)
        return puzzled(a)
    def toString(self):
        a=""
        for i in range(0,self.puzzledHei):
            for j in range(0,self.puzzledWid):
                a+=str(self.puzzled[i][j])
        return a
    def isEqual(self,p):
        if(self.puzzled==p.puzzled):
            return True
        return False
    def toOneDimen(self):
        a=[]
        for i in range(0,self.puzzledHei):
            for j in range(0,self.puzzledWid):
                a.append(self.puzzled[i][j])
        return a
    
    
    def getNotInPosNum(self):
        t=0
        for i in range(0,self.puzzledHei):
            for j in range(0,self.puzzledWid):
                if(self.puzzled[i][j]!=i*self.puzzledWid+j+1):
                    if(i==self.puzzledHei-1 and j==self.puzzledWid-1 and self.puzzled[i][j]==0):
                        continue
                    t+=1
        return t
    def getNotInPosDis(self):
        t=0
        it=0
        jt=0
        for i in range(0,self.puzzledHei):
            for j in range(0,self.puzzledWid):
                if(self.puzzled[i][j]!=0):
                    it=(self.puzzled[i][j]-1)/self.puzzledWid
                    jt=(self.puzzled[i][j]-1)%self.puzzledWid
                else:
                    it=self.puzzledHei-1
                    jt=self.puzzledWid-1
                t+=abs(it-i)+abs(jt-j)
        return t    
    @staticmethod
    def generateRandomPuzzle(m,n,ran):
        
        tt=[]
        for i in range(0,m):
            t=[]
            for j in range(0,n):
                t.append(j+1+i*n)
            tt.append(t)
        tt[m-1][n-1]=0
        a=puzzled(tt)
        i=0
        while(i<ran):
            i+=1
            a.move(random.randint(0,4))
        return a

稍微注解一下,puzzled类表示一个数码类,初始化利用

a=puzzled(  [1,2,3],
            [4,5,6],
            [7,8,0])

其中呢,0表示空格位置,上面初始化的便是一个正确的,未被打乱的位置~

其他的成员函数,看名称就很好理解了呗~

ok,基础打好了,接下来就该上节点类了:

class node:
    def __init__(self,p):
        self.puzzled=p
        self.childList=[]
        self.father=None
    def addChild(self,child):
        self.childList.append(child)
        child.setFather(self)
    def getChildList(self):
        return self.childList
    def setFather(self,fa):
        self.father=fa
    def displayToRootNode(self):
        t=self
        tt=0
        while(True):
            tt+=1
            t.puzzled.printPuzzled()
            t=t.father
            if(t==None):
                break
        print "it need "+str(tt)+ " steps!"
    def getFn(self):
        fn=self.getGn()+self.getHn() #A*
        #fn=self.getHn() #贪婪
        return fn
        
    def getHn(self):
        Hn=self.puzzled.getNotInPosDis()
        return Hn
        
    def getGn(self):
        gn=0
        t=self.father
        while(t!=None):
            gn+=1
            t=t.father
        return gn

对于节点类吧,也还是很好理解的,初始化方法

    a=node(
    puzzled([1,2,3],
            [4,5,6],
            [7,8,0])
            )

基础都搭好了,重点任务该闪亮登场了呗~

class seartchTree:
    def __init__(self,root):
        self.root=root
        
    def __search2(self,hlist,m):  #二分查找,经典算法,从大到小,返回位置
                                  #若未查找到,则返回应该插入的位置
        low = 0   
        high = len(hlist) - 1   
        mid=-1
        while(low <= high):  
            mid = (low + high)/2  
            midval = hlist[mid]  
    
            if midval > m:  
                low = mid + 1   
            elif midval < m:  
                high = mid - 1   
            else:  
                return (True,mid)   
        return (False,mid)   
        
    def __sortInsert(self,hlist,m):#对于一个从大到小的序列,
                                    #插入一个数,仍保持从大到小
        t=self.__search2(hlist,m)
        if(t[1]==-1):
            hlist.append(m)
            return 0
        if(m<hlist[t[1]]):
            hlist.insert(t[1]+1, m)
            return t[1]+1
        else:
            hlist.insert(t[1], m)
            return t[1]    
    
    def breadthFirstSearch(self):#广度优先搜索
        numTree=NumTree.NumTree()
        numTree.insert(self.root.puzzled.toOneDimen())
        t=[self.root]
        flag=True
        generation=0
        while(flag):
            print "it‘s the "+str(generation)+" genneration now,the total num of items is "+str(len(t))
            tb=[]
            for i in t:
                if(i.puzzled.isRight()==True):
                    i.displayToRootNode()
                    flag=False
                    break
                else:
                    for j in i.puzzled.getAbleMove():
                        tt=i.puzzled.clone()
                        tt.move(j)
                        a=node(tt)
                        if(numTree.searchAndInsert(a.puzzled.toOneDimen())==False):
                            i.addChild(a)
                            tb.append(a)
            t=tb
            generation+=1
            
    def depthFirstSearch(self):#深度优先搜索
        numTree=NumTree.NumTree()
        numTree.insert(self.root.puzzled.toOneDimen())        
        t=self.root
        flag=True
        gen=0
        while(flag):
            bran=0
            print "genneration: "+str(gen)
            if(t.puzzled.isRight()==True):
                t.displayToRootNode()
                flag=False
                break
            else:
                f1=True
                for j in t.puzzled.getAbleMove():
                    tt=t.puzzled.clone()
                    tt.move(j)
                    a=node(tt)
                    if(numTree.searchAndInsert(a.puzzled.toOneDimen())==False):
                        t.addChild(a)
                        t=a
                        f1=False
                        gen+=1
                        break
                if(f1==True):
                    t=t.father
                    gen-=1
                    
                    
    def AStarSearch(self):#A*
        numTree=NumTree.NumTree()
        numTree.insert(self.root.puzzled.toOneDimen())        
        leaves=[self.root]
        leavesFn=[0]
        while True:
            t=leaves.pop()  #open表
            print leavesFn.pop()
            if(t.puzzled.isRight()==True):
                t.displayToRootNode()
                break
            for i in t.puzzled.getAbleMove():
                tt=t.puzzled.clone()
                tt.move(i)
                a=node(tt)
                if(numTree.searchAndInsert(a.puzzled.toOneDimen())==False):#close表
                    t.addChild(a)
                    fnS=self.__sortInsert(leavesFn,a.getFn())
                    leaves.insert(fnS, a)
时间: 2025-01-03 21:35:34

python实现求解八数码问题的相关文章

多种方法求解八数码问题

AI的实验报告,改了改发上来.希望路过的大牛不吝赐教.非常是纳闷我的ida*怎么还没有双搜快.还有发现基于不在位启示的A*和Ida*都挺慢.尤其是ida* 搜索31步的竟然要十几秒.是我写的代码有问题吗?忘路过的大牛指导啊!!!! 另外声明一下,有些东西也是看网上各路牛人的blog学来的,因为比較杂,再次无法一一列出,总之再次感谢把自己的思考的结果放到网上与大家分享的大牛们.谢谢! 八数码问题 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每一个棋子上标有1至8的某一数字,不同棋子上标

八数码

八数码问题 一.问题描述 所谓八数码问题是指:将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放在一块3×3的数码盘上.放牌时要求不能重叠.于是,在3×3的数码盘上出现了一个空格.现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,将任意摆放的数码盘逐步摆成某种特殊的排列. 二.问题分析 首先,八数码问题包括一个初始状态(strat) 和 目标状态(goal),所谓解八数码问题就是在两个状态间寻找一系列可过渡状态(strat-> strat 1-> strat 2->...

使用Muduo完成数独和八数码问题求解服务器

在剖析完Muduo网络库源码之后,我们试着完成一个高效的数独和八数码问题求解服务器. 先说说为什么要选择这两个问题?数独问题一直是陈硕老师很喜欢的问题,在muduo网络库中多次提到并有示例.八数码问题是我很喜欢的问题,所以在此综合完成求解数独和八数码问题的高效服务端程序. 编写这样一个看似简单的服务程序的技术含量远高于所谓的控件堆砌型开发,虽然有muduo网络库帮助我们处理网络事件,我们只需要关注setConnectionCallback() 和setMessageCallback() 事件,但

广度优先搜索解决八数码问题

八数码简介 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每一个棋子上标有1至8的某一数字,不同棋子上标的数字不同样.棋盘上另一个空格,与空格相邻的棋子能够移到空格中.要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤.所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态. 求解八数码问题要懂得的知识 1.康托展开,八数码在交换的过程

1225 八数码难题

1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.问题描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765

洛谷【P1379】八数码难题

P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变. 输入输出格式 输入格式: 输入初试状态,一行九个数字,空格用0表示 输出格式: 只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊

洛谷OJ P1379 八数码难题 解题报告

洛谷OJ P1379 八数码难题 解题报告 by MedalPluS 题目描述   在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变.   输入格式   输入初试状态,一行九个数字,空格用0表示   输出格式 只有一行,该行只有一个数字,表示从初始状态到

八数码问题:C++广度搜索实现

毕竟新手上路23333,有谬误还请指正. 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限制又会有很多情况无法找到,然后果断放弃,改用广度搜索.  如果要改善代码效率还可以用双向搜索,即从起始状态和最终状态同时搜索,找到相同状态,这样搜索时间会缩短一半.此外还可以用A*(启发式算法)会显得高端很多. 题目要求: 在一个3*3的棋盘上,随机放置1到8的数字棋子,剩下一个空位.数字可以移动到

洛谷 P1379 八数码难题

P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变. 输入输出格式 输入格式: 输入初始状态,一行九个数字,空格用0表示 输出格式: 只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊