Какой хороший алгоритм для создания лабиринта?
Вопрос
Скажем, вы хотите простой лабиринт на сетке N by M с одним проходом и большим количеством тупиков, но это выглядит " right " (то есть, как будто кто-то сделал это вручную, не слишком много маленьких крошечных тупиков и все такое). Есть ли известный способ сделать это?
Решение
От http://www.astrolog.org/labyrnth/algrithm.htm р>
Рекурсивный бэк-трекер. Это в некоторой степени связано с методом решения рекурсивного бэк-трекера, описанным ниже, и требует стека до размера лабиринта. При вырезании будьте как можно более жадными, и всегда делайте вырезки на необработанный участок, если он находится рядом с текущей ячейкой. Каждый раз, когда вы переходите в новую ячейку, вставляйте прежнюю ячейку в стек. Если рядом с текущей позицией нет неразделенных ячеек, вставьте стек в предыдущую позицию. Лабиринт делается, когда вы вытаскиваете все из стека. Этот алгоритм приводит к лабиринтам примерно с & Quot; river & Quot; фактор, насколько это возможно, с меньшим, но более длинным тупиком, и, как правило, очень длинный и извилистое решение. Он работает довольно быстро, хотя алгоритм Прима немного быстрее. Рекурсивное отслеживание в обратном направлении не работает как сумматор, так как это приводит к пути решения, который следует за внешним краем, где вся внутренняя часть лабиринта прикреплена к границе одним стержнем. Р>
Они создают только 10% тупиков
является примером лабиринта, созданного этим методом.
Другие советы
Оказывается, существует 12 классических алгоритмов для генерации " perfect " лабиринты. Лабиринт идеален, если в нем есть одно и только одно решение. Вот несколько ссылок на каждый алгоритм в порядке моих предпочтений.
<Ол>Для получения дополнительной информации, ознакомьтесь с mazelib в GitHub, библиотеке Python, реализующей все стандартные алгоритмы создания / решения лабиринтов. р>
Довольно простым решением может быть присвоение произвольных весов краям графа и применение алгоритма Крускала найти минимальное остовное дерево.
Лучшая дискуссия об алгоритмах создания лабиринтов: http://www.jamisbuck.org/ Presentations / rubyconf2011 / index.html (был на HN пару дней назад).
Как ни странно, немного изменив «канонические» правила и начав со случайной конфигурации, Конвея Игра Жизни , кажется, генерирует довольно хорошие лабиринты!
(я не помню точное правило, но это очень простая модификация, которая имеет тенденцию «уплотнять» популяцию клеток ...)
Мой любимый способ - использовать алгоритм Крускала, но при случайном выборе и удалении ребра оценивать выбор в зависимости от типов ребер, к которым он подключен.
Изменяя веса для разных типов ребер, вы можете создавать лабиринты с множеством отличительных характеристик или " индивидуальности " ;. Смотрите мой пример здесь:
Одним из методов создания лабиринта является рандомизированная версия алгоритма Прима.
Начните с сетки, полной стен. Выберите клетку, отметьте ее как часть лабиринта. Добавьте стены ячейки в список стен. Пока в списке есть стены:
Выберите случайную стену из списка. Если ячейка на противоположной стороне еще не в лабиринте:
(i) Сделайте стену проходом и отметьте клетку на противоположной стороне как часть лабиринта.
(ii) Добавьте соседние стены ячейки в список стен.
Если ячейка на противоположной стороне уже была в лабиринте, удалите стену из списка.
Для большего понимания нажмите здесь
Вот алгоритм DFS, записанный в виде псевдокода:
создайте CellStack (LIFO) для хранения списка местоположений ячеек
установить TotalCells = количество ячеек в сетке
выберите ячейку наугад и назовите ее CurrentCell
set VisitedCells = 1
while VisitedCells < TotalCells
найти всех соседей CurrentCell со всеми неповрежденными стенами
если один или несколько найдены
выберите один наугад
сбить стену между ней и CurrentCell
нажмите местоположение CurrentCell на CellStack
сделать новую ячейку CurrentCell
добавить 1 в VisitedCells
еще
вытолкнуть последнюю запись ячейки из CellStack
сделать это CurrentCell
ENDIF
endWhile