Алгоритм генерации лабиринта без тупиков?
Я ищу алгоритм генерации лабиринта, который может генерировать лабиринты с тупиками, но только начало и конец. Вот так:
изображение из http://www.astrolog.org/labyrnth/maze/unicursl.gif
где я могу найти или перейти к построению такого алгоритма генерации лабиринта?
8 ответов
похоже, вам нужна кривая заполнения псевдослучайного пространства (например, см. контекстные кривые заполнения пространства-EUROGRAPHICS ’2000 (формат PDF, 1.1 Мб))
посмотрите кривая заполнения пространства.
Я подозреваю, что вы могли бы применить некоторую случайность к построению одного из них, чтобы достичь того, что вы хотите.
Я бы sugest, чтобы начать с полностью черного (полного) квадрата и попытаться выкопать путь. Во время копания вы легко убедитесь, что нет тупиков, просто продолжайте идти. Используйте алгоритм поиска backtracking, depth first. Сделайте "случайное блуждание" - на каждом шаге случайным образом решите, сохранить ли направление или изменить его. Проверьте состояние тупика - если вы застряли, вы можете либо сказать: "Ну, я закончил, я в финише", или, если вы считаете, что лабиринт еще не выкопан достаточно, просто вернуться. Всегда помните, что вы делали раньше, и попробуйте случайно какое-то другое действие. Вероятно, используйте эвристику, чтобы предпочесть определенные направления, например, всегда держать некоторое свободное пространство перед уклонением от стены, попытаться сначала обойти стены и т. д. - таким образом, вы могли бы найти желаемое решение, которое заполняет весь квадрат гораздо быстрее.
в приведенном примере есть только один фактический путь от начала до конца. Если это все, что вы хотите, я думаю, вы могли бы использовать случайные блуждания!
концепция проста: учитывая внешние границы лабиринта, начальную и конечную точки, напишите функцию для генерации случайных блужданий из начальной точки, которые в конечном итоге заканчиваются в конечной точке. Условия были бы таковы, что наш "случайный ходок" может двигаться только вверх, вниз, вправо или влево от предыдущего квадрата и не может прийти в пределах одного квадрата ранее пройденного квадрата (это создает стены).
Как я вижу, здесь есть две алгоритмические проблемы. Во-первых, выяснение того, находимся ли мы в пределах одного квадрата от ранее пройденного квадрата (столкновения). Возможно, мы могли бы сохранить список пройденных квадратов (их координаты) и границ лабиринта, и для каждого нового квадрата оценить расстояние от каждого квадрата в списке. Хотя это звучит не очень эффективно.
другой задача на самом деле достигает конечной точки с нашим случайным блужданием. Если бы столкновения с ранее пройденными квадратами не были проблемой, мы были бы обязаны в конечном итоге достичь нашей конечной точки, но с ними у нас есть проблема, что мы могли бы отгородиться от конечной точки. Способ избежать этого-проверить и избежать ввода циклов. Если мы избегаем входить в петли, образованные пройденным путем и / или границами лабиринта, то мы поддерживаем возможный путь к конечной точке. Насколько на самом деле прикидываем, не попали ли мы в петлю... Это довольно сложно.
Если у вас уже есть алгоритм решения лабиринта, вы можете запустить его всякий раз, когда у вас есть возможное столкновение, чтобы увидеть, существует ли путь от вашего текущего квадрата до конечной точки. Когда вы запустите его, подумайте, что все ранее пройденные квадраты являются стенами, а также их границами.
Я не думал об этом, просто идея:
- сосредоточьтесь не на тропе, а на стенах
- начните только с черного внешнего квадрата
- постепенно добавлять блоки стены в произвольных положениях, прилегающих к существующим блокам стены, сохраняя условие, что остается путь от начала до конца
- когда ни одна ячейка пути не имеет более двух соседей пути, вы сделали
"произвольный" выбор процесс для новых битов стены может начать пытаться "вырасти" прямые разделы перпендикулярные к наружной стене, тогда на некотором этапе переключите к заполнять внутри где возможный.
вероятно, ему понадобится возможность вернуться, если он застрянет.
наверное, это не слишком эффективно.
Ahh-я нашел гораздо более простой способ создания одномерного лабиринта.
начните с пустой сетки и заполните ее небольшими петлями 2x2. Если сетка нечетная по четной, вам нужно будет смешать несколько петель 2x3, а если нечетная по нечетной, вам придется оставить один квадрат свободным-я обычно оставляю угол незаполненным.
далее, произвольно соедините петли вместе, чтобы сформировать большие петли-так (например)2 петли 2x2 становятся одним циклом 4x2. Продолжайте делать это, убедившись, что вы не присоединяйте петлю обратно к себе.
в конечном итоге вы получите один цикл, который использует все ячейки, занятые исходной фермой циклов. Разорвите эту петлю в любом положении, и вы получите одномерный лабиринт, где начальная и конечная локации находятся рядом друг с другом.
теперь вы можете перемещать конечные точки по сетке, формируя и разрывая небольшие петли-зацепите конец в другую точку в лабиринте, а затем сломайте Т-образный переход на противоположной стороне, чтобы переформовать ваш единственный кусок веревки с новым конечным местоположением.
Если вы работаете над нечетным лабиринтом, используйте этот последний метод, чтобы червь один из ваших концов к незаполненному углу, чтобы завершить лабиринт.
Я думаю, что нашел другой метод, однако я еще не тестировал его широко.
см.https://twitter.com/tdhooper/status/340853820584230915/photo/1
слева направо:
создайте не-уникурсальный лабиринт, как описано здесь https://en.wikipedia.org/wiki/File:Prim_Maze.svg, я думаю, что это алгоритм прим
закрыть выход
нарисовать путь, который посещает каждую точку в лабиринте (т. е. попробуйте решить его)
сделайте этот путь стеной
когда 'прогулки' сохранить изменения, сделанные на каждом шаге в стек, так что вы можете смотреть х шагов вперед, а затем на каждом этапе таким образом, что вы можете не предпринимать никаких дальнейших шагов ( пошел в угол или спирали как пешком ) поп стека, пока у вас есть жизнеспособный пешеходная дорожка и продолжайте идти оттуда до тех пор, пока стек пуст ( я.е вы поп стек весь путь обратно, потому что на каждом предыдущем шаге не было никакой жизнеспособной соседа ). Затем примените преобразования к структуре данных maze.
Я работаю над этим в данный момент... Начиная с края, я случайно иду по квадратному массиву, отмечая ячейки длиной пути, когда я прохожу через них.
когда вы застряли (и вы будете), создайте Т-образный переход, образующий цикл с самым последним путем, который рядом с вами (но см. ниже). Затем я возвращаюсь по существующему пути на другую сторону Т-образного перехода и разрываю там петлю. Этот болтающийся хвост затем формирует вашу новую "голову" случайного блуждания (не забудьте пересчитать длину пути из источника пути), и вы можете продолжить.
эксперименты показывают, что, делая это, он не (Или еще не - см. ниже) попал в петлю создания новых хвостов, пока ваш новый "хвост" пойман, вы не просто безмозгло переформируете связь с клеткой, от которой вы только что отделились, если это самый последний-выберите второй самый последний в этом случае.
завершающий случай-это когда вы застреваете на элементе edge, и вы заполнили массив (длина вашего пути совпадает с площадью массива) - вы сделали. Ваша начальная точка ведет к конечной.
кажется, есть две возможные неэффективности и потенциальные икоты с этим (я сейчас играю с алгоритмом) - иногда вы заходите в угол, и единственный способ продолжить-это переформулировать петлевую связь с той, которую вы только что сломали. Затем последовательность возвращается через все петли, которые вы ранее сделали для точка, в которой вы изначально застрял. Если это не могу пойти куда-нибудь еще (это еще один угол), то вы будете просто подпрыгивать между ними. Есть способы обойти это, но это означает, что вы сохраняете какой-то список замкнутых ячеек, только очищая его, когда вы на самом деле кладете какой-то новый путь.
другое заключается в том, что он, похоже, склонен оставлять нечетный квадрат незаполненным, особенно когда Ваш массив нечетным. Я не полностью исследовал, почему это так, и когда это возникает, что предыдущая проблема угла кажется особенно распространенной. Работа продолжается...