簡體   English   中英

使用A-star搜索算法的N-puzzle問題

[英]N-puzzle problem using A-star search algorithm

我正在使用 Python 中的 A* 為我的人工智能課程制作一個 n-puzzle 求解器。 我的解決方案的問題是,solve_puzzle() 無法正常工作。 在搜索節點時,它變得越來越深,但它永遠不會結束,深度變得非常高(例如,某些子節點的深度為 5k)。

我認為它會卡在某個循環中,並且一直循環通過相同的節點(這正是我的想法,我不確定)。 我真的不知道,我嘗試了 3 種不同的 A* 解決方案,但結果是一樣的 - 搜索循環永遠不會結束,也永遠不會達到目標。

我可以解決非常原始的難題,例如
開始 -> 0, 1, 2, 3, 4, 5, 6, 7, 8
目標 -> 1, 2, 0, 3, 4, 5, 6, 7, 8 (只向左移動兩次)
但對於一個更復雜的謎題,比如
開始 = 0, 1, 2, 3, 4, 5, 6, 7, 8
目標 = 1, 2, 5, 0, 3, 4, 6, 7, 8 這是一個永無止境的搜索。

我用數字移動瓷磚,而不是空白瓷磚。

下面是整個代碼:

'''
class Node():

    def __init__(self, n_size, m_size, current_state, goal_state, choosen_heuristic, parent):
        self.n_size = n_size
        self.m_size = m_size
        self.dimension = self.n_size * self.m_size
        self.current_state = current_state
        self.goal_state = goal_state
        self.choosen_heuristic = choosen_heuristic
        self.parent = parent
        self.child = [None, None, None, None]
        self.last_operator = None
        self.heuristic_cost = 0
        self.depth = 0
        self.priority = self.depth + self.heuristic_cost

    def check_if_goal_is_reached(self):
        if (self.heuristic_cost == 0):
            print("GOAL IS REACHED!")
            exit(1)                                         #for now
            #return

    def get_blank_tile_position(self):
        blank_position = 0
        for i in range(self.dimension):
            if (self.current_state[i] == 0):
                blank_position = i
        return blank_position

    def misplaced_tiles_heuristic(self):
        misplaced_sum = 0
        for i in range(self.dimension):
            if self.current_state[i] != self.goal_state[i]:
                misplaced_sum += 1
        #print("Count of misplaced tiless in this node is : ", misplaced_sum)
        self.heuristic_cost = "misplaced"
        self.heuristic_cost = misplaced_sum
        self.check_if_goal_is_reached()
        return misplaced_sum

    def manhattan_distance(self):
        distance_sum = 0
        for i in range(self.dimension):
            current_x = self.current_state[i] % self.n_size
            goal_x = self.goal_state[i] % self.n_size
            current_y = self.current_state[i] // self.m_size
            goal_y = self.goal_state[i] // self.m_size
            distance_sum += abs(current_x - goal_x) + abs(current_y - goal_y)
        #print("Sum of Manhattan distance for this node is : ", distance_sum)
        self.heuristic_cost = "manhattan"
        #print("Hĺbka tohto uzla : ", self.depth)
        self.check_if_goal_is_reached()
        return distance_sum

    def generate_children(self, choosen_heuristic):
        possible_directions = []
        current_node_blank_position = self.get_blank_tile_position()
        # UP - I move a tile with number on it, not the blank tile
        if current_node_blank_position < (self.dimension - self.n_size):
            self.child[0] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
            self.child[0] = copy.deepcopy(self)
            self.child[0].parent = self.current_state
            self.child[0].last_operator = "UP"
            self.child[0].depth = self.depth + 1

            new_blank_position = current_node_blank_position + self.m_size

            temp = self.child[0].current_state[current_node_blank_position]
            self.child[0].current_state[current_node_blank_position] =  self.child[0].current_state[new_blank_position]
            self.child[0].current_state[new_blank_position] = temp

            if choosen_heuristic == "misplaced":
                self.child[0].misplaced_tiles_heuristic()
            if choosen_heuristic == "manhattan":
                self.child[0].manhattan_distance()

            possible_directions.append("UP")
            print("Depth of this node is : : ", self.child[0].depth)
        else:           
            self.child[0] = None
        # DOWN - I move a tile with number on it, not the blank tile
        if current_node_blank_position > (self.n_size - 1):
            self.child[1] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
            self.child[1] = copy.deepcopy(self)
            self.child[1].parent = self.current_state
            self.child[1].last_operator = "DOWN"
            self.child[1].depth = self.depth + 1

            new_blank_position = current_node_blank_position - self.m_size

            temp = self.child[1].current_state[current_node_blank_position]
            self.child[1].current_state[current_node_blank_position] =  self.child[1].current_state[new_blank_position]
            self.child[1].current_state[new_blank_position] = temp

            if choosen_heuristic == "misplaced":
                self.child[1].misplaced_tiles_heuristic()
            if choosen_heuristic == "manhattan":
                self.child[1].manhattan_distance()

            possible_directions.append("DOWN")
            #print("Depth of this node is : : ", self.child[1].depth)
        else:           
            self.child[1] = None
        # RIGHT - I move a tile with number on it, not the blank tile
        if (current_node_blank_position + self.n_size) % self.m_size:
            self.child[2] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
            self.child[2] = copy.deepcopy(self)
            self.child[2].parent = self.current_state
            self.child[2].last_operator = "RIGHT"
            self.child[2].depth = self.depth + 1

            new_blank_position = current_node_blank_position - 1

            temp = self.child[2].current_state[current_node_blank_position]
            self.child[2].current_state[current_node_blank_position] =  self.child[2].current_state[new_blank_position]
            self.child[2].current_state[new_blank_position] = temp

            if choosen_heuristic == "misplaced":
                self.child[2].misplaced_tiles_heuristic()
            if choosen_heuristic == "manhattan":
                self.child[2].manhattan_distance()

            possible_directions.append("RIGHT")
            #print("Depth of this node is : : ", self.child[2].depth)
        else:           
            self.child[2] = None
        # LEFT - I move a tile with number on it, not the blank tile
        if (current_node_blank_position + 1) % self.m_size:
            self.child[3] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
            self.child[3] = copy.deepcopy(self)
            self.child[3].parent = self.current_state
            self.child[3].last_operator = "LEFT"
            self.child[3].depth = self.depth + 1

            new_blank_position = current_node_blank_position + 1

            temp = self.child[3].current_state[current_node_blank_position]
            self.child[3].current_state[current_node_blank_position] =  self.child[3].current_state[new_blank_position]
            self.child[3].current_state[new_blank_position] = temp

            if choosen_heuristic == "misplaced":
                self.child[3].misplaced_tiles_heuristic()
            if choosen_heuristic == "manhattan":
                self.child[3].manhattan_distance()

            possible_directions.append("LEFT")
            #print("Depth of this node is : ", self.child[3].depth)
        else:           
            self.child[3] = None

        #print("From this node (the parent node) I can move to -> ", possible_directions)


def get_node_priority(node):
    return node.priority

def solve_puzzle(n_size, m_size, current_state, goal_state, choosen_heuristic):
    open_list = []
    closed_list = []
    init_node_parent = None
    init_node = Node(n_size, m_size, current_state, goal_state, choosen_heuristic, init_node_parent)
    open_list.append(init_node)

    while len(open_list) != 0:
        if (len(open_list) == 0):
            print("Fail - solution not found !")
        else:
            node = open_list.pop(0)

            if (node.parent != None):
                node.check_if_goal_is_reached()

            node.generate_children(choosen_heuristic)
            closed_list.append(node)

            temp_list = []
            for i in range(4):
                if node.child[i] != None:
                    temp_list.insert(0, node.child[i])
            sorted_temp_list = sorted(temp_list, key=get_node_priority, reverse=True)
            for x in range(len(sorted_temp_list)):
                if sorted_temp_list[x] != None:
                    open_list.insert(0, sorted_temp_list[x])

def print_current_node(current_node):
    puzzle = ""
    if current_node is None:
        puzzle = ""
        print(puzzle)
    else:
        puzzle = ""
        count_lines = 0
        for i in range(current_node.dimension):
            puzzle +=  (str(current_node.current_state[i]) + " ")
            count_lines += 1
            if (count_lines % current_node.m_size == 0):
                puzzle += "\n"
        print(puzzle)


def main():

    ###################
    #   Static Data   #
    ###################
    # static for now, later I will let user to choose
    n_size = 3
    m_size = 3
    current_state = [0, 1, 2, 3, 4, 5, 6, 7, 8]
    goal_state = [8, 0, 6, 5, 4, 7, 2, 3, 1]
    choosen_heuristic = "manhattan"
    start_time = time.process_time()
    solve_puzzle(n_size, m_size, current_state, goal_state, choosen_heuristic)
    end_time = time.process_time()
    search_time = end_time - start_time
    print("Solved in : ", search_time, "seconds.")

main()
'''

確保您使用可解決的難題進行測試。 以下是一些可解決的測試:

 goal: {1,2,3,4,5,6,7,8,0} 6 steps: {1,3,5,4,0,2,7,8,6} 18 steps: {1,4,0,5,2,8,7,6,3} 26 steps: {2,1,7,5,0,8,3,4,6} 27 steps: {8,5,3,4,7,0,6,1,2} 28 steps: {0,6,7,3,8,5,4,2,1} 30 steps: {5,7,0,4,6,8,1,2,3} 31 steps: {8,6,7,2,5,4,3,0,1} (highest number of steps possible for 3x3 )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM