2D мінус лабіринт 1D


27

Ця проблема полягає в перетворенні 2D лабіринтів у 1D лабіринти.

Огляд

+-+-+-+-+-+-+   +-+-+-+-+-+-+                    graph {
| |   |     |   |A|   |    B|   A         B        A -- D
+ + + + +-+-+   + + + + +-+-+    \        |        C -- D
|   | |     |   |   | |     |     \       |        D -- E
+-+-+ +-+-+ +   +-+-+ +-+-+ +      \      |        E -- F
|           |   |C   D E   F|   C---D-E---F        E -- G
+-+-+-+ +-+ +   +-+-+-+ +-+ +         |   |        B -- F
|         | |   |      G  | |     .---G   |        F -- J
+ +-+-+-+ + +   + +-+-+-+ + +   .'   /    |        G -- H
| |       | |   |H|I      |J|   H I-'     J        G -- I
+-+-+-+-+-+-+   +-+-+-+-+-+-+     (ascii)        } // (graphviz dot)       
   Figure 1       Figure 2                 Figure 3

Для цілей цього виклику традиційний 2D лабіринт - це прямокутний лабіринт, сформований з точок решітки, де містяться всі наступні дії:

  • Він закритий (зовнішній ободок з'єднаний стінами).
  • Всі точки решітки з'єднані зі стінами
  • Він пов'язаний (для кожні два проміжки X і Y є шлях між ними)
  • Це ациклічно (немає жодного шляху X назад до X без зворотного відстеження)

На малюнку 1 показаний традиційний 2D лабіринт. Ці лабіринти мають три сфери інтересу:

  • Тупики - місця, з яких є лише один доступний шлях
  • Коридори - місця, з яких є дві наявні шляхи
  • Точки прийняття рішень - місця, з яких є три або чотири доступних шляху

Для кожного такого лабіринту можна створити графік, де кінці та точки прийняття рішень є вузлами, а між кожними двома вузлами є край, пов'язаний стежкою по коридору. На малюнку 2 показаний такий самий лабіринт з такими вузлами, що позначені, а на малюнку 3 - графік лабіринту (у точках позначення точок ASCII та Graphviz).

1D лабіринти

1D лабіринти містять основи, які складаються парами і ідентифікуються за допомогою літери (в будь-якому випадку). На малюнку 4 показаний приклад 1D-лабіринту. Це в іншому випадку ідентично двовимірному лабіринту висотою 1, як показано на малюнку 5. Зокрема, на малюнку 5 відзначте позиції точки решітки, позначені символом +, які чергуються зліва направо; у лабіринті 1D кожен інший символ, що починається з самої лівої стінки, також є точкою грат.

                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  D|  D E|G E F|  F  |  G  |    |  D|  D E|G E F|  F  |  G  |
                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            Figure 4                         Figure 5

Правила навігації по цьому лабіринту наступні. Кожен хід може бути представлений як вперед ( >), так і назад ( <). Тут вперед і назад за замовчуванням мають те саме значення, що й наше інтуїтивне просторове усвідомлення; вперед йде в положення відразу праворуч, а назад відразу вліво.

Точки викривлення представляють місця, які асиметрично змінюють зв'язок із сусідами. Якщо ви переходите від сусіда до точки викривлення, положення двох точок перекону змінюється; якщо ви переходите з точки викривлення до сусіда, вони не поміняються. Наприклад, на рисунку 6 переміщення назад від 1 приводить вас до 2 (оскільки 1 - сусід G, а ми рухаємося від сусіда, точки 2 і @ змінюються місцями). Якщо рухатись вперед від точки 2 (точка викривлення G), ви приведете до рівня 3 (тут ми починаємо з деформації, тому підміна немає). Так само переміщення назад від 3 приведе вас до @.

        54 2367    89^   @1
|  D|  D E|G E F|  F  |  G  |
                     Y     X
          Figure 6

На малюнку 6 також показаний приклад навігації від X до Y, використовуючи послідовність рухів <<>><>>>>>. Ці кроки приводять вас до точок, позначених 123456789^відповідно, у такому порядку. Не соромтеся досліджувати його самостійно, використовуючи фрагмент коду в наступному розділі.

Перетворення 2D в 1D

Враховуючи 1D-лабіринт, можна створити графік, де кожен вузол є або тупиком, або парою основи, а краї існують між будь-якими двома вузлами, з'єднаними уздовж коридору. Цей графік дозволяє порівняти 1D та 2D лабіринти.

Наприклад, 1D лабіринт на рисунку 4 - це той самий лабіринт, що на малюнку 1. Щоб зрозуміти, чому, малюнок 7 додає мітки до тупиків. Використовуючи ці мітки для побудови графіка, графік рисунка 7 просто знову зображений на рисунку 3. На малюнку 8 показано прорив побудови цього графіка.

|  D|  D E|G E F|  F  |  G  |
 A   C           B   J H   I 
          Figure 7

|  D|  D E|G E F|  F  |  G  |
+ + + + + + + + + + + + + + + <- lattice points
|A  |C    |     |B   J|H   I| <- dead ends
|A D|C D E|G E F|B F J|H G I| <- all nodes (dead ends+warp points); i.e.:
                                 "where each end is either a dead end
                                  or a warp point pair"; note that each
                                  pair of warp points is the same node.
|A-D|C-D-E|G-E-F|B-F-J|H-G-I| <- corridors; note each is a connection, since
  1   2 3   4 5   6 7   8 9      "edges exist between any two nodes
                                  connected along a corridor"
   graph {                 graph {                 
     A -- D  // 1 <---->     A -- D                
     C -- D  // 2 <---->     C -- D                
     D -- E  // 3 <---->     D -- E                
     G -- E  // 4 <---->     E -- G                
     E -- F  // 5 <---->     E -- F                
     B -- F  // 6 <---->     B -- F                
     F -- J  // 7 <---->     F -- J                
     H -- G  // 8 <---->     G -- H                
     G -- I  // 9 <---->     G -- I                
   }                ^      }
    Built from      |      From Figure 3
     1D maze         `-> isomorphic mappings
                Figure 8

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

Наступний фрагмент надається, щоб допомогти візуалізувати механіку 1D-лабіринту та зв’язок між 1D-лабіринтом, графіком еквівалентності та 2D-лабіринтом.

Під час переміщення по 1D лабіринту в цьому фрагменті виділяються останні два вузли, які ви торкаєтеся. Ті ж вузли виділяються однаково на графіку еквівалентності та 2D-лабіринті.


Загалом для будь-якого традиційного 2D лабіринту може бути створений еквівалентний 1D лабіринт цього типу. Дещо складнішим прикладом є малюнок 9:

+-+-+-+-+-+-+   +-+-+-+-+-+-+                   graph {
| |   |   | |   |A|   |   |B|   A         B       A -- D
+ + + + + + +   + + + + + + +    \       /        C -- D
|   | | |   |   |   | | |   |     \     /         D -- E
+-+-+ + +-+-+   +-+-+ + +-+-+      \   /          B -- E
|           |   |C   D E    |   C---D-E           E -- F
+-+-+-+ +-+ +   +-+-+-+ +-+ +         |\          E -- I
|         | |   |      F  | |     .---F \         F -- G
+ +-+-+-+ + +   + +-+-+-+ + +   .'   /   \        G -- H
| |       | |   |G|H      |I|   G H-'     I       H -- I
+-+-+-+-+-+-+   +-+-+-+-+-+-+     (ascii)       } // (graphviz dot)
   Figure 9       Figure 10             Figure 11

|  D|  D E  |F E  |  F  |       |  D|  D E  |F E  |  F  |
                                 A   C     I     B G   H
      Figure 12                       Figure 13

Цей лабіринт має вузол з чотирма шляхами (E на малюнку 10). На малюнку 11 показано його графік. Фіг.12 - еквівалентний 1D лабіринт; і на малюнку 13 показаний такий же лабіринт з мітками для тупиків для порівняння з малюнком 11.

Виклик

Подавши 2D лабіринт як вхід, напишіть функцію або програму, яка перетворює 2D лабіринт у 1D лабіринт з точками деформації. У точці викривлення може використовуватися будь-яка з 52 букв у кожному випадку.

Гарантії введення (якщо будь-яке з них не виконано на вході, вам не доведеться з цим боротися):

  • Лабіринт введення підключений (тобто ви завжди можете перейти з будь-якої точки до будь-якої іншої).
  • Вхідний лабіринт закритий.
  • Вхідний лабіринт прямокутний.
  • Використовуються всі точки решітки +.
  • Використовуються всі стіни між точками решітки в одному ряду |
  • Використовуються всі стіни між точками решітки в одному стовпчику -.
  • Усі простори є частиною стежки (і все всередині лабіринту).
  • Шляхи - це всі простори (це завжди буде традиційно, без перешкод)
  • Шляхи - це рівно один простір.
  • Лабіринт будується з'єднанням точок на решітці.
  • У графі лабіринту не більше 52 загальних вузлів (тобто тупиків плюс пунктів рішення).

Формат виводу:

  1. Вихід повинен бути одним рядком із зображенням 1D лабіринту.
  2. У вашому виході не повинно бути пробілів проміжних / кінцевих пробілів; за винятком того, що заздалегідь новий рядок відмінний.
  3. Перший символ і кожен другий символ згодом - це точки решітки.
  4. Всі стіни повинні бути на точках грат; і всі точки викривлення між ними.
  5. Графік 1D-лабіринту повинен бути еквівалентний графіку 2D-лабіринту.
  6. Ваші 1D лабіринти повинні бути компактними; всі точки, що не мають решітки, повинні бути тупиками (тобто прилеглими до стін) або точковими основами.
  7. В тільки букви в вашому виведення повинні бути точки основи. Кожна викривна точка трапляється на лінії рівно двічі.

Приклад:

|  D|  D E|G E F|  F  |  G  | <- (1,2) The single line output
+ + + + + + + + + + + + + + + <- lattice point spacing... (3) 
                                 (4,6) lattice points are all walls or spaces
                                 (5) See Figure 8
                                 (7) D, E, F, G appear twice; no other labels

Це код-гольф. Переможець - це правильне подання, що не має лайків, з найменшими байтами.

Тестування

Немає тестових випадків для цього виклику, оскільки існує велика кількість правильних результатів для будь-якого нетривіального лабіринту.

Однак я вбудував шашку в C ++ (ця перевірка графікує обидва рішення за допомогою кананізації графіка ).

Крім того, ось кілька прикладів, які допоможуть проілюструвати правильне форматування:

Приклад 1

+-+-+-+-+-+-+
| |   |     |
+ + + + +-+-+
|   | |     |
+-+-+ +-+-+ +
|           |
+-+-+-+ +-+ +
|         | |
+ +-+-+-+ + +
| |       | |
+-+-+-+-+-+-+
->
|  D|  D E|G E F|  F  |  G  |

Приклад 2

+-+-+-+-+-+-+
| |   |   | |
+ + + + + + +
|   | | |   |
+-+-+ + +-+-+
|           |
+-+-+-+ +-+ +
|         | |
+ +-+-+-+ + +
| |       | |
+-+-+-+-+-+-+
->
|  D|  D E  |F E  |  F  |

Більше прикладів можна знайти тут .


1
Я не думаю, що пояснення 1D лабіринтів зовсім зрозуміле ... Можливо, доповнити менший / простіший приклад допоможе.
mbomb007

Це досить круто. Так, це допомагає.
mbomb007

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

Опис 1D лабіринту є схематичним. Мені довелося прочитати цифру 7, щоб зрозуміти, що символи вертикальної смуги в 1D лабіринті - це стіни, через які ти не можеш перейти.
edc65

1
приклад 1, 1-лабіринт, складений у 2-лабіринт, де кожна пара букв - це сходи: gist.github.com/sparr/36d6355cc4c785a27b12157666169082
Sparr

Відповіді:


3

Python 2 з igraph , 492 369 байт

import igraph,string
def f(s):
 C=s.find('\n')/2;N=' ';g=igraph.Graph(0,[(i,i+j)for i in range(len(s)/(4*C+4)*C)for j in(1,C)if s[(i/C*2+1)*(2*C+2)+i%C*2+2*j+j/C*3]==N]);V=g.vs;g.d=g.degree;O='';V(_d=1)[N]=N;V(_d_gt=2)[N]=list(string.ascii_letters)
 while g.es:
    v=V(_d=1)[0];O+='|'+v[N]
    while g.d(v):w=v.neighbors()[0];g-=(v,w);v=w;O+=N+v[N]if v[N]else''
 print O+'|'

(П'ятий та шостий рядки починаються з вкладки, а не чотирьох пробілів, як показує StackExchange.)

  • Збережено шість байтів, переставляючи деяку арифметику
  • Збережено сім байтів, використовуючи фрагмент замість блискавки
  • Збережено три байти, використовуючи g+=tuple(v.neighbors())замістьg.add_edge(*v.neighbors())
  • Збережено сім байтів, використовуючи g-=g.es[g.incident(v)]замістьg.delete_edges(g.incident(v))
  • Збережено псевдонім одинадцяти байтів g.d=g.degree
  • Збережено 52 байти (!), Усуваючи цикл, який скорочував усі коридори, замінюючи вершини ступеня 2 на край між сусідами. Натомість цикл виводу просто ігнорує ці вершини.
  • Збережено 13 байт, зауваживши, що при призначенні імен igraph не хвилює, чи наданий ітерабельний файл занадто довгий
  • Збережено чотири байти, не маючи змінної Rдля кількості рядків, перемістивши його обчислення до єдиної точки використання
  • Збережено два байти, змінивши відступ другого рівня на вкладки замість пробілів
  • Збережено шість байтів, переставлених 2*(i%C)на i%C*2, 2*(i/C)до i/C*2та (C-1)*jнаj*C-j
  • Збережено чотири байти іменування N='n'
  • Збережено один байт, що визначає, чи використовується символ простору, <'-'а не ==' 'при умові, що відображаються лише дійсні символи.
  • Потім зрозумів, що я можу назвати атрибут вершини ' 'замість 'n', і повторно використовувати Nдля двох буквальних пробілів у джерелі, а ==Nзамість цього <'-'зберегти ще п’ять байтів

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

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

import string
import igraph
def f(s):
  C = s.find('\n')/2 # number of maze vertices in each row
  R = len(s)/(4*C+4) # number of rows
  def strpos(r, c):
    """Index of the vertex at row r, col c in the newline-delimited string s"""
    return (2*r+1)*(2*C+2) + 2*c + 1
  def vertpos(i):
    """Index of the i-th vertex in s"""
    return strpos(i/C, i%C)
  g = igraph.Graph(edges=[(i, i+(C if j else 1))
                          for i in range(R*C)
                          for j in (0, 1)
                          if s[vertpos(i)+(2*C+2 if j else 1)] == ' '])
  V = g.vs # the graph's vertex sequence
  O = ''
  V(_degree=1)['n'] = ' ' # All leaves are named space
  W = V(_degree_gt=2) # All warp points...
  W['n'] = list(string.ascii_letters[:len(W)]) # ...are named successive letters
  while g.es: # while any edges remain...
    v = V(_degree=1)[0] # find a leaf
    O += '|'+v['n'] # start a new 'block'
    while v.degree():
      w = v.neighbors()[0] # pick a neighbor
      g -= (v, w) # delete that edge
      v = w
      if v['n']: # If it's a dead end or warp point...
        O += ' '+v['n'] # ...write out the new neighbor
  print O+'|'

Ви можете побачити результати п’яти прикладів лабіринтів . (На жаль, igraphце не доступно в програмі Try It Online; ці результати були експортовані з SageMathCloud .)


4

Haskell - 481 405 387 байт

import Data.List
s&t=elemIndices s t
l=last
c!(x:y:z)=l$(y:c)!(x:z):do{[x:p,q]<-mapM([id,reverse]<*>)[[x],[y]];x&[l q];[[]!((q++p):c++z)]}
c![x]=x:[]!c
c!z=z
main=interact(\m->let{g=' '&m;
u=(\\[k|k<-g,length(v>>=(k&))==2])<$>[]!v;
v=[[x,y]|x<-g,y<-g,elem(y-x-1)[0,head$'\n'&m]];
}in '|':(u>>=(++"|").init.(>>=(:" ").toEnum.((+)<*>(+65).(*32).(`div`26)).l.(-1:).(&(nub$u>>=init.tail)))))

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

2D-лабіринт зчитується з STDIN, а 1D-лабіринт друкується в STDOUT.

Edit: Зниження на 62 байт перестановкою купу речей і зміни алгоритму трохи, і ще 14, замінивши chrз toEnumяк це було запропоновано Laikoni.

Редагувати 2: Збережено ще 13 байтів, спростивши логіку в системі (!), 3 за допомогою шаблону списку відповідає цукру, а 2 - >>=для скорочення u.


Я думаю, що вам не потрібні нові рядки та пробіли перед захисними шаблонами, наприклад, вони також o(x:p)q|x==last q=[q++p]|1>0=[]повинні працювати.
Лайконі

Також toEnumслід працювати замість того chr, щоб потім import Data.Charможна було кинути.
Лайконі

І нарешті, оскільки виклик вимагає програми чи функції, ви можете замінити main=interact(\m->...)на справедливі f m=.... Цього має бути достатньо, щоб перемогти відповідь пітона, якщо це для вас щось означає.
Лайконі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.