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

我的算法流程

  • 初始化open_list 和 close_list;
  • 将开始节点添加到open_list
    • 找到open_list最优的字典和索引
    • 如果最好的节点等于当前节点
      • 从终点开始逐步追踪父亲节点,一直找到开始节点
      • 返回找到的结果路径,算法结束
    • 如果最好的节点不等于当前节点
      • 将最小节点从open_list中删除
      • 将最小节点从添加到close_list中
      • 遍历最小节点所有的邻近节点
        • 如果该邻近节点在close_list中可以找到
          • 则continue
        • 如果该邻近节点在open_list中可以找到
          • 则continue
        • 将邻近节点加入open_list中

代码

class Solution:

    def salvePuzzle(self, init, targ):
        ''' 求解8数码问题
        参数:
        init - 初始状态 例如'123046758'
        targ - 目标状态 例如'012345678'
        返回值:
        clf - 由udlr组成的移动路径字符串
        ''' 
        def open_min(opl): # 找到open列表中最小的一个
            k = opl[0]
            d = -1
            t = 0
            f_min = opl[0]['g'] + opl[0]['h']
            for i in opl:
                d = d + 1
                if i['g'] + i['h'] < f_min:
                    f_min = i['g'] + i['h']
                    k = i
                    t = d
            return k, t
         
            
        def find_fat(cll, f): # 寻找父亲节点
            for i in cll:
                if i['ind'] == f:
                    return i
                
                
        def find_near(oc, node): # 寻找邻近节点
            d = -1
            for i in oc:
                d = d + 1
                if i['val'] == node:
                    return d
            return -1        
            
            
        start_node = init # 开始节点
        
        end_node = targ # 结束节点
        
        open_list = [] # open表
        
        close_list = [] # close表
        
        hx = self.calcDistH(start_node, end_node) # h(x)
        
        # ind: 序号,当前点的序号 | g表示g(x)代数 | h表示h(x) | val表示值 | fat表示father指针 | pos表示(上u 下d 左l 右r)
        set1 = {'ind': 0, 'g': 0, 'h': hx, 'val': start_node, 'fat': -1, 'pos': ''}
        
        n = 0 # ind索引
        
        path_list = []  # 打印路径
        
        open_list.append(set1)  # 将开始节点添加到open_list
        
        best_set = {} # 最好的字典
        
        best_node = '' # 最好的节点
        
        index = 0 # 索引
        while n < 100000:
            
            best_set, index = open_min(open_list) # 找到open_list最优的字典和索引
            
            best_node = best_set['val']  # 找到改最小字典的节点值
            
            if best_node == end_node: # 如果最好的节点等于当前节点
                while True: # 从终点开始逐步追踪父亲节点,一直找到开始节点
                    node_fat = best_set['fat'] # 找到父亲索引
                    
                    path_list.append(best_set['pos']) # 添加到路径列表中
                    
                    if node_fat == -1: # 一直找到开始节点
                        break
                        
                    best_set = find_fat(close_list, node_fat)
            
            if path_list != []: # 返回找到的结果路径,算法结束
                break
            
            del open_list[index] # 将最小节点从open_list中删除
            
            close_list.append(best_set) # 将最小节点从添加到close_list中
            
            ###  产生所有邻近节点
            fx = ['u', 'd', 'l', 'r']
            
            for fxw in fx: # 遍历最小节点所有的邻近节点
                index_0 = best_node.find('0')   #找到0处的索引值
                
                index_row =  int(index_0 / 3)   # 行
                indx_col = index_0 % 3          # 列
                
                if fxw == 'u': # 上移
                    index_row = index_row - 1
                if fxw == 'd': # 下移
                    index_row = index_row + 1
                if fxw == 'l': # 左移
                    indx_col = indx_col - 1
                if fxw == 'r': # 右移
                    indx_col = indx_col + 1
                    
               # print('移动到的索引:',jh_index_0, '移动方向:',fxw, '行:', int(index_row), '列:', indx_col )
                
                if int(index_row) > 2 or int(index_row) < 0 or indx_col > 2 or indx_col < 0: # 判断是否越界,即是否超出九宫格
                    continue
                    
                jh_index_0 = 3 * int(index_row) + indx_col # 移动之后的0的索引值
                
                near_node = self.moveMap(best_node, int(index_0), int(jh_index_0)) #移动之后的邻近节点
                
                # g(n)是从开始结点到结点n的路径代价
                set2 = {'ind': 0, 'g': best_set['g'] + 1, 'h': 0, 'val': '', 'fat': best_set['ind'], 'pos': fxw}  
                
                '''
                # 下面注释的代码本应当要实现以下功能:
                    + 如果该邻近节点在close_list中可以找到
                        + 因为节点相同,所以h(x)一样,则判断g(x)的大小进行操作 
                        + 这里的操作就是修改该节点的属性,g(x)和指向父亲的['fat'],再continue
                    + 如果该邻近节点在open_list中可以找到
                        + 因为节点相同,所以h(x)一样,则判断g(x)的大小进行操作 
                        + 这里的操作就是修改该节点的属性,g(x)和指向父亲的['fat'],再continue
                # 但是本人实力有限,实现不了。
                ''' 

                near_index = find_near(close_list, near_node) # 在close_list找near_node的索引值
                
                if near_index != -1:  #如果找到
                    '''
                    if set2['g'] < close_list[near_index]['g']:
                        close_list[near_index]['g'] = set2['g']
                        close_list[near_index]['fat'] = best_set['ind']
                    '''
                    continue
                    
                
                
                near_index = find_near(open_list, near_node) #在open_list找near_node的索引值
                
                if near_index != -1:  #如果找到
                    '''
                    if set2['g'] < open_list[near_index]['g']:
                        open_list[near_index]['g'] = set2['g']
                        open_list[near_index]['fat'] = best_set['ind']
                    ''' 
                    continue

                near_h =  self.calcDistH(near_node, end_node) # 计算h(x)
                n = n + 1
                set2['ind'] = n
                set2['h'] = near_h
                set2['val'] = near_node
                open_list.append(set2) # 将节点m加入open_list中
            
        path_list.reverse()   # 逆序
        return ''.join(path_list)     
    

    
    def calcDistH(self, src_map, dest_map):
        '''     启发式函数h(n):是从结点n到目标结点的最小路径代价的估计值
        参数:
            src_map  - 当前8数码状态
            dest_map - 目标8数码状态
        返回值:
            clf - 当前状态到目标状态的启发式函数值
        '''
        sum = 0
        src_i = 0
        for i in src_map:  # 检索i
            src_i = src_i + 1
            dest_j = 0 
            for j in dest_map:
                if i == '0':
                    break
                dest_j = dest_j + 1
                if i == j:
                    sum = sum + abs(src_i - dest_j)
        return sum


    def moveMap(self, cur_map, i, j):
        '''     状态转换(交换位置i和j)
        参数:
            cur_map - 当前8数码状态
            i - 当前8数码状态中空格0的位置索引
            j - 将空格0的位置i移动到位置j,位置j移动到位置i
        返回值:
            clf - 新的8数码状态
        '''
        i = int(i)
        j = int(j)
        cur_map = cur_map[:i] + cur_map[j] + cur_map[i + 1:]
        cur_map = cur_map[:j] + '0' + cur_map[j + 1:]
        return cur_map


solution = Solution()
# init - 初始状态
# targ - 目标状态
# path_list - 移动路径 例如 'lurddlurrulldrrdllurruldlu'
init = "724506831"
targ = "012345678"
path_list = solution.salvePuzzle(init, targ)
print(path_list)
  • 9
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值