Алгоритм двоичного дерева лабиринт

Пример проектной работы / АиСД. Проектная работа

Студенты: Коваленко Л. А. Курс: 2 Группа: ИКПИ-81 Преподаватель: Дагаев А. В.

Алгоритмы генерации идеальных лабиринтов .

1.1.1 Алгоритм Олдоса – Бродера .

1.1.3 Алгоритм двоичного дерева.

1.1.4 Алгоритм Recursive Backtracking .

1.1.5 Алгоритм рекурсивного деления.

1.1.7 Алгоритм растущего дерева.

1.1.9 Алгоритм Прима (упрощенный).

1.1.10 Алгоритм Прима (модифицированный) .

Алгоритмы генерации неидеальных лабиринтов .

1.2.1 Алгоритм змеевидного лабиринта .

1.2.2 Алгоритм маленьких комнат .

1.2.3 Алгоритм спирального лабиринта .

2. ПОИСК КРАТЧАЙШЕГО ПУТИ В ЛАБИРИНТАХ.

Алгоритм итеративного поиска в ширину.

3. РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ .

1.1 Алгоритмы генерации идеальных лабиринтов

Идеальный лабиринт – такой лабиринт, в котором одна клетка связана с другой одним единственным путём. Иначе говоря, остовное дерево.

Для создания стандартного идеального лабиринта обычно необходимо «выращивать» его, обеспечив отсутствие петель и изолированных областей.

Следующие алгоритмы генерируют идеальные лабиринты либо методом добавления стен, либо методом вырезания проходов.

Таблица 1. Алгоритмы генерации идеальных лабиринтов

Решение. Это процент ячеек лабиринта, по которым проходит его решение для типичного лабиринта, создаваемого алгоритмом. Здесь предполагается, что лабиринт состоит из 100×100 проходов, а начало и конец находятся в противоположных углах. Этот параметр является показателем «извилистости» пути решения. Максимальную извилистость имеют одномаршрутные лабиринты, потому что решение проходит по всему лабиринту. Минимально возможную извилистость имеет двоичное дерево, у которого решение просто пересекает лабиринт и никогда не отклоняется и не приостанавливает движение по направлению к концу. Обычно генерация добавлением стен имеет те же свойства, что и вырезание проходов, но если значения сильно отличаются, то в скобках указывается процент в случае добавления стен.

Тупики. Это приблизительный процент ячеек, являющихся тупиками в лабиринте. Обычно при добавлении стен процент такой же, как и при вырезании проходов, но если они значительно отличаются, то в скобках указан процент при добавлении стен. Значение для алгоритма выращивания дерева на самом деле варьируется от 10% (если всегда выбирается самая новая ячейка) до 49% (если всегда выбирается самая старая ячейка). При достаточно высоком показателе проходов количество тупиков Recursive Backtracking может становиться ниже 1%. Наибольший вероятный процент тупиков в двухмерном ортогональном идеальном лабиринте равен 66% — это одномаршрутный проход с кучей тупиков единичной длины по обеим сторонам от него.

Тип. Существует два типа алгоритмов создания идеальных лабиринтов:

• Алгоритм на основе дерева выращивает лабиринт подобно дереву, всегда добавляя к тому, что уже есть, и на каждом этапе имея правильный идеальный лабиринт.

• Алгоритм на основе множеств выполняет построения там, где ему хочется, отслеживая части лабиринта, соединённые друг с другом, чтобы соединить всё и создать правильный лабиринт на момент завершения.

Фокус. Большинство алгоритмов можно реализовать или как вырезание проходов, или как добавление стен. Очень немногие можно реализовать только как один или другой подход. В одномаршрутных лабиринтах всегда используется добавление стен, потому что в них задействуется разбиение проходов стенами на две части, однако базовый лабиринт можно создать любым способом. Recursive Backtracking нельзя реализовать с добавлением стен, потому что в этом случае он склонен создавать путь решения, который следует вдоль внешнего края, где вся внутренняя часть лабиринта соединена с границей единственным проходом. Рекурсивное деление нельзя использовать для вырезания проходов, потому что это приводит к созданию очевидного решения, которое или следует вдоль внешнего края, или иначе напрямую пересекает внутреннюю часть.

Читайте также:  На какие деревья можно привить айву

Отсутствие смещенности. Одинаково ли воспринимает алгоритм все направления и стороны лабиринта так, что последующий анализ лабиринта не может обнаружить никакой смещенности проходов. Алгоритм двоичного дерева чрезвычайно смещён, в нём легко перемещаться в один угол и сложно в противоположный. Sidewinder тоже смещён, в нём легко перемещаться к одному краю и сложно к противоположному. Алгоритм Эллера склонен к созданию проходов, приблизительно синхронизируя начальные или конечные края.

Однородность . Генерирует ли алгоритм все возможные лабиринты с равной вероятностью. «Да» означает, что алгоритм полностью однороден. «Нет» означает, что

алгоритм потенциально может генерировать все возможные лабиринты в пределах любого пространства, но не с равной вероятностью. «Никогда» означает, что существуют возможные лабиринты, которые алгоритм никогда не сможет сгенерировать. Учтите, что только алгоритмы с полным отсутствием смещенности могут быть полностью однородными.

Память . Объём дополнительной памяти или стека, необходимый для реализации алгоритма. Эффективные алгоритмы требуют только битовой карты самого лабиринта, в то время как другие требуют объёма памяти, пропорционального одной строке (N), или пропорционального количеству ячеек (N 2 ). Некоторым алгоритмам даже не нужно иметь в памяти весь лабиринт, и они могут добавлять части лабиринта бесконечно (такие алгоритмы помечены звёздочкой). Алгоритму Эллера нужен объём памяти для хранения строки, но большего ему не требуется, потому что достаточно хранить только одну строку лабиринта. Алгоритму Sidewinder тоже нужно хранить только одну строку лабиринта, в то время как двоичному дереву нужно отслеживать только текущую ячейку. Для рекурсивного деления требуется стек объёмом вплоть до размера строки, но ему не нужно смотреть на битовую карту лабиринта.

1.1.1 Алгоритм Олдоса – Бродера Алгоритм Олдоса–Бродера — однородный алгоритм, то есть он с равной

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

1. Изначально все поле содержит стены.

3. Перемещаемся в любую соседнюю ячейку в пределах поля.

4. Если мы попали в не вырезанную ячейку, то вырезаем в неё проход из предыдущей.

5. Пока не вырежем проходы во все ячейки (пока все ячейки не будут посещены), повторяем №3-4: продолжаем двигаться в соседние ячейки, пока не вырежем

Плохо в этом алгоритме то, что он очень медленный, так как не выполняет интеллектуального поиска последних ячеек, то есть, по сути, не имеет гарантий завершения. Однако из-за своей простоты он может быстро проходить по множеству ячеек, поэтому завершается быстрее, чем можно было бы подумать. В среднем его выполнение занимает в семь раз больше времени, чем у стандартных алгоритмов, хотя в плохих случаях оно может быть намного больше, если генератор случайных чисел постоянно избегает последних нескольких ячеек.

Читайте также:  Дизайнерское решение интерьера деревом

Поскольку соседа раньше не посещали, вырезаем проход между ними

Выбираем случайного соседа и делаем проход по нему.

Поскольку сосед был посещен ранее, мы не вырезаем проход к нему из предыдущей ячейки.

1.1.2 Алгоритм Уилсона Алгоритм Уилсона — усовершенствованная версия алгоритма Олдоса-Бродера,

создаёт лабиринты точно с такой же текстурой (алгоритмы однородны, то есть все возможные лабиринты генерируются с равной вероятностью), но выполняется гораздо быстрее.

1. Изначально все поле содержит стены.

2. Выбираем любую ячейку и добавляем ее в UST.

3. Выбираем любую ячейку, которой еще нет в UST, и выполняем случайную прогулку, пока не встретим ячейку, которая находится в UST.

4. Добавляем ячейки и ребра, затронутые в случайном блуждании, к UST.

5. Повторяем №3-4, пока все ячейки не будут добавлены к UST.

UST (uniform spanning trees) — однородные остовные деревья. Остовное дерево — это дерево, которое соединяет все вершины графа.

Однородное остовное дерево — это любое из возможных остовных деревьев графа, выбранное случайным образом и с равной вероятностью.

Алгоритм имеет те же проблемы со скоростью, что и алгоритм Олдоса-Бродера, потому что может уйти много времени на нахождение первого случайного пути к начальной ячейке, однако после размещения нескольких путей остальная часть лабиринта вырезается довольно быстро. В среднем он выполняется в пять раз быстрее Олдоса-Бродера, и менее чем в два раза медленнее лучших по скорости алгоритмов. Стоит учесть, что в случае добавления стен он работает в два раза быстрее, потому что вся стена границы изначально является частью лабиринта, поэтому первые стены присоединяются гораздо быстрее.

Начинаем со случайного добавления ячейки в лабиринт

Затем мы выбираем случайно другую не посещённую ячейку и совершаем случайный обход, пока не встретим эту первую ячейку. Обратите внимание, что у этого случайного обхода есть несколько ограничений: хотя он может пересекать уже пройденные ячейки (если они еще не в лабиринте), мы не хотим, чтобы в конечном пути были какие-либо петли. Таким образом, мы также записываем направление, последнее использовавшееся для выхода из каждой ячейки, и будем использовать эти направления для формирования окончательного пути, как только прогулка встретится со стартовой ячейкой.

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

Читайте также:  Шаблон генеалогическое дерево 2 класс

Все остальные ячейки, которые были посещены во время прогулки, но которые не сделали «окончательный срез», просто сбрасываются.

Теперь мы делаем это снова. Обратите внимание, что на этот раз в лабиринте четыре ячейки, а не одна, что дает нам гораздо больше целей для попадания. Это то, что позволяет алгоритму сходиться быстрее: каждый проход по алгоритму увеличивает вероятность того, что следующий проход закончится раньше.

Затем мы идем по пути и снова добавляем ячейки и ребра в лабиринт

К настоящему времени паттерн становится виден: каждый проход добавит еще одну случайную «ветвь» к дереву, пока все ячейки не будут добавлены в лабиринт.

1.1.3 Алгоритм двоичного дерева Алгоритм двоичного дерева — это самый простой и быстрый из возможных

алгоритмов. Однако создаваемые лабиринты имеют текстуру с очень высокой смещённостью.

1. Изначально все поле содержит стены.

2. Для каждой ячейки в сетке случайным образом разделяем проход на север или

запад (север или восток / юг или запад / юг или восток).

Причем: любой выбранный вами диагональный набор должен использоваться последовательно во всем лабиринте.

Каждая ячейка независима от всех других ячеек, потому что не нужно при её создании проверять состояние каких-либо других ячеек. Следовательно, это настоящий алгоритм генерации лабиринтов без памяти, не ограниченный по размерам создаваемых лабиринтов (Такое свойство отлично подходит для визуального отображения бесконечно большого лабиринта при перемещении по нему.).

Лабиринты на основе двоичных деревьев отличаются от стандартных идеальных лабиринтов, потому что в них не может существовать больше половины типов ячеек. Например, в них никогда не будет перекрёстков, а все тупики имеют проходы, ведущие вверх или влево, и никогда не ведущие вниз или вправо. Лабиринты склонны иметь проходы, ведущие по диагонали из верхнего левого в нижний правый угол, и по ним гораздо проще двигаться из нижнего правого в верхний левый угол. Всегда можно перемещаться вверх или влево, но никогда одновременно в оба направления, поэтому всегда можно детерминированно перемещаться по диагонали вверх и влево, не сталкиваясь с барьерами. Иметь возможность выбора и попадать в тупики вы начнёте, перемещаясь вниз и вправо.

Поскольку этот алгоритм не должен учитывать состояние каких-либо соседних ячеек, мы можем начать с любого угла.

Для первой строки мы вырезаем весь проход.

Вырезать весь проход по первому столбцу можно сразу. Мы будем делать это последовательно.

Идем сверху-вниз, слева-направо. Подкидываем монетку — прорезаем

сверху-вниз. Могло быть так: (Мы могли бы прорезать слева-направо,

как представлено на втором рисунке.)

Далее снова подкидываем монетку. Прорезаем слева-направо.

Источник

Оцените статью