Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import matplotlib.pyplot as plt
- import numpy as np
- from IPython.display import display, clear_output
- from IPython.display import HTML
- from matplotlib.animation import FuncAnimation
- import time
- from queue import Queue
- def find_shortest_path(
- maze: np.ndarray,
- start: tuple[int, int],
- end: tuple[int, int]
- ):
- parent = np.full((maze.shape[0], maze.shape[1], 2), [-1, -1])
- parent[start[0]][start[1]] = start
- visited = np.zeros(maze.shape)
- visited[start[0]][start[1]] = 1
- level = np.full(maze.shape, -1)
- level[start[0]][start[1]] = -1
- queue = Queue()
- queue.put(start)
- while not queue.empty():
- node = queue.get()
- level[node[0]][node[1]] = level[parent[node[0]][node[1]][0]][parent[node[0]][node[1]][1]] + 1
- #print ("node: ", node)
- dx = [0, 1, 0, -1]
- dy = [-1,0, 1, 0]
- neighbors = []
- for i in range(4):
- x = node[0] + dx[i]
- y = node[1] + dy[i]
- if 0 <= x < maze.shape[0] and 0 <= y < maze.shape[1] and maze[x][y] and not visited[x][y]:
- neighbors.append(tuple((x, y)))
- for neighbor in neighbors:
- if not visited[neighbor[0]][neighbor[1]]:
- visited[neighbor[0]][neighbor[1]] = 1
- queue.put(neighbor)
- parent[neighbor[0]][neighbor[1]] = [node[0], node[1]]
- """print("visited")
- print(visited)
- #print("parent")
- #print(parent)"""
- if end != start and level[end[0]][end[1]] == -1:
- return False, False
- path = [np.array([end[0], end[1]])]
- nd = end
- while not (nd[0] == start[0] and nd[1] == start[1]):
- nd = parent[nd[0]][nd[1]]
- path.append(nd)
- return path, level
- def visualize_grid(size_x, size_y, coordinates, grid_data, level):
- fig, ax = plt.subplots(figsize=(size_y, size_x)) # Изменение порядка, size_x — строки, size_y — столбцы
- # Настройка осей
- ax.set_xticks(np.arange(size_y)) # Координаты по оси X (по столбцам)
- ax.set_yticks(np.arange(size_x)) # Координаты по оси Y (по строкам)
- ax.set_xticklabels(np.arange(size_y)) # Подписи для оси X
- ax.set_yticklabels(np.arange(size_x)) # Подписи для оси Y
- # Жирные линии для сетки между клетками (толщина линии увеличена)
- ax.set_xticks(np.arange(size_y + 1) - 0.5, minor=True) # Для рисования сетки
- ax.set_yticks(np.arange(size_x + 1) - 0.5, minor=True) # Для рисования сетки
- ax.grid(which="minor", color="black", linestyle='-', linewidth=6) # Жирная сетка (толщина линии увеличена в 3 раза)
- # Отображаем сетку по краям (границы)
- ax.spines['top'].set_linewidth(6) # Верхняя граница (толщина линии увеличена)
- ax.spines['right'].set_linewidth(6) # Правая граница (толщина линии увеличена)
- ax.spines['bottom'].set_linewidth(6) # Нижняя граница (толщина линии увеличена)
- ax.spines['left'].set_linewidth(6) # Левая граница (толщина линии увеличена)
- # Убираем подписи с осей, потому что они уже на координатах
- ax.tick_params(which="both", bottom=False, left=False, labelbottom=False, labelleft=False)
- plt.xlim(-0.5, size_y - 0.5)
- plt.ylim(size_x - 0.5, -0.5) # Инвертируем ось Y, чтобы (0, 0) была в верхнем левом углу
- ax.set_aspect('equal')
- # Отображаем клетки в зависимости от значений в grid_data
- for i in range(size_x): # Идем сверху вниз по оси X (строки)
- for j in range(size_y): # И слева направо по оси Y (столбцы)
- color = 'blue' if grid_data[i, j] == 1 else 'white'
- ax.add_patch(plt.Rectangle((j - 0.5, i - 0.5), 1, 1, color=color)) # Заполняем клетки
- # Раскрашиваем клетки в розовый цвет, если они находятся в списке координат
- for x, y in coordinates:
- ax.add_patch(plt.Rectangle((y - 0.5, x - 0.5), 1, 1, color='pink')) # Розовые клетки (x по Y, y по X)
- # Добавление координат для оси X снизу (сдвигаем выше)
- for i in range(size_y):
- ax.text(i, -0.8, str(i), ha='center', va='center', fontsize=12) # Подписи снизу
- # Добавление координат для оси Y слева (сдвигаем влево)
- for j in range(size_x):
- ax.text(-0.8, j, str(j), ha='center', va='center', fontsize=12) # Подписи слева
- # Список для хранения текстовых объектов
- text_objects = []
- # Функция обновления для анимации
- def update(frame):
- nonlocal text_objects
- # Очищаем старые текстовые объекты только после того, как отрисованы все цифры
- if frame == len(np.unique(level)) - 1:
- for text in text_objects:
- text.remove()
- text_objects.clear() # Очищаем список после удаления старых цифр
- # Выбираем цифры, которые будут отрисовываться
- unique_values = np.unique(level) # Получаем уникальные значения в level
- unique_values = unique_values[unique_values != -1] # Убираем -1, чтобы не отображать его
- # Перемещаемся по уровням и рисуем соответствующие цифры
- value = unique_values[frame % len(unique_values)] # Выбираем очередное значение для отображения
- for i in range(size_x):
- for j in range(size_y):
- if level[i, j] == value:
- text = ax.text(j, i, str(value), ha='center', va='center', fontsize=12, color='red', fontweight='bold')
- text_objects.append(text) # Сохраняем объект текста
- # Возвращаем список текстовых объектов
- return text_objects
- # Создаём анимацию
- anim = FuncAnimation(fig, update, frames=len(np.unique(level)) - 1, interval=1000, repeat=True)
- # Сохраняем анимацию в файл
- return anim
- def animate_wave_algorithm(
- maze: np.ndarray,
- start: tuple[int, int],
- end: tuple[int, int],
- save_path: str = ""
- ): # -> FuncAnimation:
- path, level = find_shortest_path(maze, start, end)
- if not path:
- print("NO PATH FROM START TO END")
- exit(0)
- anim = visualize_grid(maze.shape[0], maze.shape[1], path, maze, level)
- return anim
- maze = np.array([
- [0, 0, 0, 0, 0, 0, 0, 0],
- [0, 1, 1, 1, 1, 1, 0, 0],
- [1, 1, 0, 1, 0, 1, 0, 0],
- [1, 1, 1, 1, 1, 1, 0, 0],
- [0, 1, 0, 0, 0, 1, 1, 1],
- [1, 1, 1, 1, 1, 1, 0, 0],
- [0, 0, 0, 0, 0, 1, 1, 1],
- ])
- start = (2, 0)
- end = (6, 7)
- way = find_shortest_path(maze, start, end)
- save_path = "labyrinth.gif" # Укажите путь для сохранения анимации
- animate_wave_algorithm(maze, start, end, "")
- animation = animate_wave_algorithm(maze, start, end, save_path)
- HTML(animation.to_jshtml())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement