Какой хороший алгоритм для создания лабиринта?

скажем, вам нужен простой лабиринт на сетке 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 классических алгоритмов для создания "идеального" лабиринты. Лабиринт совершенен, если он имеет одно, и только одно, решение. Вот некоторые ссылки на каждый алгоритм, в грубом порядке моих предпочтений.

  1. Краскала!--5-->
  2. прим
  3. Рекурсивный Backtracker
  4. Олдос-Бродер
  5. растет Дерево!--5-->
  6. Охота-и-убить
  7. Уилсон
  8. Эллер
  9. Клеточный Автомат (легко)
  10. Рекурсивное Деление (Очень Легко)
  11. Сайдвиндер (предсказуемо)
  12. Бинарное Дерево (с изъяном)

для получения дополнительной информации, проверить mazelib на GitHub, библиотека Python реализация всех стандартных алгоритмов генерации/решения лабиринта.


довольно простым решением может быть назначение случайных Весов ребрам графика и применение алгоритм Крускала найти минимальное остовное дерево.

лучшее обсуждение алгоритмов генерации лабиринта:http://www.jamisbuck.org/presentations/rubyconf2011/index.html (был на HN пару дней назад).


Как ни странно, слегка изменив "канонические" правила и начав со случайной конфигурации,Игра жизни Конвея Кажется, генерирует довольно хорошие лабиринты!

(Я не помню точного правила, но это очень простая модификация, которая имеет тенденцию "уплотнять" популяцию клеток...)


мой любимый способ-использовать алгоритм Крускала, но при случайном выборе и удалении ребра взвешивайте выбор на основе типов ребер, с которыми он связан.

изменяя веса для разных типов ребер, вы можете создавать лабиринты с множеством различных характеристик или "личностей". См. мой пример здесь:

https://mtimmerm.github.io/webStuff/maze.html


одним из методов создания лабиринта является рандомизированная версия алгоритма Prim.

начните с сетки, полной стен. Выберите ячейку, отметьте ее как часть лабиринта. Добавьте стены ячейки в список стен. Пока в списке есть стены:

выберите случайную стену из списка. Если ячейка на противоположной стороне еще не находится в лабиринте:

(i) сделайте стену проходом и отметьте ячейку на противоположной стороне как часть лабиринт.

(ii)добавьте соседние стены ячейки в список стен.

Если ячейка на противоположной стороне уже была в лабиринте, удалите стену из списка.

для более глубокого понимания нажать здесь


вот алгоритм DFS, написанный как псевдокод:

создайте CellStack (LIFO) для хранения списка местоположений ячеек
set TotalCells = количество ячеек в сетке
выберите ячейку наугад и назовите ее CurrentCell
установить VisitedCells = 1

в то время как VisitedCells если один или несколько найдены выберите один наугад
снести стену между ним и CurrentCell
толкать CurrentCell расположение на CellStack
сделайте новую ячейку CurrentCell
добавить 1 в VisitedCells еще pop самая последняя запись ячейки из CellStack
сделать это CurrentCell за endif endWhile