Жизнь - это лабиринт: мы выбрали неверный путь, прежде чем научились ходить


30

Входные данные:

Лабиринт, содержащий символы:

  • -- (горизонтальная стена);
  • | (вертикальная стена);
  • + (Соединение);
  • (прогулочное пространство);
  • I (Вход);
  • U (выход).

Т.е. вход может выглядеть так:

 +--+--+--+--+--+--+--+--+--+--+ 
I               |     |        | 
 +  +--+--+--+  +  +  +  +--+  + 
 |           |     |  |  |     | 
 +--+--+--+  +--+--+  +  +  +--+ 
 |           |     |     |     | 
 +  +--+--+  +  +--+--+  +--+  + 
 |     |     |     |     |     | 
 +--+  +  +--+--+  +--+--+  +  + 
 |     |        |        |  |  | 
 +  +--+--+--+  +--+--+  +  +  + 
 |     |     |     |        |  | 
 +--+  +  +--+--+  +--+--+--+--+ 
 |  |  |                 |     | 
 +  +  +--+--+--+  +--+  +  +  + 
 |     |        |  |  |  |  |  | 
 +--+--+  +  +--+  +  +  +--+  + 
 |        |     |     |  |     | 
 +  +--+--+--+  +  +  +  +  +--+ 
 |           |     |  |         U
 +--+--+--+--+--+--+--+--+--+--+ 

Выход:

Наиболее эффективный путь , который вы должны пройти , чтобы получить от входа к выходу из лабиринта (через лабиринт), обозначенный обозначающие влево, вправо, вверх и вниз (то есть >; <; ^; v).

Правила соревнований:

  • Вы можете принять вход в любом разумном формате. String-array, single String с новыми строками, 2D char-array и т. Д. - все возможные форматы ввода.
  • Вывод может состоять из любых четырех разных символов. Т.е. ><^v; →←↑↓; ⇒⇐⇑⇓; RLUD; 0123; ABCD; так далее.).
  • Вы можете добавить пробелы или завершающий перевод новой строки в выходной файл, если хотите; это необязательно.
  • Шаги подсчитываются за квадрат (см. Четыре +символа для квадратов), а не за символ.
  • Лабиринт может быть размером от 5х5 до 15х15 и всегда будет квадратным (поэтому не будет никаких тестов для 5х10 лабиринтов).
  • Вы можете предположить, что у каждого лабиринта есть один или несколько допустимых путей от начала до конца, и вы всегда выводите самый короткий (см. Контрольные примеры 4 и 5).
  • Если существует несколько путей одинаковой длины, вы можете выбрать, какой из них вывести (см. Контрольный пример 6).
  • Вы не можете «выйти» за пределы лабиринта (см. Контрольные примеры 7 и 8).

Основные правила:

  • Это , поэтому выигрывает самый короткий ответ в байтах.
    Не позволяйте языкам кода-гольфа отговаривать вас от публикации ответов на языках, не относящихся к кодексу. Попробуйте придумать как можно более короткий ответ для «любого» языка программирования.
  • К вашему ответу применяются стандартные правила , поэтому вы можете использовать STDIN / STDOUT, функции / метод с правильными параметрами, полные программы. Ваш звонок.
  • По умолчанию лазейки запрещены.
  • Если возможно, добавьте ссылку с тестом для вашего кода.
  • Также, пожалуйста, добавьте объяснение, если это необходимо.

Тестовые случаи:

1. Input:
 +--+--+--+--+--+--+--+--+--+--+ 
I               |     |        | 
 +  +--+--+--+  +  +  +  +--+  + 
 |           |     |  |  |     | 
 +--+--+--+  +--+--+  +  +  +--+ 
 |           |     |     |     | 
 +  +--+--+  +  +--+--+  +--+  + 
 |     |     |     |     |     | 
 +--+  +  +--+--+  +--+--+  +  + 
 |     |        |        |  |  | 
 +  +--+--+--+  +--+--+  +  +  + 
 |     |     |     |        |  | 
 +--+  +  +--+--+  +--+--+--+--+ 
 |  |  |                 |     | 
 +  +  +--+--+--+  +--+  +  +  + 
 |     |        |  |  |  |  |  | 
 +--+--+  +  +--+  +  +  +--+  + 
 |        |     |     |  |     | 
 +  +--+--+--+  +  +  +  +  +--+ 
 |           |     |  |         U
 +--+--+--+--+--+--+--+--+--+--+ 

1. Output:
>v>>>vv<v>>v>v>>vvv>>>

2. Input:
 +--+--+--+--+--+ 
I   |        |  | 
 +  +--+--+  +  + 
 |        |  |  | 
 +  +--+  +  +  + 
 |  |  |     |  | 
 +  +  +--+  +  + 
 |        |     | 
 +--+  +  +--+--+ 
 |     |         U
 +--+--+--+--+--+ 

2. Output:
>vvv>>v>>>

3. Input:
 +--+--+--+--+--+ 
U      |        | 
 +  +  +--+--+  + 
 |  |     |     | 
 +--+--+  +  +--+ 
 |        |     | 
 +  +--+--+--+  + 
 |  |     |     | 
 +  +  +  +  +--+ 
 |     |         I
 +--+--+--+--+--+ 

3. Output:
<<<^<v<^^>>^<^<<

4. Input (test case with two valid paths):
 +--+--+--+--+--+ 
U      |        | 
 +  +  +--+--+  + 
 |  |           | 
 +--+--+  +  +--+ 
 |        |     | 
 +  +--+--+--+  + 
 |  |     |     | 
 +  +  +  +  +--+ 
 |     |         I
 +--+--+--+--+--+ 

4. Output:
<<^>^<^<<^<<     (<<<^<v<^^>>^<^<< is less efficient, and therefore not a valid output)

5. Input (test case with two valid paths):
                               I
+--+--+--+--+--+--+--+--+--+--+  +--+--+--+--+
|     |              |                    |  |
+  +  +  +--+--+--+  +  +--+--+  +--+--+  +  +
|  |     |        |     |        |     |     |
+--+--+--+  +--+  +  +--+--+--+--+  +--+--+--+
|     |  |  |  |     |     |           |     |
+  +  +  +  +  +--+  +  +  +  +--+--+  +--+  +
|  |        |        |  |     |        |     |
+  +--+--+--+  +--+--+  +  +--+  +--+--+  +--+
|  |     |     |        |  |     |     |     |
+  +--+  +  +--+  +--+--+  +--+--+  +  +--+  +
|  |     |        |     |           |        |
+  +  +--+--+--+--+  +  +--+--+--+  +--+  +--+
|     |     |        |        |  |     |     |
+--+--+--+  +  +--+--+  +--+  +  +--+  +--+  +
|              |     |     |        |  |  |  |
+  +--+--+--+--+  +  +  +--+--+--+  +  +  +  +
|     |  |     |  |  |        |        |  |  |
+--+  +  +  +  +  +  +--+--+  +  +  +--+  +  +
|     |     |  |  |  |           |  |     |  |
+--+  +--+--+  +  +  +  +--+--+--+  +  +  +  +
|     |        |  |  |     |        |  |  |  |
+  +--+  +--+--+  +  +--+--+  +  +--+  +  +  +
|        |     |  |     |     |  |     |  |  |
+--+--+--+  +  +  +--+  +  +--+--+  +--+  +  +
|  |        |        |     |        |     |  |
+  +  +--+--+--+--+  +--+--+  +--+--+  +--+  +
|  |              |              |     |     |
+  +  +  +--+--+--+--+--+--+--+--+  +--+  +--+
|     |                                |     |
+--+--+--+--+--+--+--+--+--+  +--+--+--+--+--+
                            U

5. Output:
v<<<v<vv<<v<v>>^>>^^>vvv>>>v>vv<vv<<v<v<^<^^^^<vvvvv<^<v<<v>v>>>>>>>v     (v<<<v<vv<<v<v>>^>>^^>vvv>>>v>vv<vv<<v<v<^<^^^^<vvvvv>v>>>^>>^>^^>vvv<v<v<<v is less efficient, and therefore not a valid output)

6. Input:
 +--+--+--+--+--+
I               |
 +  +  +  +  +  +
 |              |
 +  +  +  +  +  +
 |              |
 +  +  +  +  +  +
 |              |
 +  +  +  +  +  +
 |               U
 +--+--+--+--+--+

6. Output:
>>v>v>v>v> or >v>v>v>v>> or >>>>>vvvv> or etc. (all are equally efficient, so all 10-length outputs are valid)

7. Input:
 I  U
+  +  +--+--+--+
|  |        |  |
+  +--+--+  +  +
|     |     |  |
+--+  +  +--+  +
|        |  |  |
+  +--+  +  +  +
|     |        |
+--+  +--+--+  +
|     |        |
+--+--+--+--+--+

7. Output:
vv>v>^>^<<^

8. Input:
 +--+--+--+--+--+
 |     |        |
 +  +--+  +--+  +
I   |     |  |  |
 +  +  +--+  +  +
U   |     |  |  |
 +--+--+  +  +  +
 |     |     |  |
 +  +--+--+--+  +
 |               
 +--+--+--+--+--+

8. Output:
>v<

Лабиринты генерируются с помощью этого инструмента (а в некоторых случаях слегка модифицированы).


10
Я нашел более короткое решение для третьего теста! v<<<<<<^^^^^(всегда мыслить нестандартно)
Лев

2
Если кто-то может доказать, что их код даст самое короткое решение, при условии достаточного времени и памяти, конкурирует ли он? Даже в случае действительно длительного времени работы (конец вселенской моды)?
Yytsi

1
@JackBates Это шутка. Он буквально обходит коробку до выхода: D
Yytsi

1
Я думаю, что первый контрольный пример не так, оно должно быть >v>>>vv<v>>v>v>>vvv>>>.
Smls

1
@KevinCruijssen Например, решение, которое проверяет каждую комбинацию «v ^ <>» на длину до количества пустых ящиков внутри лабиринта. Правильное решение будет там, но требует астрономического времени для вычисления.
Yytsi

Ответы:


7

Сетчатка , 338 281 275 273 261 байт

¶U
¶&
+`·(\w.+)$
|$1
((.)+I.+¶.+¶(?<-2>.)+)·
$1v
+`((.)*)\+(.).*(¶(?<-2>.)*.)((\w)|·)·?
$1$4$.4$3$6
·v
-v
G`1
·U
&
{`\B·\d+.(\w+)
$1K$&
(\w+)·\d+.\B
$&$1r
(?<=\D\2.(\w+).+?¶.*\D(\d+)[·&])\B
$1v
)`\D(\d+).\B(?=.+¶.*\D\1·(\w+))
$&$2A
^.+\d·(\w+)
&$1A
M!`&\w+
I|&

Попробуйте онлайн!


Заметки

  • Из-за значительных пробелов все пробелы ( 0x20) заменяются на interpunct ( ·) как в этом ответе, так и в ссылке TIO. Программа работает нормально, если пробелы восстановлены.
  • Используется AvKrдля вверх, вниз, влево и вправо соответственно. Они могут быть заменены любыми буквами, кроме I.
  • Занимает около 40 секунд на TIO для теста 15 × 15. Потерпи. Переработана часть для поиска кратчайшего пути, как только путь достигнет выхода. Оказывается, это заняло много времени.
  • Может полностью разбиться на лабиринты, которые имеют ширину 66 или более ячеек, но могут обрабатывать лабиринты произвольной высоты. Исправление для произвольной ширины занимает +1 байт.

объяснение

Программа состоит из 3 этапов:

  • Этап строительства для преобразования лабиринта в компактный формат , который легче работать с (подробно описано ниже).
  • Фаза заполнения на самом деле решить лабиринт , используя алгоритм заливки.
  • Возврат фаза , чтобы вернуть кратчайший путь на выходе.

Формат

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

ячейки

В исходном формате каждая ячейка представлена ​​областью 2 × 3:

+               <top wall>      <top wall>
<left wall>     <data/space>    <space>

Поскольку правый столбец не содержит информации, программа идентифицирует ячейки как любую область 2 × 2 с +символом слева вверху.

Это оставляет нам 3 вида клеток:

  • Я Клетки : Клетки, которые правильно находятся в лабиринте.
  • Ячейки R : Ячейки, которые находятся справа от лабиринта. Они создаются дополнением, используемым для размещения входа или выхода. Например, выход Uв тестовом примере 1 находится в R-ячейке.
  • Клетки B : Клетки, которые находятся ниже лабиринта. Как и R-клетки, они создаются путем заполнения.

В новом формате ячейки представлены в виде строки переменной длины:

<left wall> <column number> <top wall/exit marker> <path>

Левая и верхняя стены скопированы из оригинального формата. Номер столбца основан на горизонтальном положении ячейки и используется для выравнивания (идентифицируя ячейки непосредственно друг над другом). Путь - это алфавитная строка, используемая на этапе заполнения для сохранения кратчайшего пути к этой ячейке. Маркер пути и выхода будет дополнительно объяснен.

Половина клеток

Хотя большая часть лабиринта является клеткой, существуют области лабиринта, которые не являются клетками:

  • R Полуэлементы : если справа нет отступов, то +s вдоль правой стены не образуют ячеек, поскольку они находятся в последнем столбце.
  • L Полуклетки : если есть отступы слева, клетки не могут образовываться там, так +как слева от них нет. Например, вход Iв контрольном примере 1 находится в полукадре L.

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

Верхний ряд полуклетки будет удален как часть построения полных ячеек в той же строке, поэтому полуклетки представлены в новом формате как

<wall/exit marker>? <path>

Полуклетки R это просто |. L-полуклетка имеет только Iпуть, только маркер выхода и пустой путь, или просто пустую стену.

Входы и выходы

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

Если вход выше лабиринта, первый (нисходящий) шаг делается во время фазы строительства, так как Т-полуклетки удаляются во время строительства. Это сохраняет работоспособный путь в полной ячейке. Верхняя стена закрыта после.

Если выход находится слева, справа или снизу от лабиринта, то U, естественно, будет включен в (половину) ячейки. Чтобы избежать ошибки в качестве пути, &вместо U. Используется маркер выхода, не являющийся алфавитом . Маркер выхода встраивается в ячейку или половину ячейки (как указано выше).

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

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

пример

Как пример, первый тестовый пример

·+--+--+--+--+--+--+--+--+--+--+·
I···············|·····|········|·
·+··+--+--+--+··+··+··+··+--+··+·
·|···········|·····|··|··|·····|·
·+--+--+--+··+--+--+··+··+··+--+·
·|···········|·····|·····|·····|·
·+··+--+--+··+··+--+--+··+--+··+·
·|·····|·····|·····|·····|·····|·
·+--+··+··+--+--+··+--+--+··+··+·
·|·····|········|········|··|··|·
·+··+--+--+--+··+--+--+··+··+··+·
·|·····|·····|·····|········|··|·
·+--+··+··+--+--+··+--+--+--+--+·
·|··|··|·················|·····|·
·+··+··+--+--+--+··+--+··+··+··+·
·|·····|········|··|··|··|··|··|·
·+--+--+··+··+--+··+··+··+--+··+·
·|········|·····|·····|··|·····|·
·+··+--+--+--+··+··+··+··+··+--+·
·|···········|·····|··|·········U
·+--+--+--+--+--+--+--+--+--+--+·

является

I·3-·6-·9-·12-·15-|18-·21-|24-·27-·30-|33·
·|3··6-·9-·12-|15··18·|21·|24·|27-·30·|33·
·|3-·6-·9-·12·|15-·18-|21··24·|27··30-|33·
·|3··6-|9-·12·|15··18-|21-·24·|27-·30·|33·
·|3-·6·|9··12-·15-|18··21-·24-|27·|30·|33·
·|3··6-|9-·12-|15··18-|21-·24··27·|30·|33·
·|3-|6·|9··12-·15-·18··21-·24-|27-·30-|33·
·|3··6·|9-·12-·15-|18·|21-|24·|27·|30·|33·
·|3-·6-·9·|12··15-|18··21·|24·|27-·30·|33·
·|3··6-·9-·12-|15··18·|21·|24··27··30-·33&

в новом формате. Вы можете конвертировать другие лабиринты здесь .


Этап строительства

Этап строительства составляет первые 13 строк программы.

¶U
¶&

Конвертирует выход в L Полуклетка в маркер выхода

+`·(\w.+)$
|$1

Добавляет стены слева от входа и выхода в ячейках B

((.)+I.+¶.+¶(?<-2>.)+)·
$1v

Делает первый шаг, если вход выше лабиринта

+`((.)*)\+(.).*(¶(?<-2>.)*.)((\w)|·)·?
$1$4$.4$3$6

Выполняет фактическое преобразование

·v
-v

Закрывает отверстие верхнего входа

G`1

Сохраняет только строки с 1. Поскольку лабиринты имеют ширину не менее 5 ячеек, а номера столбцов появляются с шагом 3, строка с ячейками нового формата должна содержать номер столбца от 10 до 19.

·U
&

Преобразует выход в ячейку R или ячейку B для маркера выхода


Заполнить фазу

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

{`

Помещает всю фазу заполнения на петлю, чтобы заполнить весь лабиринт.

\B·\d+.(\w+)
$1K$&

Каждая клетка, способная двигаться влево, делает это. Клетка может двигаться влево, если

  1. у него есть непустой путь
  2. у него пустая левая стена; а также
  3. ячейка или L полуклетка слева имеет пустой путь
(\w+)·\d+.\B
$&$1r

Затем каждая клетка, способная двигаться вправо, делает это. Клетка может двигаться вправо, если

  1. у него есть непустой путь
  2. клетка справа имеет пустую левую стенку; а также
  3. клетка справа имеет пустой путь
(?<=\D\2.(\w+).+?¶.*\D(\d+)[·&])\B
$1v

Затем каждая клетка, способная двигаться вниз, делает это. Клетка может двигаться вниз, если

  1. у него есть непустой путь
  2. справа от него есть хотя бы одна ячейка или полуклетка (т.е. это не R-ячейка)
  3. ячейка под ней (то есть ячейка на следующей строке с тем же номером столбца) имеет пустую верхнюю стенку или имеет маркер выхода; а также
  4. ячейка под ней имеет пустой путь

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

\D(\d+).\B(?=.+¶.*\D\1·(\w+))
$&$2A

Затем каждая клетка, способная двигаться вверх, делает это. Клетка может двигаться вверх, если

  1. у него есть непустой путь
  2. у него пустая верхняя стенка
  3. клетка над ней имеет по крайней мере одну клетку или полуклетку справа; а также
  4. клетка над ней имеет пустой путь

Фаза возврата

Фаза возврата составляет последние 5 строк программы. Эта фаза ищет и возвращает путь, заполненный в выходной ячейке.

Схема пути на выходе зависит от того, где находится выход:

  1. Если выход находится в полуклетке L, то эта полуклетка будет & <path>
  2. Если выход находится в ячейке R или ячейке B, то эта ячейка будет <left wall> <column number> & <path>
  3. Если выход находится в T-ячейке T, то, как отмечалось выше, I-ячейка, ведущая к выходу, будет находиться <left wall> <column number> · <path>в верхнем ряду.
^.+\d·(\w+)
&$1A

Находит ячейку в верхней строке с пустой верхней стенкой и непустым путем. Это позаботится о последнем случае, добавив последний шаг и маркер выхода.

M!`&\w+

Соответствует и возвращает непустой путь после маркера выхода.

I|&

Удаляет маркер выхода и Iпрефикс пути.


Почему то AvKr? Имеют ли они значение / являются ли они аббревиатурами вверх, вниз, влево и вправо на вашем родном языке, или есть другая причина, по которой вы выбрали именно эти символы?
Кевин Круйссен,

@KevinCruijssen Просто потому, что я должен использовать буквенно-цифровые символы и AvKrближе всего к стрелкам в алфавите.
TwiNight

12

Perl 6 , 259 295 байт

{my \a=S:g/(.)$0+/{$0 x($/.comb+.5)*2/3}/;sub f (\c,\v,*@p) {with (c ne any v)&&a.lines».comb[+c[0];+c[1]] ->$_ {for (/\s/??10011221!!/I/??a~~/^\N*I|I\N*$/??2101!!1012!!'').comb X-1 {f [c Z+$^a,$^b],(|v,c),@p,chr 8592+$++}
take @p if /U/}}
[~] (gather f a~~/(\N+\n)*(.)*I/,[]).min(+*)[1,3...*]}

Как это работает

  1. my \a = S:g/ (.) $0+ /{ $0 x ($/.chars + .5) * 2/3 }/;

Это сжимает лабиринт, так что внутри каждой ячейки 1x1 вместо 2x1 пробелов:

 + - + - + - + - + - + + - + - + - + - + - + 
Я | | | Я | | |
 + + - + - + + + + + - + - + + + 
 | | | | | | | |
 + + - + + + + + + - + + + + 
 | | | | | -> | | | | |
 + + + - + + + + + + - + + + 
 | | | | | |
 + - + + + - + - + + - + + + - + - + 
 | | U | | U
 + - + - + - + - + - + + - + - + - + - + - +

  1. sub f (\c,\v,*@p) {
        with (c ne any v) &&                   # If the coordinate wasn't visited yet
             lines».comb[+c[0];+c[1]] -> $_ {  # and a character exists there...
            for (                          # For each vector...
                 /\s/ ?? 10011221 !!       #  from a cell: (0,-1), (-1,0), (0,1), (1,0)
                 /I/  ?? a~~/^\N*I|I\N*$/
                          ?? 2101          #  from a top/bottom entrance: (1,0), (-1,0)
                          !! 1012          #  from a left/right entrance: (0,-1), (0,1)
                      !! ''                #  otherwise: none
                ).comb X-1 {
                f                       #   Recurse with arguments:
                    [c Z+ $^a, $^b],    #     c plus the vector
                    (|v, c),            #     v with c appended
                    @p, chr 8592 + $++  #     p with the correct Unicode arrow appended
            }
            take @p if /U/
        }
    }

Это рекурсивная функция поиска пути. Он принимает три параметра: текущую координату c=(y,x), список уже посещенных координат vи пройденный путь p(в виде списка символов стрелки).

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

  1. [~] (gather f a ~~ /(\N+\n)*(.)*I/, []).min(+*)[1,3...*]

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

gatherКлючевое слово собирает все ценности , на которых takeбыли называемыми внутри функции, то есть весь допустимый нециклических путь через лабиринт.

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


Прежде всего, отличная работа - быть первым, кто выполнил мою задачу! :) Умно, как вы изменили два пробела в одно, чтобы облегчить фактическое движение / подсчет. +1 от меня. Во всяком случае, после некоторых комментариев были добавлены два новых теста. Не могли бы вы также проверить эту работу с вашим решением? (Кроме того, есть ли в Perl 6 TIO или другой онлайн-компилятор, на который вы могли бы добавить ссылку?)
Кевин Круйссен

@KevinCruijssen: Он прошел лабиринт в новых тестовых случаях. :( Я исправил код сейчас. Tio.run поддерживает Perl 6, но по какой-то причине он там не работает ... может быть, у него слишком старая версия Perl 6?
smls

Отличная работа по исправлению кода. Извините за указание правила прохождения лабиринта после того, как вы уже опубликовали свой ответ, но вводная часть за его быстрое исправление. А насчет версии TIO я понятия не имею. Не совсем мой опыт ..
Кевин Круйссен

Поскольку ты был первым, кто ответил на мой вызов четыре месяца назад, я дал тебе награду. :) А Accept для чуть более короткого ответа Retina.
Кевин Круйссен,

5

Python 2: 302 байта

from re import*
r=lambda x:[''.join(_)for _ in zip(*x)][::-1]
z=',l)for l in s]'
def f(s,b=1,o=0,n=0):
 exec("s=[sub('(..).(?!$)',r'\\1'%s;"%z+"s=r([sub(' I ','+I+'%s);"%z*4)*b+"t=[sub('I  ','@@I'"+z
 if'I U'in`s`or n>3:return`o%4`+n/4*`s`
 return min(`o%4`+f(t,0,o,4*(t==s)),f(r(s),0,o+1,n+1),key=len)

Принимает входные данные в виде массива строк одинаковой длины. Отпечатки 0вправо, 1вниз, 2влево и 3вверх.

объяснение

Я выбрал другой подход, чем другие ответы. Общая идея: рекурсивный поиск, находя кратчайший путь между движением прямо вперед и поворотом доски на 90 градусов.

from re import*
r=lambda x:[''.join(_)for _ in zip(*x)][::-1] #Rotates the board counterclockwise
z=',l)for l in s]'    #Suffix for hacky exec golfing
def f(s,b=1,o=0,n=0): #b is 1 on initial call, 0 on every recursion
                      #o is orientation
                      #n is number of rotations
 exec("s=[sub('(..).(?!$)',r'\\1'%s;"%z  #Squeeze the maze
      +"s=r([sub(' I ','+I+'%s);"%z*4)   #Add walls around the I to keep it in the maze
      *b                                 #Only if b is 1
      +"t=[sub('I  ','@@I'"+z            #Attempt to move right

 if'I U'in`s`or n>3:return`o%4`+n/4*`s`  #If the I is next to the U, return the orientation
                                         #If there were 4 rotations, return a long string
 return min(                             #Return the path with the shortest length:
            `o%4`+f(t,0,o,4*(t==s)),       #Moving forward if possible
            f(r(s),0,o+1,n+1),             #Rotating the board
        key=len)

Попробуйте онлайн!


3
Добро пожаловать в PPCG! Это отличный первый ответ, и я впечатлен, что вы решили сделать довольно сложную задачу в качестве первого. Также продумайте, как вы расположите стены вокруг, Iчтобы предотвратить выход пути из лабиринта. Приятного пребывания и +1 от меня. :)
Кевин Круйссен

2

JavaScript (ES6), 356 байт

a=>(a=a.map(s=>s.filter((_,i)=>!i|i%3)),g=([x,y])=>a[y]&&a[y][x],o=[],c=([x,y],m="",v=[])=>[[0,1],[1,0],[0,-1],[-1,0]].map(([j,k],i)=>(p=[x+j,y+k],!m&(!y|y>a[l="length"]-2)==i%2|v.includes(""+p)||(g(p)<"!"?c(p,m+"v>^<"[i],[...v,""+p]):g(p)=="U"?o.push(m.replace(/(.)\1/g,"$1")):0))),a.map((h,i)=>h.map((k,j)=>k=="I"&&c([j,i]))),o.sort((a,b)=>a[l]-b[l])[0])

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

Использует идею smls о том, чтобы сжать лабиринт, чтобы сделать каждую ячейку 1x1 и убрать повторяющиеся стрелки из выходных данных.

Неуправляемый и объясненный

a=>(
    a=a.map(s=>s.filter((_,i)=>!i|i%3)),    // squish the maze to 1x1 cells
    g=([x,y])=>a[y]&&a[y][x],               // helper func to get maze value
    o=[],                                   // resulting movesets
    c=([x,y], m="", v=[]) =>                // recursive func to search
                                            // takes current point, moves, and visited spots
        [[0,1],[1,0],[0,-1],[-1,0]].map(([j,k],i)=>(// for each direction
            p=[x+j,y+k],
            !m & (!y | y>a[l="length"]-2) == i%2 |  // if first move, prevent moving out of maze
                v.includes(""+p) || (               // also prevent if already visited
                    g(p)<"!" ?                      // is this a space?
                        c(p, m+"v>^<"[i], [...v,""+p]) // check this spot recursively
                    : g(p)=="U" ?                   // if this the end?
                        o.push(                     // add moves to moveset
                            m.replace(/(.)\1/g,"$1")) // with double arrows removed
                    : 0
                )
        )),

    a.map((h,i)=>h.map((k,j)=>      // find the starting "I" and
        k=="I" && c([j,i])          // begin recursion at that point
    )),

    o.sort((a,b)=>a[l]-b[l])[0]     // get shortest path
)

Тестовый фрагмент


1

Сетчатка , 416 байт

T` `+`^.*| ?¶.|.*$
I
#
{+` (\w)
d$1
+`(\w) 
$1a
+`(¶(.)*) (.*¶(?<-2>.)*(?(2)(?!))\w)
$1s$3
}+m`(^(.)*\w.*¶(?<-2>.)*(?(2)(?!))) 
$1w
^
w¶
w((.|¶)*(¶(.)*#.*¶(?<-4>.)*(?(4)(?!))(s)|#(d)|(a)#))
$4$5$6¶$1
{`^(.*d)(¶(.|¶)*)#(\w)
$1$4$2 #
^(.*a)(¶(.|¶)*)(\w)#
$1$4$2# 
^(.*s)(¶(.|¶)*¶(.)*)#(.*¶(?<-4>.)*(?(4)(?!)))(\w)
$1$6$2 $5#
}`^(.*w)(¶(.|¶)*¶(.)*)(\w)(.*¶(?<-4>.)*(?(4)(?!)))#
$1$5$2#$6 
s`U.*

(a|d)\1\1?
$1
ss
s
ww
w

Попробуйте онлайн!Если бы я видел этот вопрос, когда он был первоначально опубликован, это, вероятно, ответ, который я бы дал, так что я все равно его отправляю, хотя в Retina есть гораздо лучший ответ. Объяснение:

T` `+`^.*| ?¶.|.*$

Заполните границу. Это позволяет избежать прогулки по внешней стороне лабиринта (например, для контрольного примера 7).

I
#

Поместите не алфавитный маркер на входе.

{+` (\w)
d$1
+`(\w) 
$1a
+`(¶(.)*) (.*¶(?<-2>.)*(?(2)(?!))\w)
$1s$3
}+m`(^(.)*\w.*¶(?<-2>.)*(?(2)(?!))) 
$1w

Наводнение заполните от выхода до входа. На каждом шаге используйте букву, чтобы указать наилучшее направление (разве - это может быть знакомо геймерам; я также подумал о hjkl, но нашел его слишком запутанным). Кроме того, предпочитайте повторять в том же направлении; это позволяет избежать перехода влево / вправо между двумя вертикально смежными ячейками.

^
w¶

Предположим, что первый шаг вниз.

w((.|¶)*(¶(.)*#.*¶(?<-4>.)*(?(4)(?!))(s)|#(d)|(a)#))
$4$5$6¶$1

Но если есть буква выше, слева или справа от входа, измените это на первый шаг.

{`^(.*d)(¶(.|¶)*)#(\w)
$1$4$2 #
^(.*a)(¶(.|¶)*)(\w)#
$1$4$2# 
^(.*s)(¶(.|¶)*¶(.)*)#(.*¶(?<-4>.)*(?(4)(?!)))(\w)
$1$6$2 $5#
}`^(.*w)(¶(.|¶)*¶(.)*)(\w)(.*¶(?<-4>.)*(?(4)(?!)))#
$1$5$2#$6 

Переместите маркер в направлении последнего движения, считывая направление следующего движения от квадрата, к которому движется маркер, и добавьте его в список направлений. Это повторяется доU будет достигнуто.

s`U.*

Удалите все после указаний, поскольку это больше не нужно.

(a|d)\1\1?
$1
ss
s
ww
w

Исходная сетка имеет макет 3 × 2. При перемещении по вертикали, если мы делаем зигзаг по горизонтали, заливка будет оптимизировать движение и перемещать только 3n-1 символов по горизонтали, поэтому при делении на три нам нужно округлить. Вертикально мы просто делим на 2.

Я также исследовал реальное решение с квадратной сеткой, то есть там, где матрица символов сама по себе квадратная, а не как макет 3 × 2 с необязательной рамкой. Возможно, это не соответствовало этому вопросу, но возможность транспонирования позволила уменьшить количество байтов до 350: попробуйте онлайн!


Хороший ответ, +1! Я вижу, что в вашей ссылке на TIO вы добавили два -символа для входа и выхода. Поскольку задача в основном состоит в том, чтобы пройти лабиринт, я думаю, это нормально, но мне интересно: какие были проблемы, когда вы не разместили эти стены выше / ниже Iи U? Кроме того, не могли бы вы проверить, что это работает для контрольного примера 7 с Iи Uвверху вместо сторон? TIO превышает 60-секундный лимит, поэтому я не могу проверить это сам. Хотя вы читаете ваше объяснение первой попытки отключиться по умолчанию, я предполагаю, что она должна работать нормально.
Кевин Круйссен

@KevinCruijssen «Вторичный» ответ работает для теста 7, но требует дополнительных символов: попробуйте онлайн! продолжение ...
Нил

@KevinCruijssen В «основном» ответе была ошибка, из-за которой он вообще не мог справиться с выходом в верхней строке. Он также имеет ошибку, аналогичную «второстепенному» ответу, согласно которому он предпочитает ходить по лабиринту, если может. (Кроме того, я не
Нил

На самом деле, я мог бы исправить оба ответа, заполнив границу. Я сделаю это позже, когда у меня будет время.
Нил
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.