A*算法解决8数码问题python实现

1.A*的通俗理解

很多游戏特别是rts,rpg类游戏,都需要用到寻路。寻路算法有深度优先搜索(DFS),广度优先搜索(BFS),A星算法等,而A星算法是一种具备启发性策略的算法,效率是几种算法中最高的,因此也成为游戏中最常用的寻路算法。
对于A星算法的具体理解可以参考下面这篇文章,本文着重讲解A星算法,在解决8数码问题的思路以及代码
A*算法的通俗理解

2.8数码问题

A*算法解决8数码问题python实现_第1张图片
首先:估价函数对求解八数码问题有不同的影响。
这里我们介绍4种不同启发函数,我们主要使用第一种:

  • 最简单的估价函数:取一格局与目的格局相比,其位置不符的将牌数目。
  • 较 好的估价函数:各将牌移到目的位置所需移动的距离的总和
  • 第三种估价函数:对每一对逆转将牌乘以一个倍数。
  • 第四种估价函数:克服了仅计算将牌逆转数目策略的局限,将位置不符将牌数目的总和与3倍将牌逆转数目相加。

下面我们开始移动,并计算各个状态的估价函数值,然后选估价函数值最小的节点继续移动,直到出现目标状态为止如下图所示**(注意:图种有两处错误A(4)应为A(7),C(4)应为C(7))**:

A*算法解决8数码问题python实现_第2张图片

3.代码

import numpy as np
import operator
O=int(input(("请输入方阵的行/列数:")))
A=list(input("请输入初始状态:"))
B=list(input("请输入目标状态:"))
z=0
M=np.zeros((O,O))
N=np.zeros((O,O))
for i in range(O):
    for j in range(O):
        M[i][j]=A[z]
        N[i][j]=B[z]
        z=z+1
openlist=[]#open表

class State:
    def __init__(self,m):
        self.node=m#节点代表的状态
        self.f=0#f(n)=g(n)+h(n)
        self.g=0#g(n)
        self.h=0#h(n)
        self.father=None#节点的父亲节点

init = State(M)#初始状态
goal=State(N)#目标状态
#启发函数
def h(s):
    a=0
    for i in range(len(s.node)):
        for j in range(len(s.node[i])):
            if s.node[i][j]!=goal.node[i][j] and s.node[i][j]!=0:
                a=a+1
    return a
#对节点列表按照估价函数的值的规则排序
def list_sort(l):
    cmp=operator.attrgetter('f')
    l.sort(key=cmp)
#A*算法    
def A_star(s):
    global openlist#全局变量可以让open表进行时时更新
    openlist=[s]
    fatherlist=[s.node]
    while(openlist):
        get=openlist[0] #取出open表的首节点  
        if (get.node==goal.node).all():#判断是否与目标节点一致
            return get
        openlist.remove(get)#将get移出open表
        #判断此时状态的空格位置
        for a in range(len(get.node)):
            for b in range(len(get.node[a])):
                if get.node[a][b]==0:
                    break
            if get.node[a][b]==0:
                break
        #开始移动
        for i in range(len(get.node)):
            for j in range(len(get.node[i])):
                c=get.node.copy()
                if (i-a)**2+(j-b)**2==1:
                    c[a][b]=c[i][j]
                    c[i][j]=0
                    new=State(c)
                    K=0
                    for k in range(len(fatherlist)):
                        if (new.node==fatherlist[k]).all():
                            break
                        else:
                            K=K+1
                    if K==len(fatherlist):     
                        new.father=get#此时取出的get节点成为新节点的父亲节点
                        new.g=get.g+1#新节点与父亲节点的距离
                        new.h=h(new)#新节点的启发函数值
                        new.f=new.g+new.h#新节点的估价函数值
                        openlist.append(new)
                        fatherlist.append(new.node)


                
# 递归打印路径
def printpath(f):
    if f is None:
        return
    #注意print()语句放在递归调用前和递归调用后的区别。放在后实现了倒叙输出
    printpath(f.father)
    print(f.node)
    


final=A_star(init)
if final:
    print("有解,解为:")
    printpath(final)
else:
    print("无解")
           

你可能感兴趣的:(算法,python,开发语言)