Какой хороший алгоритм для создания лабиринта?
скажем, вам нужен простой лабиринт на сетке N by M, с одним путем и большим количеством тупиков, но это выглядит "правильно" (т. е. как будто кто-то сделал это вручную без слишком много маленьких крошечных тупиков и все такое). Есть ли способ сделать это?
7 ответов
от http://www.astrolog.org/labyrnth/algrithm.htm
Recursive backtracker: это несколько связано с рекурсивным методом решения backtracker, описанным ниже, и требует стека до размера лабиринта. При резьбе будьте как можно более жадными и всегда вырезайте неубранный раздел, если он находится рядом с текущей ячейкой. Каждый раз, когда вы переходите к новой ячейке, нажмите на прежнюю ячейку в стеке. Если рядом с текущей ячейкой нет неустановленных ячеек позиция, поместите стек в предыдущую позицию. Лабиринт делается, когда вы поп все из стека. Этот алгоритм приводит к лабиринтам с максимально высоким" речным " фактором, с меньшим, но более длинными тупиками и, как правило, очень длинным и извилистым решением. Он работает довольно быстро, хотя алгоритм Prim немного быстрее. Рекурсивное обратное отслеживание не работает как сумматор стены, потому что это приводит к пути решения, который следует за внешним краем, где вся внутренняя часть Лабиринт прикреплен к границе одним стеблем.
Они производят только 10% тупиков
http://www.astrolog.org/labyrnth/sample/recursiv.gif
является примером лабиринта, созданного этим методом.
оказывается есть 12 классических алгоритмов для создания "идеального" лабиринты. Лабиринт совершенен, если он имеет одно, и только одно, решение. Вот некоторые ссылки на каждый алгоритм, в грубом порядке моих предпочтений.
- Краскала!--5-->
- прим
- Рекурсивный Backtracker
- Олдос-Бродер
- растет Дерево!--5-->
- Охота-и-убить
- Уилсон
- Эллер
- Клеточный Автомат (легко)
- Рекурсивное Деление (Очень Легко)
- Сайдвиндер (предсказуемо)
- Бинарное Дерево (с изъяном)
для получения дополнительной информации, проверить mazelib на GitHub, библиотека Python реализация всех стандартных алгоритмов генерации/решения лабиринта.
довольно простым решением может быть назначение случайных Весов ребрам графика и применение алгоритм Крускала найти минимальное остовное дерево.
лучшее обсуждение алгоритмов генерации лабиринта:http://www.jamisbuck.org/presentations/rubyconf2011/index.html (был на HN пару дней назад).
Как ни странно, слегка изменив "канонические" правила и начав со случайной конфигурации,Игра жизни Конвея Кажется, генерирует довольно хорошие лабиринты!
(Я не помню точного правила, но это очень простая модификация, которая имеет тенденцию "уплотнять" популяцию клеток...)
мой любимый способ-использовать алгоритм Крускала, но при случайном выборе и удалении ребра взвешивайте выбор на основе типов ребер, с которыми он связан.
изменяя веса для разных типов ребер, вы можете создавать лабиринты с множеством различных характеристик или "личностей". См. мой пример здесь:
одним из методов создания лабиринта является рандомизированная версия алгоритма Prim.
начните с сетки, полной стен. Выберите ячейку, отметьте ее как часть лабиринта. Добавьте стены ячейки в список стен. Пока в списке есть стены:
выберите случайную стену из списка. Если ячейка на противоположной стороне еще не находится в лабиринте:
(i) сделайте стену проходом и отметьте ячейку на противоположной стороне как часть лабиринт.
(ii)добавьте соседние стены ячейки в список стен.
Если ячейка на противоположной стороне уже была в лабиринте, удалите стену из списка.
для более глубокого понимания нажать здесь
вот алгоритм DFS, написанный как псевдокод:
создайте CellStack (LIFO) для хранения списка местоположений ячеек
set TotalCells = количество ячеек в сетке
выберите ячейку наугад и назовите ее CurrentCell
установить VisitedCells = 1
в то время как VisitedCells
если один или несколько найдены
выберите один наугад
снести стену между ним и CurrentCell
толкать CurrentCell расположение на CellStack
сделайте новую ячейку CurrentCell
добавить 1 в VisitedCells
еще
pop самая последняя запись ячейки из CellStack
сделать это CurrentCell
за endif
endWhile