* * визуализация поиска звезд невероятно медленная / python - PullRequest
3 голосов
/ 25 марта 2020

Я попытался реализовать алгоритм поиска кратчайшего пути, используя python и pygame. Алгоритм и визуализация, кажется, работают. Тем не менее, время, необходимое для нахождения пути, увеличивается в геометрической прогрессии, поскольку я помещаю начальный и конечный узлы далеко друг от друга. Чтобы найти путь длиной 5 или 6 узлов, требуются часы. Я считаю, что проблема в одном из циклов в функции Астар, но я не знаю, какой и как его решить. Я искал inte rnet относительно проблемы, но не мог найти никакого решения. Вот код:

import pygame


class cube():
    rows = 30
    w = 840
    def __init__(self, pos=None, color=None):
        self.pos = pos
        self.color = color
        self.neighbours = []


    def draw(self, surface):
        dis = self.w // self.rows
        i = self.pos[0]
        j = self.pos[1]


        pygame.draw.rect(surface, self.color, (i * dis + 1, j * dis + 1, dis - 2, dis - 2))
class node(cube):

    def __init__(self, pos=None, color=None, parent=None):
        super().__init__(pos, color)
        self.parent = parent

        self.g = 0
        self.h = 0
        self.f = self.g + self.h

    def __eq__(self, other):
        return self.pos == other.pos

//here is the astar function

def astar(start, end):
    global rows, path, obs_list, start_node, end_node, window, closed_list, blue, children, red, green, grey

    counter = 0
    green = (0,255,0)
    red = (255,0,0)
    blue = (0,0,255)
    grey = (170,170,170)
    start_node = node(start, red)
    end_node = node(end, red)
    start_node.g = start_node.h = start_node.f = 0
    end_node.g = end_node.h = end_node.f = 0


    open_list = []
    closed_list = []
    open_list.append(start_node)

    while len(open_list) > 0:

        # Get the current node
        current_node = open_list[0]

        current_index = 0
        for index, item in enumerate(open_list):
            if item.f < current_node.f:
                current_node = item

                current_index = index

        # Pop current off open list, add to closed list
        open_list.pop(current_index)
        closed_list.append(current_node)
        visualize(window, open_list)


        if current_node.pos == end_node.pos:

            path = []
            current = current_node
            while current is not None:
                path.append(current.pos)
                current = current.parent
            return path[::-1]  # Return reversed path

        children = []
        for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)]:
            node_position = (current_node.pos[0] + new_position[0], current_node.pos[1] + new_position[1])



            #check if neighbour isn't a obstacle
            if node_position in obs_list:
              #  print("not possible")
                continue

            #check if neighbour isn't in closed list

            #create a new node
            new_node = node(node_position, green, current_node)



            # new node is the child of the previous node. Add child node to the list
            children.append(new_node)
        #     print(children)
            #loop through children
            for child in children:


                for closed_child in closed_list:
                    if child == closed_child:
                        continue

                child.g = current_node.g + 10
                child.h = ((child.pos[0] - end_node.pos[0]) **2) + ((child.pos[1] - end_node.pos[1]) **2)
                child.f = child.g + child.h

                for open_node in open_list:
                    if child == open_node and child.g > open_node.g:
                        continue



          #       visualize(window, children)
                    # Add the child to the open list
                open_list.append(child)


def draw_grid(w, rows, window):
    size_between = w // rows
    x = 0
    y = 0
    for l in range(rows):
        x = x + size_between
        y = y + size_between

        pygame.draw.line(window, (255,255,255), (x, 0), (x, w))
        pygame.draw.line(window, (255,255,255), (0,y), (w,y))


def visualize(surface, list):
    global red, blue, green, grey, counter
    for i,c in enumerate(list):
        c.draw(surface)
        pygame.display.update()




def show_path(surface):
    global path
    for i in path:
        node_path = cube(i, color=(0,0,255))
        node_path.draw(surface)
        pygame.display.update()

    for c in (path):
        node_p = cube(c, color=(35, 180, 89))
        node_p.draw(surface)

def draw_inital(surface):
    surface.fill((0, 0, 0))
    draw_grid(840, 30, surface)
    start_node.draw(surface)
    end_node.draw(surface)
    pygame.display.update()

def mouse_press(x):
    global rows, window, obs, start_node, end_node, obs_list
    t = x[0]
    w = x[1]

    g1 = t // (840 // rows)
    g2 = w // (840 // rows)
    obs = cube((g1,g2), (125, 125, 125))


    if obs.pos == start_node.pos:
        obs.color = (255,0,0)
        obs.draw(window)
        pygame.display.update()

    elif obs.pos == end_node.pos:

        obs.color = (255, 0, 0)
        obs.draw(window)
        pygame.display.update()

    else:
        if obs.pos not in obs_list:

            obs_list.append(obs.pos)
            obs.draw(window)
            pygame.display.update()




def main():
    global start_node, end_node, rows, window, counter, obs_list, start, end
    width = 840
    rows = 30
    window = pygame.display.set_mode((width,width))

    start = (12, 24)
    end = (12, 26)
    obs_list = []

    start_node = node(start, color=(255,0,0))
    end_node = node(end, color=(255,0,0))

    start_node.draw(window)
    end_node.draw(window)
    draw_inital(window)

    loop = True
    while loop:

        ev = pygame.event.get()
        for event in ev:
            if event.type == pygame.QUIT:
                pygame.quit()
            if pygame.mouse.get_pressed()[0]:
                try:
                    pos = pygame.mouse.get_pos()
                    mouse_press(pos)

                except AttributeError:
                    pass
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    loop = False
                    break

    path = astar(start, end)
    print(path)
    show_path(window)




    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False


main()

1 Ответ

3 голосов
/ 27 марта 2020

Ваш код очень трудно читать. Вот некоторые наблюдения.

Незначительная ошибка

child.g = current_node.g + 10

Требуется стать

child.g = current_node.g + 1

Это решает проблему, но только по счастливой случайности. Это на самом деле не решение!

Реальная ошибка

Вы добавляете слишком много элементов в список open_list.

        for new_position in ...:
            # create a new node
            new_node = node(node_position, green, current_node)
            ...
            children.append(new_node)
            #     print(children)
            # loop through children
            for child in children:
                ...
                open_list.append(child)

Обратите внимание, что для каждого сосед (for new_position in ...) (8x) вы добавляете нового дочернего элемента в список дочерних элементов, а затем выполняете итерацию по всем дочерним элементам. Это 1/2 * 8 * 8 = 32 детей добавлено.

Простое решение состоит в том, чтобы иметь только один l oop на каждого соседа / ребенка, а не два, которые у вас есть в настоящее время.

Очередь приоритетов

Вы не используете Очередь приоритетов для открытого списка. Это означает, что для каждого элемента, который вы извлекаете из открытого списка, вы сканируете весь список.

Используйте это: https://docs.python.org/3/library/heapq.html

Установить членство

for closed_child in closed_list:
    if child == closed_child:
        continue

Должен стать, но потребуется сделать хешируемым тип узла:

closed_list = set()
...
if child in closed_list:
    continue

Heuristi c Функция

Ошибка: вы забыли квадрат root, когда вычисление евклидова расстояния.

...