Слайд 2
Графы: основы
Граф – множество вершин и ребер.
Ребра соединяют
между собой вершины.
Графы бывают разные:
Неориентированные и ориентированные
Взвешенные и невзвешенные.
Слайд 3
Графы: примеры
Неориентированный невзвешенный
Ориентированный взвешенный
Слайд 4
Графы в играх
Тайловая сетка(tile map, grid)
Слайд 5
Графы в играх
Полигональная карта(polygonal map)
Слайд 6
Графы в играх
Навигационная сетка(navigation mesh)
Слайд 7
Графы в играх
Почему тайловая сетка это граф?
Слайд 8
Поиск кратчайшего пути: задача
Есть вершина начала пути и
вершина конца пути. Нужно найти кратчайший путь от начала
до конца.
Слайд 9
Поиск кратчайшего пути: общие принципы
Разбиваем клетки на два
типа: посещенные и непосещенные.
Постепенно посещаем клетки.
Изначально только стартовая клетка
посещена.
Слайд 10
Поиск кратчайшего пути: обзор
Поиск в ширину(breadth-first search)
Алгоритм Дейкстры(Dijkstra's algorithm)
Поиск
первого наилучшего(best-first search)
A*(A star)
Слайд 11
Поиск в ширину: идея
Равномерно во все стороны расширяется
радиус обхода.
Посещенные вершины хранятся в очереди(queue).
Заканчиваем, когда очередь пуста(изначально
в очереди находится стартовая клетка).
Слайд 16
Поиск в ширину: код
Простейший вариант(инициализация)
frontier = Queue()
frontier.put(start)
visited =
{}
visited[start] = True
Слайд 17
Поиск в ширину: код
Простейший вариант(алгоритм)
while not frontier.empty():
current =
frontier.get()
for next in graph.neighbors(current):
if next not in visited:
frontier.put(next)
visited[next] =
True
Слайд 18
Поиск в ширину: код
Чтобы узнать, откуда пришли(инициализация)
frontier =
Queue()
frontier.put(start)
came_from = {}
came_from[start] = None
Слайд 19
Поиск в ширину: код
Чтобы узнать, откуда пришли (алгоритм)
while
not frontier.empty():
current = frontier.get()
for next in graph.neighbors(current):
if next not
in came_from:
frontier.put(next)
came_from[next] = current
Слайд 21
Поиск в ширину: код
Чтобы узнать кол-во шагов (инициализация)
frontier
= Queue()
frontier.put(start)
distance = {}
distance[start] = 0
Слайд 22
Поиск в ширину: код
Чтобы узнать кол-во шагов(алгоритм)
while not
frontier.empty():
current = frontier.get()
for next in graph.neighbors(current):
if next not in
distance:
frontier.put(next)
distance[next] = distance[current] + 1
Слайд 24
Поиск в ширину: use cases
Отметить все достижимые вершины
из данной вершины
Найти пути и расстояния до всех вершин
из данной вершины(просмотреть, что находится рядом с героем/монстром)
Слайд 26
Алгоритм Дейкстры: идея
Исследуем вершины не равномерно, а ориентируясь
на расстояние до начала поиска
Посещенные вершины хранятся в очереди
с приоритетом(min priority queue) – чем меньше расстояние до вершины, тем больше ее приоритет. Т. е. тем раньше эта вершина будет исследована.
Слайд 32
Алгоритм Дейкстры: код
frontier = PriorityQueue()
frontier.put(start,0)
came_from = {}
cost_so_far =
{}
came_from[start] = None
cost_so_far[start] = 0
Слайд 33
Алгоритм Дейкстры: код
while not frontier.empty():
current = frontier.get()
for
next in graph.neighbors(current):
new_cost = cost_so_far[current] + graph.cost(current, next)
if next
not in cost_so_far or new_cost < cost_so_far[next]:
cost_so_far[next] = new_cost
frontier.put(next, new_cost)
came_from[next] = current
Слайд 34
Алгоритм Дейкстры: use cases
Найти кратчайший путь от одной
вершины до многих других вершин во взвешенном графе
Когда нет
знания об общей структуре графа. Т. е. мы обладаем лишь локальной информацией о графе(вблизи каждой клетки)
Слайд 35
Алгоритм Дейкстры : ограничения
Если нужно найти путь до
единственной вершины, исследуется слишком много клеток
Слайд 36
Поиск первого наилучшего: идея
Исследуем вершины, ориентируясь на расстояние
до цели
Используем эвристику(heuristic)
Слайд 41
Поиск первого наилучшего: код
frontier = PriorityQueue()
frontier.put(start, 0)
came_from =
{}
came_from[start] = None
Слайд 42
Поиск первого наилучшего: код
while not frontier.empty():
current =
frontier.get()
for next in graph.neighbors(current):
new_cost = cost_so_far[current] + graph.cost(current, next)
if
next not in came_from:
priority = heuristic(goal, next)
frontier.put(next, priority)
came_from[next] = current
Слайд 43
Поиск первого наилучшего: use cases
Быстро найти кратчайший путь
от одной вершины до другой, когда нет препятствий
Слайд 44
Поиск первого наилучшего: ограничения
Кратчайший путь не найден
Слайд 45
A*: идея
Исследуем вершины не равномерно, а ориентируясь на
расстояние до начала поиска…
И на расстояние до цели. Т.е.
используем эвристику.
Сочетание алгоритма Дейкстры и поиска первого наилучшего.
Слайд 47
A*: код
frontier = PriorityQueue()
frontier.put(start, 0)
came_from = {}
cost_so_far =
{}
came_from[start] = None
cost_so_far[start] = 0
Слайд 48
A*: код
while not frontier.empty():
current = frontier.get()
for next
in graph.neighbors(current):
new_cost = cost_so_far[current] + graph.cost(current, next)
if next not
in cost_so_far or new_cost < cost_so_far[next]:
cost_so_far[next] = new_cost
priority = new_cost + heuristic(goal, next)
frontier.put(next, priority)
came_from[next] = current
Слайд 49
A*: use cases
Быстро найти кратчайший путь от одной
вершины до другой, даже если есть препятствия
Слайд 50
A*: эвристики
Эвристики бывают разные. От выбора эвристики зависит
корректность алгоритма и его быстрота.
Манхэтонновское расстояние
Слайд 51
A*: эвристики
Диагональное расстояние
Слайд 52
A*: эвристики
Евклидово расстояние