
Добавил:
CanyonE
СПбГУТ * ИКСС * Программная инженерия
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:
"""
Программа для нахождения кратчайшего пути между двумя точками в ограниченном N-мерном дискретном метрическом
подпространстве при помощи алгоритма A*
"""
import heapq
import threading
from math import inf
from random import sample
from typing import Set, List, Tuple, Callable
global_wait = False
class Heuristic:
"""
Эвристики поиска: "Октиль", Манхэттена, Чебышёва, Евклида
"""
@staticmethod
def octile(first: Tuple[int], second: Tuple[int]):
diffs = [abs(f - s) for f, s in zip(first, second)]
return max(diffs) + (2 ** 0.5 - 1) * min(diffs)
@staticmethod
def manhattan(first: Tuple[int], second: Tuple[int]):
return sum(abs(f - s) for f, s in zip(first, second))
@staticmethod
def chebyshev(first: Tuple[int], second: Tuple[int]):
return max(abs(f - s) for f, s in zip(first, second))
@staticmethod
def euclidean(first: Tuple[int], second: Tuple[int]):
return sum((f - s) ** 2 for f, s in zip(first, second)) ** 0.5
def a_star(space: Set[Tuple[int]], begin_point: Tuple[int], end_point: Tuple[int],
heuristic: Callable = Heuristic.manhattan) -> List[Tuple[int]]:
"""
Алгоритм A*. Использует приоритетную очередь.
:param space: ограниченное N-мерное дискретное метрическое подпространство
:param begin_point: начальная точка
:param end_point: конечная точка
:param heuristic: функция эвристики
:return: кратчайший путь между начальной и конечной точками
"""
assert begin_point not in space
assert end_point not in space
global global_wait
global_wait = True
current = []
n_points, n_axes = (len(space), len(begin_point))
q = []
cost = 0
heapq.heappush(q, (cost, end_point))
directions = []
for x in (-1, 1):
for p in range(n_axes):
temp = [0] * n_axes
temp[p] = x
directions.append(temp)
parent_point = {end_point: end_point}
cost_map = {end_point: cost}
while q and global_wait:
current = heapq.heappop(q)[1]
if current == begin_point:
break
cost = cost_map.get(current) + 1
for d in directions:
neighbor = tuple(t + dt for t, dt in zip(current, d))
if neighbor in space:
continue
if cost < cost_map.get(neighbor, inf):
cost_map[neighbor] = cost
parent_point[neighbor] = current
heapq.heappush(q, (cost + heuristic(current, begin_point), neighbor))
if not global_wait:
return list()
path = list()
if current == begin_point:
path.append(current)
while current != end_point:
current = parent_point[current]
path.append(current)
return path
def thread_stop():
"""
Функция, которая вызывается после срабатывания 15-секундного таймера
"""
global global_wait
global_wait = False
def check(value: List[Tuple[int]]):
"""
Функция проверки -- если таймер сработал, то пути (вероятно) не существует
:param value: одно из проверяемых значений -- найденный путь (если пуст, то пути не существует)
"""
if not value and global_wait:
print("Путь между точками отсутствует")
exit(9)
if not value and not global_wait:
print("15 секунд поиска прошло. Вероятно, путь между точками отсутствует.")
exit(10)
def main():
"""
Точка входа
"""
points = eval("{" + input("Введите точки-ограничители (стены): ") + "}")
if not isinstance(points, set) or not points or not all(
isinstance(x, tuple) and all(isinstance(t, int) for t in x) for x in points):
print("Точки-ограничители не представлены в виде множества точек с целыми координатами")
exit(1)
t = len(sample(points, 1)[0])
if not all(len(x) == t for x in points):
print("Размеры точек не совпадают")
exit(2)
begin = eval(input("Введите начальную точку: "))
if not isinstance(begin, tuple) or not all(isinstance(x, int) for x in begin):
print("Начальная точка не представлена в виде кортежа целых чисел")
exit(3)
if not len(begin) == t:
print("Размеры точек не совпадают")
exit(4)
if begin in points:
print("Начальная точка не может быть стеной")
exit(5)
end = eval(input("Введите конечную точку: "))
if not isinstance(end, tuple) or not all(isinstance(x, int) for x in begin):
print("Конечная точка не представлена в виде кортежа целых чисел")
exit(6)
if not len(end) == t:
print("Размеры точек не совпадают")
exit(7)
if end in points:
print("Конечная точка не может быть стеной")
exit(8)
timer = threading.Timer(15, thread_stop)
r = [[], [], [], []]
timer.start()
r[0] = a_star(points, begin, end, Heuristic.octile)
timer.cancel()
check(r[0])
r[1] = a_star(points, begin, end, Heuristic.manhattan)
check(r[1])
r[2] = a_star(points, begin, end, Heuristic.chebyshev)
check(r[2])
r[3] = a_star(points, begin, end, Heuristic.euclidean)
check(r[3])
print("Результаты поиска")
print("Octile heuristic: ", r[0])
print("Manhattan heuristic: ", r[1])
print("Chebyshev heuristic: ", r[2])
print("Euclidean heuristic: ", r[3])
if __name__ == '__main__':
try:
main()
except ():
print("\nВозникла ошибка работы программы")
input()