使用盲搜索(蛮力)和曼哈顿距离启发式

时间:2015-11-03 08:33:32

标签: python heuristics 8-puzzle

我用Python开发了自己的程序来解决8-puzzle。最初,我使用“盲”或不知情的搜索(基本上是暴力破解)生成和探索所有可能的后继者并使用广度优先搜索。当它找到“目标”状态时,它基本上回溯到初始状态并提供(我相信)是解决它的最优化步骤。当然,最初的状态是搜索需要花费大量时间并在找到目标之前产生超过100,000个状态。

然后我添加了启发式 - 曼哈顿距离。解决方案开始呈指数级增长,并且探索状态较少。 但我的困惑是,有些时候,生成的优化序列比使用盲目或不知情的搜索所达到的更长。

我正在做的基本上是这样的:

  1. 对于每个州,查找所有可能的移动(向上,向下,向左和向右),并生成后继状态。
  2. 检查状态是否重复。如果是,则忽略它。
  3. 计算州的曼哈顿。
  4. 选出曼哈顿最低的继任者,并在列表末尾添加。
  5. 检查目标状态。如果是,请打破循环。
  6. 我不确定这是否符合贪婪优先或A *。

    我的问题是,这是曼哈顿距离启发式的一个固有缺陷,有时它无法提供最佳解决方案,或者我做错了什么。

    以下是代码。我很抱歉这不是一个非常干净的代码,但大多是顺序的,它应该很容易理解。我也为长代码道歉 - 我知道我需要优化它。也欢迎任何清理代码的建议/指导。这就是它:

    import numpy as np
    from copy import deepcopy
    import sys
    
    # calculate Manhattan distance for each digit as per goal
    def mhd(s, g):
        m = abs(s // 3 - g // 3) + abs(s % 3 - g % 3)
        return sum(m[1:])
    
    # assign each digit the coordinate to calculate Manhattan distance
    def coor(s):
        c = np.array(range(9))
        for x, y in enumerate(s):
            c[y] = x
        return c
    
    #################################################
    def main():
        goal    =  np.array( [1, 2, 3, 4, 5, 6, 7, 8, 0] )
        rel     = np.array([-1])
        mov     = np.array([' '])
        string = '102468735'
        inf = 'B'
        pos = 0
        yes = 0
        goalc = coor(goal)
        puzzle = np.array([int(k) for k in string]).reshape(1, 9)
        rnk = np.array([mhd(coor(puzzle[0]), goalc)])
        while True:
            loc = np.where(puzzle[pos] == 0)        # locate '0' (blank) on the board
            loc = int(loc[0])
            child = np.array([], int).reshape(-1, 9)
            cmove = []
            crank = []
            # generate successors on possible moves - new states no repeats
            if loc > 2:         # if 'up' move is possible
                succ = deepcopy(puzzle[pos])
                succ[loc], succ[loc - 3] = succ[loc - 3], succ[loc]
                if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                    child = np.append(child, [succ], 0)
                    cmove.append('up')
                    crank.append(mhd(coor(succ), goalc)) # manhattan distance
            if loc < 6:         # if 'down' move is possible
                succ = deepcopy(puzzle[pos])
                succ[loc], succ[loc + 3] = succ[loc + 3], succ[loc]
                if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                    child = np.append(child, [succ], 0)
                    cmove.append('down')
                    crank.append(mhd(coor(succ), goalc))
            if loc % 3 != 0:    # if 'left' move is possible
                succ = deepcopy(puzzle[pos])
                succ[loc], succ[loc - 1] = succ[loc - 1], succ[loc]
                if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                    child = np.append(child, [succ], 0)
                    cmove.append('left')
                    crank.append(mhd(coor(succ), goalc))
            if loc % 3 != 2:    # if 'right' move is possible
                succ = deepcopy(puzzle[pos])
                succ[loc], succ[loc + 1] = succ[loc + 1], succ[loc]
                if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                    child = np.append(child, [succ], 0)
                    cmove.append('right')
                    crank.append(mhd(coor(succ), goalc))
            for s in range(len(child)):
                if (inf in 'Ii' and crank[s] == min(crank)) \
                or (inf in 'Bb'):
                    puzzle = np.append(puzzle, [child[s]], 0)
                    rel = np.append(rel, pos)
                    mov = np.append(mov, cmove[s])
                    rnk = np.append(rnk, crank[s])
                    if np.array_equal(child[s], goal):
                        print()
                        print('Goal achieved!. Successors generated:', len(puzzle) - 1)
                        yes = 1
                        break
            if yes == 1:
                break
            pos += 1
        # generate optimized steps by back-tracking the steps to the initial state
        optimal = np.array([], int).reshape(-1, 9)
        last = len(puzzle) - 1
        optmov = []
        rank = []
        while last != -1:
            optimal = np.insert(optimal, 0, puzzle[last], 0)
            optmov.insert(0, mov[last])
            rank.insert(0, rnk[last])
            last = int(rel[last])
    
        # show optimized steps
        optimal = optimal.reshape(-1, 3, 3)
        print('Total optimized steps:', len(optimal) - 1)
        print()
        for s in range(len(optimal)):
            print('Move:', optmov[s])
            print(optimal[s])
            print('Manhattan Distance:', rank[s])
            print()
        print()
    
    ################################################################
    # Main Program
    
    if __name__ == '__main__':
        main()
    

    以下是一些初始状态和计算出的优化步骤(如果您想检查)(上面的代码会给出此选项,以便在盲目与知情搜索之间进行选择)

    初始状态
      - 283164507盲人:19曼哈顿:21
      - 243780615盲人:15曼哈顿:21
      - 102468735盲人:11曼哈顿:17
      - 481520763盲人:13曼哈顿:23
      - 723156480盲人:16曼哈顿:20

    我故意选择了结果很快的例子(几秒钟或几分钟内)。

    非常感谢您的帮助和指导。

    编辑:我做了一些快速更改并设法减少了大约30多行。不幸的是,此时不能做太多 注意:我已经硬编码了初始状态和盲目与知情选择。请更改初始状态变量“string”的值和Informed / Blind变量“inf”[I / B]。谢谢!

0 个答案:

没有答案