Найдовший алгоритм шляху для генерування лабіринтів


10

У мене проста карта на основі сітки, що складається з таких приміщень (A = вхід, B = вихід):

   0 1 2 3
  #########
0 # B # #####
  #########
1 # ### #
  #########
2 # #
  # #
3 # #
  #########
4 # ### #
  #########
5 ### A #
  ### #
6 ### #
  #########

І я застряг, намагаючись скласти відповідний алгоритм, щоб створити шлях між дверима між кімнатами, таким чином, щоб гравець повинен вивчити більшу частину карти, перш ніж знайти вихід.

Іншими словами, я намагаюся знайти самий довгий можливий шлях від А до В .

(Я знаю, що цю проблему можна вирішити для ациклічних графіків; проте в цьому випадку можуть бути цикли.)

EDIT: Ще один приклад, коли кімнати з'єднані за допомогою заливки, а вихід обраний як найдаліша кімната від входу:

   0 1 2 3
  #########
0 # B # #
  # # - #####
1 # | # #
  ### # #
2 ### # #
  ### - # - ###
3 # | ###
  # - #######
4 #А | #
  # #
5 # #
  # #
6 # #
  #########

Зауважте, що шлях до виходу зовсім не найдовший шлях.


Якщо ви змусите гравця пройти найдовший можливий шлях, ви насправді будуєте прямий шлях, який видається складним. Це погано.
o0 '.

Це непогано (наприклад, це основа жанру залізничного шутера), але вам потрібно знати, що ви це робите, і розробити решту своєї гри, щоб добре працювати з нею.

Також простіше контролювати темп гри, коли рівні здебільшого лінійні. Це дає змогу додати, наприклад, приміщення для відновлення після особливо важкої кімнати монстрів. Якби не було основного шляху, розподіл викликів та нагород було б випадковим.
Користувача не знайдено

Відповіді:


11

Я думаю, що ти йдеш про це неправильним шляхом. Максимальний шлях у графіку з циклами технічно не визначений, оскільки це нескінченно, якщо цикл лежить між початком і кінцем. Ймовірно, є розумні способи розширення / обмеження визначення максимального шляху, але я не думаю, що це найкращий підхід тут.

Ви не намагаєтесь моделювати фактично довгий шлях (наприклад, робот, який намагається дослідити якомога більше області на карті). Ви просто намагаєтесь змусити гравця досліджувати багато кімнат.

Отже, зробіть шанс гравця знайти вихід пропорційним відсотковій частині досліджуваної карти досі . Скажімо, на рівні X є кімнати, і персонаж гравця досліджував Y. Наступного разу, коли персонаж заходить до кімнати, розмістіть вихід з ним з імовірністю f (Y, X). Тривіальним прикладом f може бути (Y * Y) / (X * X) - наприклад, для 10 номерів є 100% шанс виходу в останню кімнату, 81% шансів, що це буде в сусідній останній номер - і лише 1% шансів, що це в першій кімнаті.

Ви можете налаштувати рівняння, проте хочете, щоб гра відчувала себе правильно, і, можливо, навіть дати гравцеві певні здібності, щоб зробити його більш схильним. Ключова частина полягає в тому, щоб не створювати вихід, поки персонаж фактично не ввійде в кімнату. Цей метод також захищений від знань гравця про алгоритм генерації підземелля; навіть якщо у гравця є дивні моделі руху, такі як стрибок лицаря в NetHack або телепортація, їм доведеться вивчити більше кімнат, щоб знайти вихід.

Якщо вам потрібно статично генерувати вихід, ви можете використовувати ту саму ідею з віртуальним символом. Уявіть, що заливка заповнюється, починаючи з позиції персонажа, переміщаючись по одній комірці кожної ітерації. Остання кімната, яку потрібно заповнити, - це кімната, куди належить вихід (насправді, остання заповнена комірка - це клітина, де вона знаходиться найдалі від гравця). Однак у цьому випадку у гравця є більше інформації про вихід - якщо вони зліва, швидше за все, справа - і якщо вони зможуть телепортуватись, то, можливо, зможуть дістатися туди швидше, ніж звичайна випадкова прогулянка.

Нарешті, я щойно закінчив шахрайство, де вихід з іншого боку карти породжував персонажа гравця, а потім випадково блукав. Деякі предмети в підземеллі зробили це помітним на карті, за рахунок швидшого голодування. Я не робив жодного аналізу, але напевно відчувалося, що мені потрібно було вивчити більше карти, щоб знайти його, і це надало рівнів унікального відчуття.


Динамічне покоління здається досить гарною ідеєю, поки гравець не помітить. Інакше я думаю, що вони почували б себе досить обдуреними. Я люблю ідею заливки.
Користувача не знайдено

2
Ну, уся ваша пропозиція в певному сенсі обманює гравця. Не звинувачуйте мене в удосконаленні математики, щоб не вимагати світової моделі. ;) Але ви можете використовувати конструктивні трюки, щоб зробити його більш приємним - наприклад, вихід розміщується апріорі, але ключ, необхідний для його використання, генерується в описаному нами методі, або розміщується на монстрі, який нереститься після вивчення X кімнати / вбиття X монстрів, або для відкриття дверей потрібно перевернути X-вимикачі, по одному в кожній кімнаті тощо ...

Я спробував підхід до заливки. Це добре підключає кожну кімнату і виробляє короткі гілки, але насправді це не дає найдовшого можливого шляху до виходу, навіть якщо вихід є останнім вузлом, який відвідав (або, на мою реалізацію, самий далекий). (приклад доданий до мого запитання)
Користувача не знайдено

Хоча я все для лабіринтів на основі ключів / комутаторів. Просто здається, що реалізувати таку річ з деревами, адже тоді, якщо у вас є дві гілки, ви можете виявити, яка гілка веде до виходу, заблокуйте її і покладіть ключ в іншу гілку.
Користувача не знайдено

Але я визнаю, що помилявся, думаючи, що це проблема "від A до B". Я усвідомлюю, що має сенс знайти вихід як результат алгоритму, а не як мета.
Користувача не знайдено

6

Можливою альтернативою було б створити (максимум?) Дерево, що охоплює, використовуючи Prim / Kruskal (з метою усунення циклів) і застосувати традиційний алгоритм найдовшого шляху на дереві, що охоплює.

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

EDIT: Результат використання алгоритму на основі Крускала та розміщення виходу в кінці найдовшої гілки:

   0 1 2 3
  #########
0 #A | #
  # ##### - #
1 # #
  ### #
2 ### #
  ### #
3 ### #
  ### - #####
4 # | #
  # - ##### - #
5 # ### #
  # - #######
6 # # B #
  # # - #
7 # | #
  #########

1
Я також збирався запропонувати Primm :-), +1, я думаю, що зворотний
трек

2

Ось з чим можна поспішати:

Connect each room with a door to another room.
N = 0.75*TotalNumberOfRooms
Until (pathSize > N) {
  Use A* pathing to get a path from A to B. (G being size of room, or # of monsters)
  if (pathSize < N) remove a connection/door
  if (noPath) choose a different door/connection
  if (room.doors < 1) choose a different door/connection
}

Я б прибрав двері навмання вздовж доріжки, інакше у вас виходить 1 дверцята на виході та тонни дверей на початку.

Я думаю, що це O(n^2)не дуже добре для великих карт.


В принципі дуже елегантне рішення. Наступного разу я повинен спробувати придумати щось подібне, перш ніж піти на перекручені методи.
Користувача не знайдено

Ну, елегантний, можливо, але це буде процесорна свиня. O (n ^ 2) не буде добре масштабуватися з великими картами.
Стівен Фурлані


1

Я вважаю, у вас вже є чудові відповіді, але ось мій 0,02 долара теоретичного вирішення проблеми.

Те, що ви хочете, НЕ найдовший шлях, але найдовший найкоротший шлях. Ви хочете, щоб приміщення було найдалі, враховуючи, що ви розглядаєте найкоротший шлях до кімнати. Це, мабуть, звучить заплутано, але підрахувати це дуже просто.

  1. Почніть з початкової кімнати. Позначте кожного з сусідів 1. Вони знаходяться на відстані 1 від стартової зали.
  2. Для кожної кімнати з позначкою 1 відвідайте кожного з її НЕМАРКОВИХ сусідів та позначте їх 2. Вони знаходяться на відстані 2 відстані від початку.
  3. Продовжуйте, поки ви не покриєте всі кімнати. Кімната з максимальною кількістю знаходиться найдалі від початку.

Обчислення фактично найдовшого шляху (звичайно не буде зайняти занадто багато часу, наприклад, 10 номерів) не буде працювати, оскільки ви не можете змусити гравця пройти цей самий довгий шлях. Тож розміщення входу та виходу у дві кімнати, віддалені одна від одної, - найкраща пропозиція. Щоб знайти це, обчисліть найдальшу кімнату від випадкової кімнати. Потім з тієї кімнати знайдіть найдальшу кімнату. Це називається знаходження діаметра графіка, будь ласка, Google.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.